Java 8 stream的记录
Java 8 stream的記錄
- Java 8 stream
- 1、什么是流
- 2、如何生成流
- 1、通過集合生成,應用中最常用的一種
- 2、通過數組生成
- 3、通過值生成
- 4、通過文件生成
- 5、通過函數生成
- 1.iterator
- 2.generator
- 3、流的操作類型
- 4、常規操作案例
- collect 返回集合
- reduce的介紹及用法
- Steam之兩個list間交集、并集、差集
- list和tree相互轉換
- stream流式寫法把list換為Tree
- People.java
- Zone.java
Java 8 stream
Stream 是 Java8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常復雜的查找、過濾和映射數據等操作。使用Stream API 對集合數據進行操作,就類似于使用 SQL 執行的數據庫查詢。也可以使用 Stream API 來并行執行操作。簡而言之,Stream API 提供了一種高效且易于使用的處理數據的方式。
1、什么是流
流是從支持數據處理操作的源生成的元素序列,源可以是數組、文件、集合、函數。流不是集合元素,它不是數據結構并不保存數據,它的主要目的在于計算。
如果對以上函數接口不太理解的話,可參考另外一篇文章:Java 8 函數式接口
鏈接: Java 8 函數式接口
2、如何生成流
生成流的方式主要有五種
1、通過集合生成,應用中最常用的一種
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6); Stream<Integer> stream = integerList.stream();2、通過數組生成
int[] intArr = {1, 2, 3, 4, 5, 6}; IntStream stream = Arrays.stream(intArr);通過Arrays.stream方法生成流,并且該方法生成的流是數值流【即IntStream】而不是 Stream。補充一點使用數值流可以避免計算過程中拆箱裝箱,提高性能。
Stream API提供了mapToInt、mapToDouble、mapToLong三種方式將對象流【即Stream 】轉換成對應的數值流,同時提供了boxed方法將數值流轉換為對象流.
3、通過值生成
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);通過Stream的of方法生成流,通過Stream的empty方法可以生成一個空流.
4、通過文件生成
Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());通過Files.line方法得到一個流,并且得到的每個流是給定文件中的一行
5、通過函數生成
1.iterator
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);iterate方法接受兩個參數,第一個為初始化值,第二個為進行的函數操作,因為iterator生成的流為無限流,通過limit方法對流進行了截斷,只生成5個偶數。
2.generator
Stream<Double> stream = Stream.generate(Math::random).limit(5);generate方法接受一個參數,方法參數類型為Supplier ,由它為流提供值。generate生成的流也是無限流,因此通過limit對流進行了截斷。
3、流的操作類型
操作分類
| 中間操作 | 無狀態 (stateless) | unordered() fillter() map() mapToInt() peek() mapToDouble() flatMap() ... |
| 有狀態 (staeful) | distinct() sorted() limit() skip() ... | |
| 結束操作 | 非短路操作 (non-short-circuit operation) | forEach() forEachOrderd() toArray() reduce() collect() max() min() count() ... |
| 短路操作 (short circuit operation) | anyMatch() allMatch() noneMatch() findFirst() findAny() |
4、常規操作案例
public class StreamDemo {static List<People> list = null;//初始化數據static {list = Arrays.asList(new People("1", "Tom", 88, 90),new People("2", "Jerry", 77, 89),new People("3", "Lily", 98, 79),new People("4", "Lucy", 70, 80),new People("5", "趙二", 88, 90),new People("6", "HanMeiMei", 87, 79));}public void streamtest() {// filter 過濾器返回還是一個stream流對象//查詢math成績大于80的學生并遍歷輸出list.stream().filter(e -> e.getMath() > 80).forEach(System.out::println);//.forEach(e->System.out.println(e))//統計數量countSystem.out.println(list.stream().count());//如統計總分大于160的人數System.out.println(list.stream().filter(e -> e.getEnglish() + e.getMath() > 160).count());//limit 取前n個值list.stream().limit(3).forEach(System.out::println);//skip 跳過前n個list.stream().skip(2).forEach(System.out::println);//distinct 去除重復數據list.stream().distinct().forEach(System.out::println);//map 映射元素可以對元素進行操作 例如對每個人年齡加1list.stream().map(e -> {e.setAge(e.getAge() + 1);return e;}).forEach(System.out::println);//sorted 排序//升序list.stream().sorted((a, b) -> {return a.getEnglish().compareTo(b.getEnglish());});List<People> sortenList = list.stream().sorted(Comparator.comparing(People::getAge)).collect(Collectors.toList());//降序list.stream().sorted((a, b) -> {return b.getEnglish().compareTo(a.getEnglish());});//自定義排序:先按姓名升序,姓名相同則按年齡升序list.stream().sorted((o1, o2) -> {if (o1.getName().equals(o2.getName())) {return o1.getAge() - o2.getAge();} else {return o1.getName().compareTo(o2.getName());}}).forEach(System.out::println);List<People> sortenListDesc = list.stream().sorted(Comparator.comparing(People::getAge).reversed()).collect(Collectors.toList());//求和字段屬性為BigDecimal時:BigDecimal totalCost = list.stream().map(People::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);//返回第一個元素Optional<People> first = list.stream().findFirst();System.out.println(first.get());//返回任意一個元素System.out.println(list.stream().findAny().get());//anyMatch 是否匹配任意一元素 檢查是否包含名字為Tom的System.out.println(list.stream().anyMatch(e -> e.getName().equals("Tom")));//allMatch 是否匹配所有元素System.out.println(list.stream().allMatch(e -> e.getName().equals("Tom")));//noneMatch 是否未匹配所有元素System.out.println(list.stream().noneMatch(e -> e.getName().equals("Tom")));//findFirst 返回元素中第一個值People student = list.stream().findFirst().get();//findAny 返回元素中任意一個值People student1 = list.stream().findAny().get();//max 返回最大值 查詢英語成績最高的學生People student2 = list.stream().max((l1, l2) -> l2.getEnglish().compareTo(l1.getEnglish())).get();//min 最小值 將上面l1,l2位置對調People student3 = list.stream().max((l1, l2) -> l2.getEnglish().compareTo(l1.getEnglish())).get();/*** filter:過濾流中的某些元素* limit(n):獲取n個元素* skip(n):跳過n元素,配合limit(n)可實現分頁* distinct:通過流中元素的 hashCode() 和 equals() 去除重復元素*/Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);Stream<Integer> newStream = stream.filter(s -> s > 5) //6 6 7 9 8 10 12 14 14.distinct() //6 7 9 8 10 12 14.skip(2) //9 8 10 12 14.limit(2); //9 8newStream.forEach(System.out::println);/*** map:接收一個函數作為參數,該函數會被應用到每個元素上,并將其映射成一個新的元素。* flatMap:接收一個函數作為參數,將流中的每個值都換成另一個流,然后把所有流連接成一個流。* List<String> list = Arrays.asList("a,b,c", "1,2,3");*///將每個元素轉成一個新的且不帶逗號的元素Stream<String> s1 = list.stream().map(s -> s.getName().replaceAll(",", ""));s1.forEach(System.out::println); // abc 123Stream<String> s3 = list.stream().flatMap(s -> {//將每個元素轉換成一個streamString[] split = s.getName().split(",");Stream<String> s2 = Arrays.stream(split);return s2;});s3.forEach(System.out::println); // a b c 1 2 3}/**Reduce常見的用法*/public void testReduce() {Stream<Integer> stream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8});//求集合元素只和Integer result = stream.reduce(0, Integer::sum);System.out.println(result);stream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5, 6, 7});//求和stream.reduce((i, j) -> i + j).ifPresent(System.out::println);stream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5, 6, 7});//求最大值stream.reduce(Integer::max).ifPresent(System.out::println);stream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5, 6, 7});//求最小值stream.reduce(Integer::min).ifPresent(System.out::println);stream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5, 6, 7});//做邏輯stream.reduce((i, j) -> i > j ? j : i).ifPresent(System.out::println);stream = Arrays.stream(new Integer[]{1, 2, 3, 4, 5, 6, 7});//求邏輯求乘機int result2 = stream.filter(i -> i % 2 == 0).reduce(1, (i, j) -> i * j);Optional.of(result2).ifPresent(System.out::println);//拼接字符串String append = list.stream().map(People::getName).reduce("拼接字符串:", String::concat);//求平均值double average = list.stream().mapToInt(People::getAge).average().orElse(0.0);//求最大值int min = list.stream().map(People::getAge).reduce(Integer::min).orElse(0);System.out.println("min : " + min);//求最小值int max = list.stream().map(People::getAge).reduce(Integer::max).orElse(0);System.out.println("max : " + max);//四種求和的方式int ageSumThree = list.stream().map(People::getAge).reduce(0, Integer::sum);System.out.println("ageSumThree: " + ageSumThree);int ageSumFive = list.stream().map(People::getAge).reduce(Integer::sum).orElse(0);System.out.println("ageSumFive: " + ageSumFive);int ageSumOne = list.stream().collect(Collectors.summingInt(People::getAge));System.out.println("ageSumOne" + ageSumOne);int ageSumFour = list.stream().mapToInt(People::getAge).sum();System.out.println("ageSumFour: " + ageSumFour);} }collect 返回集合
/*** collect:接收一個Collector實例,將流中元素收集成另外一個數據結構。* Collector<T, A, R> 是一個接口,有以下5個抽象方法:* Supplier<A> supplier():創建一個結果容器A* BiConsumer<A, T> accumulator():消費型接口,第一個參數為容器A,第二個參數為流中元素T。* BinaryOperator<A> combiner():函數接口,該參數的作用跟上一個方法(reduce)中的combiner參數一樣,將并行流中各個子進程的運行結果(accumulator函數操作后的容器A)進行合并。* Function<A, R> finisher():函數式接口,參數為:容器A,返回類型為:collect方法最終想要的結果R。* Set<Characteristics> characteristics():返回一個不可變的Set集合,用來表明該Collector的特征。有以下三個特征:* CONCURRENT:表示此收集器支持并發。(官方文檔還有其他描述,暫時沒去探索,故不作過多翻譯)* UNORDERED:表示該收集操作不會保留流中元素原有的順序。* IDENTITY_FINISH:表示finisher參數只是標識而已,可忽略。* */ //裝成list List<Integer> ageList = list.stream().map(People::getAge).collect(Collectors.toList()); // [10, 20, 10]//轉成set Set<Integer> ageSet = list.stream().map(People::getAge).collect(Collectors.toSet()); // [20, 10]//轉成map,注:key不能相同,否則報錯 Map<String, Integer> studentMap = list.stream().collect(Collectors.toMap(People::getName, People::getAge)); // {cc=10, bb=20, aa=10}//字符串分隔符連接 String joinName = list.stream().map(People::getName).collect(Collectors.joining(",", "(", ")")); // (aa,bb,cc)//聚合操作 //1.學生總數 Long count = list.stream().collect(Collectors.counting()); //2.最大年齡 (最小的minBy同理) Integer maxAge = list.stream().map(People::getAge).collect(Collectors.maxBy(Integer::compare)).get(); //3.所有人的年齡 Integer sumAge = list.stream().collect(Collectors.summingInt(People::getAge)); //4.平均年齡 Double averageAge = list.stream().collect(Collectors.averagingDouble(People::getAge)); // 13.333333333333334 // 帶上以上所有方法 DoubleSummaryStatistics statistics = list.stream().collect(Collectors.summarizingDouble(People::getAge)); System.out.println("count:" + statistics.getCount() + ",max:" + statistics.getMax() + ",sum:" + statistics.getSum() + ",average:" + statistics.getAverage());//分組 Map<String, List<People>> collect = list.stream().collect(Collectors.groupingBy(People::getId)); //多重分組,先根據分數分再根據年齡分 Map<Integer, Map<Integer, List<People>>> typeAgeMap = list.stream().collect(Collectors.groupingBy(People::getMath, Collectors.groupingBy(People::getAge)));//分區 //分成兩部分,一部分大于10歲,一部分小于等于10歲 Map<Boolean, List<People>> partMap = list.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 10));/*List<Map<String, Object>> groupList = list2.stream().collect(Collectors.groupingBy(d -> d.get("region"))).entrySet().stream().map(d -> {Map<String, Object> map = new HashMap<>();map.put("recruitList", d.getValue());map.put("region", d.getKey());return map;}).collect(Collectors.toList());*/reduce的介紹及用法
????Optional reduce(BinaryOperator accumulator):第一次執行時,accumulator函數的第一個參數為流中的第一個元素,第二個參數為流中元素的第二個元素;第二次執行時,第一個參數為第一次函數執行的結果,第二個參數為流中的第三個元素;依次類推。
????T reduce(T identity, BinaryOperator accumulator):流程跟上面一樣,只是第一次執行時,accumulator函數的第一個參數為identity,而第二個參數為流中的第一個元素。
???? U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator combiner):在串行流(stream)中,該方法跟第二個方法一樣,即第三個參數combiner不會起作用。在并行流(parallelStream)中,我們知道流被fork join出多個線程進行執行,此時每個線程的執行流程就跟第二個方法reduce(identity,accumulator)一樣,而第三個參數combiner函數,則是將每個線程的執行結果當成一個新的流,然后使用第一個方法reduce(accumulator)流程進行規約。
reduce參考說明
/** reduce* Optional<T> reduce(BinaryOperator<T> accumulator):* 第一次執行時,accumulator函數的第一個參數為流中的第一個元素,第二個參數為流中元素的第二個元素;第二次執行時,第一個參數為第一次函數執行的結果,第二個參數為流中的第三個元素;依次類推。** T reduce(T identity, BinaryOperator<T> accumulator):* 流程跟上面一樣,只是第一次執行時,accumulator函數的第一個參數為identity,而第二個參數為流中的第一個元素。** <U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner):* 在串行流(stream)中,該方法跟第二個方法一樣,即第三個參數combiner不會起作用。在并行流(parallelStream)中,我們知道流被fork join出多個線程進行執行,* 此時每個線程的執行流程就跟第二個方法reduce(identity,accumulator)一樣,而第三個參數combiner函數,則是將每個線程的執行結果當成一個新的流,然后使用第一個方法reduce(accumulator)流程進行規約。*///經過測試,當元素個數小于24時,并行時線程數等于元素個數,當大于等于24時,并行時線程數為16List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24);Integer v = list.stream().reduce((x1, x2) -> x1 + x2).get();System.out.println(v); // 300Integer v1 = list.stream().reduce(10, (x1, x2) -> x1 + x2);System.out.println(v1); //310Integer v2 = list.stream().reduce(0,(x1, x2) -> {System.out.println("stream accumulator: x1:" + x1 + " x2:" + x2);return x1 - x2;},(x1, x2) -> {System.out.println("stream combiner: x1:" + x1 + " x2:" + x2);return x1 * x2;});System.out.println(v2); // -300Integer v3 = list.parallelStream().reduce(0,(x1, x2) -> {System.out.println("parallelStream accumulator: x1:" + x1 + " x2:" + x2);return x1 - x2;},(x1, x2) -> {System.out.println("parallelStream combiner: x1:" + x1 + " x2:" + x2);return x1 * x2;});System.out.println(v3); //197474048Steam之兩個list間交集、并集、差集
public void listOpt() {List<String> list1 = new ArrayList();list1.add("1111");list1.add("2222");list1.add("3333");List<String> list2 = new ArrayList();list2.add("3333");list2.add("4444");list2.add("5555");// 交集List<String> intersection = list1.stream().filter(item -> list2.contains(item)).collect(Collectors.toList());System.out.println("---得到交集 intersection---");intersection.parallelStream().forEach(System.out::println);// 差集 (list1 - list2)List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(Collectors.toList());System.out.println("---得到差集 reduce1 (list1 - list2)---");reduce1.parallelStream().forEach(System.out::println);// 差集 (list2 - list1)List<String> reduce2 = list2.stream().filter(item -> !list1.contains(item)).collect(Collectors.toList());System.out.println("---得到差集 reduce2 (list2 - list1)---");reduce2.parallelStream().forEach(System.out::println);// 并集List<String> listAll = list1.parallelStream().collect(Collectors.toList());List<String> listAll2 = list2.parallelStream().collect(Collectors.toList());listAll.addAll(listAll2);System.out.println("---得到并集 listAll---");listAll.parallelStream().forEach(System.out::println);// 去重并集List<String> listAllDistinct = listAll.stream().distinct().collect(Collectors.toList());System.out.println("---得到去重并集 listAllDistinct---");listAllDistinct.parallelStream().forEach(System.out::println);System.out.println("---原來的List1---");list1.parallelStream().forEach(System.out::println);System.out.println("---原來的List2---");list2.parallelStream().forEach(System.out::println);}list和tree相互轉換
/*** list轉樹形List* @param list* @return*/public static List<Zone> list2tree(List<Zone> list) {List<Zone> result = new ArrayList<>();Map<String, Zone> map = list.stream().collect(Collectors.toMap(test -> test.getId(), test -> test));for (Zone test : list) {Zone p = map.get(test.getParentId());if (p == null) {result.add(test);} else {if (p.getChildren() == null) {p.setChildren(new ArrayList<>());}p.getChildren().add(test);}}return result;}/*** 樹形list轉list* @param list* @return*/public static List<Zone> tree2list(List<Zone> list) {List<Zone> result = new ArrayList<>();for (Zone retTreePath : list) {List<Zone> c = retTreePath.getChildren();result.add(retTreePath);if (!CollectionUtils.isEmpty(c)) {result.addAll(tree2list(c));retTreePath.setChildren(null);}}return result;}stream流式寫法把list換為Tree
/*** 把list換為Tree** @param zoneList* @return*/public static List<Zone> listToTree(List<Zone> zoneList) {Map<String, List<Zone>> zoneByParentIdMap = zoneList.stream().collect(Collectors.groupingBy(Zone::getParentId));zoneList.forEach(zone -> zone.setChildren(zoneByParentIdMap.get(zone.getId())));return zoneList.stream().filter(v -> v.getParentId().equals("0")).collect(Collectors.toList());}People.java
public class People {private String id;private String name;private Integer age;private Integer math;private Integer english;private BigDecimal money;private List<People> children;public People(String id, String name, Integer age,Integer math) {this.id = id;this.name = name;this.age = age;this.math=math;} }Zone.java
public class Zone {private String id;private String name;private String parentId;private List<Zone> children;public Zone(String id, String name, String parentId) {this.id = id;this.name = name;this.parentId = parentId;}public void addChildren(Zone zone) {if (children == null) {children = new ArrayList<>();}children.add(zone);}//get set 方法 }參考的博客:
Java 8 stream的詳細用法
JAVA stream流詳細教程
總結
以上是生活随笔為你收集整理的Java 8 stream的记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 读论文——“时间序列预测方法综述”
- 下一篇: 京瓷5501i A3小册子打印设置