Stream 介紹 java8添加了一個抽象流Stream,可以讓我們像寫sql一樣操作集合元素。Stream將要處理的元素看做是一種流, 在管道中傳輸,併進行處理,最後由終止操作得到處理的結果。 什麼是Stream? Stream是一個來自特定元素隊列並支持聚合操作 元素是具體類型的對象,形成一個 ...
Stream
介紹
java8添加了一個抽象流Stream,可以讓我們像寫sql一樣操作集合元素。Stream將要處理的元素看做是一種流, 在管道中傳輸,併進行處理,最後由終止操作得到處理的結果。
什麼是Stream?
Stream是一個來自特定元素隊列並支持聚合操作
- 元素是具體類型的對象,形成一個隊列。
- 數據源是流的來源。
- 聚合操作是類似sql一樣的操作,比如filter, map, reduce, find, match, sorted等。
- Stream自己不會存儲元素。
- Stream不會改變源對象。
- Stream操作是延遲執行的。
創建流
串列流
stream():即單線程的方式去操作流
並行流
parallelStream():即多線程方式去操作流
@Test
public void test() {
//1通過Collection提供的stream()和parallelStream()方法
List<String> list = Arrays.asList("a","b","c");
Stream<String> stream1 = list.stream();
Stream<String> stream2 = list.parallelStream();
//2通過Arrays的靜態方法stream()
String[] strs= {"a","b","c"};
Stream<String> stream3 = Arrays.stream(strs);
//3通過Stream類中的靜態方法of()
Stream<String> stream4 = Stream.of("a","b","c");
//4通過Stream類的iterate方法生成無限流
Stream<Integer> stream5 = Stream.iterate(0, (x)->x+1);
//5通過Stream的generate方法生成無限流
Stream.generate(()->Math.random());
}
中間操作
過濾
使用 filter(Predicate<? super T> predicate)來按照一定規則對流中元素進行過濾
@Test
public void test() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream = list.stream();
stream = stream.filter((x)->x.compareTo(2)>0);
stream.forEach(System.out::println);
}
輸出:
3
4
5
@Test
public void test2() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream = list.stream();
stream = stream.filter(
(x)->{
System.out.println(x);
return x.compareTo(2)>0;}
);
}
結果:沒有任何輸出,這也就是前面說的Stream操作是延遲執行的,只有當終止操作這些中間操作才會依次執行
截斷
使元素的個數不超過指定的數目
@Test
public void test() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream = list.stream();
stream=stream.limit(3);
stream.forEach(System.out::println);
}
輸出:
1
2
3
可以看到只輸出了給定個元素
跳過元素
跳過流中前幾個元素
@Test
public void test4() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream = list.stream();
stream=stream.skip(2);
stream.forEach(System.out::println);
}
輸出:
3
4
5
跳過了前兩個元素
唯一篩選
兩個元素通過hashCode()判斷兩個元素是否相同
@Test
public void test5() {
List<Integer> list = Arrays.asList(1,2,3,4,5,5);
Stream<Integer> stream = list.stream();
stream.distinct().forEach(System.out::println);
}
輸出:
1
2
3
4
5
映射
map(method)接受一個方法,把流中的元素按照方法進行轉換
@Test
public void test() {
List<String> list = Arrays.asList("a","b","c");
Stream<String> stream = list.stream();
stream=stream.map((x)->x.toUpperCase());
stream.forEach(System.out::println);
}
輸出:
A
B
C
flatMap(method)也是接受一個函數作為參數,但是與map,不同的是如果這個函數生成的本來就是流,它會把函數生成流中的元素加到流中
//這個函數本身就生成流
public static Stream<Character> toStream(String s){
List<Character> list=new ArrayList<Character>();
char[] chs = s.toCharArray();
for (char c : chs) {
list.add(c);
}
Stream<Character> stream = list.stream();
return stream;
}
@Test
public void test() {
List<String> list = Arrays.asList("aaa","bbb","ccc");
Stream<Stream<Character>> stream =
//由於函數本身就生成流,所以流中加入的還是流
list.stream().map(StreamTest::toStream);
//遍歷的時候需要先從流中取出流,在遍歷
stream.forEach((s)->s.forEach(System.out::println));
}
//然而我們可以使用flatMap進行改進
@Test
public void test() {
List<String> list = Arrays.asList("aaa","bbb","ccc");
list.stream().flatMap(StreamTest::toStream).forEach(System.out::println);
}
輸出:
a
a
a
b
b
b
c
c
c
終止操作
所有匹配
當所有元素都匹配時,allMatch(Predicate<? super T> predicate)才會返回true
@Test
public void test() {
List<String> list = Arrays.asList("aaa","bbb","ccc");
boolean allMatch = list.stream().allMatch((s)->s.length()>2);
System.out.println(allMatch);
}
輸出:
true
任一匹配
當Stream中任一一個元素匹配時,anyMatch(Predicate<? super T> predicate)返回true
@Test
public void test() {
List<String> list = Arrays.asList("aaa","bbb","ccc");
boolean anyMatch = list.stream().anyMatch((s)->s.equals("bbb"));
System.out.println(anyMatch);
}
輸出:
true
所有不匹配
當Stream中所有的元素都不匹配時,noneMatch(Predicate<? super T> predicate)返回true
@Test
public void test() {
List<String> list = Arrays.asList("aaa","bbb","ccc");
boolean noneMatch = list.stream().noneMatch((s)->s.equals("ddd"));
System.out.println(noneMatch);
}
輸出:
true
第一個元素
返回當前流中的第一個元素
@Test
public void test() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Optional<Integer> findFirst = list.stream().findFirst();
System.out.println(findFirst.get());
}
輸出:
1
任一一個元素
返回當前流中的任一一個元素
@Test
public void test() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Optional<Integer> findAny = list.stream().findAny();
System.out.println(findAny.get());
}
輸出:
1
//使用並行流試試
@Test
public void test13() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Optional<Integer> findAny = list.parallelStream().findAny();
System.out.println(findAny.get());
}
輸出:
3
流中元素個數
返迴流中的元素個數
@Test
public void test14() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
long count = list.stream().count();
System.out.println(count);
}
輸出:
5
流中的最大值
返迴流中元素的最大值
@Test
public void test15() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Optional<Integer> max = list.stream().max(Integer::compare);
System.out.println(max.get());
}
輸出:
5
流中的最小值
返迴流中的最小值
@Test
public void test16() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Optional<Integer> min = list.stream().min(Integer::compare);
System.out.println(min.get());
}
輸出:
1
規約
將流中的元素反覆結合得到一個最終值
@Test
public void test() {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Optional<Integer> reduce = list.stream().reduce(Integer::sum);
System.out.println(reduce.get());
Integer reduce2 = list.stream().reduce(0, (x,y)->{
System.out.println(x+"->"+y);
return x+y;
});
System.out.println(reduce2);
}
輸出:
15
0->1
1->2
3->3
6->4
10->5
15
可以看到當使用(T identity, BinaryOperator
收集
將流轉換成其他形式
@Test
public void test() {
List<Integer> list = Arrays.asList(1,2,3,4,5,5);
Set<Integer> collect = list.stream().collect(Collectors.toSet());
System.out.println(collect);
}
輸出:
[1, 2, 3, 4, 5]
@Test
public void test() {
List<Integer> list = Arrays.asList(1,2,3,4,5,5);
Optional<Integer> collect = list.stream().collect(Collectors.maxBy(Integer::compareTo));
System.out.println(collect.get());
}
輸出:
5
class Stu{
String name;
Integer age;
String gender;
public Stu(String name, Integer age, String gender) {
super();
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Stu [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
}
//一級分組
@Test
public void test() {
List<Stu> list = Arrays.asList(
new Stu("張三",20,"男"),
new Stu("李四",22,"女"),
new Stu("王五",18,"男"),
new Stu("趙六",20,"女"),
new Stu("田七",22,"女")
);
Map<String, List<Stu>> collect = list.stream().collect(Collectors.groupingBy(Stu::getGender));
System.out.println(collect);
}
輸出:
{女=[Stu [name=李四, age=22, gender=女], Stu [name=趙六, age=20, gender=女], Stu [name=田七, age=22, gender=女]], 男=[Stu [name=張三, age=20, gender=男], Stu [name=王五, age=18, gender=男]]}
//二級分組
@Test
public void test21() {
List<Stu> list = Arrays.asList(
new Stu("張三",20,"男"),
new Stu("李四",22,"女"),
new Stu("王五",18,"男"),
new Stu("趙六",20,"女"),
new Stu("田七",22,"女")
);
Map<Integer, Map<String, List<Stu>>> collect = list.stream()
.collect(Collectors.groupingBy(Stu::getAge, Collectors.groupingBy(Stu::getGender)));
System.out.println(collect);
}
輸出:
{18={男=[Stu [name=王五, age=18, gender=男]]}, 20={女=[Stu [name=趙六, age=20, gender=女]], 男=[Stu [name=張三, age=20, gender=男]]}, 22={女=[Stu [name=李四, age=22, gender=女], Stu [name=田七, age=22, gender=女]]}}
//分區
@Test
public void test22() {
List<Stu> list = Arrays.asList(
new Stu("張三",20,"男"),
new Stu("李四",22,"女"),
new Stu("王五",18,"男"),
new Stu("趙六",20,"女"),
new Stu("田七",22,"女")
);
Map<Boolean, List<Stu>> collect = list.stream()
.collect(Collectors.partitioningBy((e)->((Stu)e).getAge()>20));
System.out.println(collect);
}
輸出:
{false=[Stu [name=張三, age=20, gender=男], Stu [name=王五, age=18, gender=男], Stu [name=趙六, age=20, gender=女]], true=[Stu [name=李四, age=22, gender=女], Stu [name=田七, age=22, gender=女]]}