本文是我在學習Java8的時候參考下面大佬的文章拷貝的台盯,僅用于個人整理和學習用途
原文地址:http://www.reibang.com/p/0bb4daf6c800
一. 什么是 Stream
Stream 中文稱為“流”江滨,通過將集合轉(zhuǎn)換為這么一種叫做 “流” 的元素序列,通過聲明性方式盲憎,能夠?qū)现械拿總€元素進行一系列并行或串行的流水線操作。
換句話說,你只需要告訴流你的要求塞椎,流便會在背后自行根據(jù)要求對元素進行處理唱凯,而你只需要 “坐享其成”羡忘。
二. 流操作
整個流操作就是一條流水線,將元素放在流水線上一個個地進行處理磕昼。
其中數(shù)據(jù)源便是原始集合卷雕,然后將如 List<T> 的集合轉(zhuǎn)換為 Stream<T> 類型的流,并對流進行一系列的中間操作票从,比如過濾保留部分元素漫雕、對元素進行排序、類型轉(zhuǎn)換等纫骑;最后再進行一個終端操作蒙袍,可以把 Stream 轉(zhuǎn)換回集合類型浸须,也可以直接對其中的各個元素進行處理,比如打印、比如計算總數(shù)恩袱、計算最大值等等
很重要的一點是,很多流操作本身就會返回一個流痢甘,所以多個操作可以直接連接起來馍刮,我們來看看一條 Stream 操作的代碼:
如果是以前,進行這么一系列操作仿野,你需要做個迭代器或者 foreach 循環(huán)铣减,然后遍歷,一步步地親力親為地去完成這些操作脚作;但是如果使用流葫哗,你便可以直接聲明式地下指令缔刹,流會幫你完成這些操作。
有沒有想到什么類似的劣针?是的校镐,就像 SQL 語句一樣,select username from user where id = 1捺典,你只要說明:“我需要 id 是 1 (id = 1)的用戶(user)的用戶名(username)”鸟廓,那么就可以得到自己想要的數(shù)據(jù),而不需要自己親自去數(shù)據(jù)庫里面循環(huán)遍歷查找襟己。
三.方法介紹與實踐:
1.獲取流:stream() / parallelStream()
List<Integer> asList = Arrays.asList(10, 20, 30, 40, 50);
Stream<Integer> stream = asList.stream();
System.out.println(stream);
輸出結(jié)果:XX.stream() 方法獲取的是流引谜,然而我們在實際開發(fā)中一般需要獲取的是集合
2.流轉(zhuǎn)換為集合:collect(Collectors.toList())
List<Integer> asList = Arrays.asList(10, 20, 30, 40, 50);
List<Integer> collect1 = asList.stream().collect(Collectors.toList());
List<Integer> collect2 = asList.stream().collect(toList());
System.out.println(collect1);
System.out.println(collect2);
輸出結(jié)果: 這兩種寫法獲取的結(jié)果都是一樣的,第二種為簡寫
3.排序 sorted()
eg1:
List<Integer> asList = Arrays.asList(10, 20, 30, 40, 50);
List<Integer> asc = asList.stream().sorted().collect(toList()); //正序
List<Integer> desc = asList.stream().sorted(Comparator.reverseOrder()).collect(toList());//倒序
System.out.println(asc);
System.out.println(desc);
輸出結(jié)果:eg2:使用mybatis-plus 查詢后對獲得的數(shù)組中的某個字段進行排序(數(shù)據(jù)有點多截取了前5條數(shù)據(jù)進行排序)
List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<>()); //查詢表中所有數(shù)據(jù)
////按照ATag中SerialNumber字段排序
List<ATag> collect1 = aTags.stream().sorted(Comparator.comparing(ATag::getSerialNumber)).limit(5).collect(toList());
List<ATag> collect2 = aTags.stream().sorted(Comparator.comparing(ATag::getSerialNumber).reversed()).limit(5).collect(toList());
collect1.forEach(System.out::println);
System.out.println("----------分割線------------");
collect2.forEach(System.out::println);
輸出結(jié)果:
4.去重 distinct()
eg1:
List<Integer> asList = Arrays.asList(10,10,20,20,30,40,50);
asList.stream().distinct().collect(toList()).forEach(System.out::println);
輸出:
eg2:
如果想要對 List<Object> 中某個字段進行去重這里使用 distinct(類::字段) 這種方法是不行的(沒有這種篩選條件)
因此擎浴,需要借助一下過濾器以及下面學到的filter()方法员咽,實現(xiàn)對 List<Object> 中根據(jù)某個字段進行去重
參考文章:http://www.reibang.com/p/77c3b503730c
//過濾器:
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>(16);
return t -> map.putIfAbsent(keyExtractor.apply(t),Boolean.TRUE) == null;
}
List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));//查詢表中serial_number=6的數(shù)據(jù)
aTags.forEach(System.out::println);
System.out.println("-------------------------分割線-------------------------");
aTags.stream().filter(distinctByKey(ATag::getNameZh)).collect(toList()).forEach(System.out::println);
輸出 :5.過濾 filter()
保留 boolean 為 true 的元素
//查詢表中serial_number=6的數(shù)據(jù)
List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
aTags.forEach(System.out::println);
System.out.println("-------------------分割線-------------------------");
aTags.stream().filter(x->x.getNameZh().equals("御坂美琴")).collect(toList()).forEach(System.out::println);
輸出:6.截取(返回前 n 個元素) limit(long n)
//查詢表中serial_number=6的數(shù)據(jù)
List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
aTags.forEach(System.out::println);
System.out.println("-------------------分割線-------------------------");
aTags.stream().limit(2).forEach(System.out::println);
輸出結(jié)果:7.跳過 skip(long n)
List<Integer> asList = Arrays.asList(10,20,30,40,50);
System.out.println(asList.stream().skip(1).limit(2).collect(toList()));
這里使用了skip()和limit()
tips:
用在 limit(n) 前面時退客,先去除前 m 個元素再返回剩余元素的前 n 個元素
limit(n) 用在 skip(m) 前面時骏融,先返回前 n 個元素再在剩余的 n 個元素中去除 m 個元素
8. map(T -> R)
將流中的每一個元素 T 映射為 R(類似類型轉(zhuǎn)換)
eg1:
List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
aTags.forEach(System.out::println);
System.out.println("-------------------分割線-------------------------");
aTags.stream().map(ATag::getNameZh).collect(toList()).forEach(System.out::println);
這里相當于把List<ATag>轉(zhuǎn)換為List<String>
List<Integer> asList = Arrays.asList(10,20,30,40,50);
List<Integer> collect = asList.stream().map(x -> x + x * 0.1).mapToInt(T -> T.intValue()).boxed().collect(toList());
輸出:9. flatMap(T -> Stream<R>)
將流中的每一個元素 T 映射為一個流,再把每一個流連接成為一個流
List<String> list = new ArrayList<>();
list.add("aaa bbb ccc");
list.add("ddd eee fff");
list.add("ggg hhh iii");
list = list.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(toList());
上面例子中萌狂,我們的目的是把 List 中每個字符串元素以" "分割開档玻,變成一個新的 List<String>。
首先 map 方法分割每個字符串元素茫藏,但此時流的類型為 Stream<String[ ]>误趴,因為 split 方法返回的是 String[ ] 類型;所以我們需要使用 flatMap 方法务傲,先使用Arrays::stream將每個 String[ ] 元素變成一個 Stream<String> 流凉当,然后 flatMap 會將每一個流連接成為一個流,最終返回我們需要的 Stream<String>
10.anyMatch(T -> boolean)
流中是否有一個元素匹配給定的 T -> boolean 條件
List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
aTags.forEach(System.out::println);
System.out.println("-------------------分割線-------------------------");
System.out.println(aTags.stream().anyMatch(x -> x.getNameEn().equals("Misaka Miko")));
輸出:11. allMatch(T -> boolean)
流中是否所有元素都匹配給定的 T -> boolean 條件,當流中所有元素都符合條件的時候才返回true
List<Integer> asList = Arrays.asList(10,20,30,40,50);
System.out.println(asList.stream().allMatch(x -> x >= 10));
輸出:12.noneMatch(T -> boolean)
流中是否沒有元素匹配給定的 T -> boolean 條件(流中有元素匹配到條件返回true否則返回false)
List<Integer> asList = Arrays.asList(10,20,30,40,50);
System.out.println(asList.stream().noneMatch(x -> x >= 10));
輸出:
13. findAny() 和 findFirst()
findAny():找到其中一個元素 (使用 stream() 時找到的是第一個元素售葡;使用 parallelStream() 并行時找到的是其中一個元素)
findFirst():找到第一個元素
List<Integer> asList = Arrays.asList(10,20,30,40,50);
System.out.println(asList.stream().findFirst());
System.out.println(asList.stream().findAny());
System.out.println(asList.parallelStream().findAny());
輸出:
14.reduce((T, T) -> T) 和 reduce(T, (T, T) -> T)
用于組合流中的元素看杭,如求和,求積挟伙,求最大值等
eg1:其中楼雹,reduce 第一個參數(shù) 0 代表起始值為 0,lambda (a, b) -> a + b 即將兩值相加產(chǎn)生一個新值
List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
aTags.forEach(System.out::println);
System.out.println("-------------------分割線-------------------------");
System.out.println(aTags.stream().map(ATag::getParentId).reduce(0L, Long::sum));
輸出:eg2:
如果沒有初始值尖阔,需要考慮結(jié)果可能不存在的情況贮缅,因此返回的是 Optional 類型如果不需要這種返回類型設(shè)置初始值即可
List<Integer> asList = Arrays.asList(10,20,30,40,50);
Integer reduce1 = asList.stream().reduce(0, (x, y) -> x + y);
Integer reduce2 = asList.stream().mapToInt(T -> T.intValue()).boxed().reduce(0, (x, y) -> x + y);
Optional<Integer> reduce3 = asList.stream().reduce((x, y) -> x + y);
System.out.println("reduce1:"+reduce1 +"\n"+ "reduce2:"+reduce2+"\n"+"reduce3:"+reduce3);
15. count()
返回流中元素個數(shù),結(jié)果為 long 類型
List<Integer> asList = Arrays.asList(10,20,30,40,50);
asList.stream().count();
16.遍歷流中的每一個元素 forEach()
當然我們也可以通過forEach()遍歷流中的每一個元素介却,然后注入Mapper對流中元素進行CRUD
List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
aTags.forEach(System.out::println);
System.out.println("-------------------分割線-------------------------");
aTags.stream().forEach(item->{
System.out.println(item.getNameZh());
});
輸出:文章出處
作者:Howie_Y
鏈接:http://www.reibang.com/p/0bb4daf6c800
來源:簡書