一、Stream API分类介绍
二、代码示例
具体包含stream创建方式(test01方法)、Stream中间操作(test02方法)、终端操作(test03方法)
package com.xwood.demo.java8;@b@@b@public class Person implements Comparable{ @b@ public Person(String name, int age) {@b@ this.name = name;@b@ this.age = age;@b@ }@b@@b@ private String name;@b@ private int age;@b@@b@ public String getName() {@b@ return name;@b@ }@b@@b@ public void setName(String name) {@b@ this.name = name;@b@ }@b@@b@ public int getAge() {@b@ return age;@b@ }@b@@b@ public void setAge(int age) {@b@ this.age = age;@b@ }@b@@b@@b@ @Override@b@ public int compareTo(Object o) {@b@ return 0;@b@ }@b@}
package com.xwood.demo.java8;@b@@b@import java.util.*;@b@import java.util.stream.Collectors;@b@import java.util.stream.IntStream;@b@import java.util.stream.Stream;@b@@b@public class StreamAPITest {@b@ //创建Stream@b@ public void test01() {@b@ //通过Collection提供的stream()和parallelStream()方法创建流@b@ List<String> list = new ArrayList<>();@b@ list.add("hello");@b@ list.add("world");@b@ //将list中的元素以"流元素"的形式,存放于Stream中@b@ Stream<String> strStream = list.stream();@b@ Stream<String> strParallelStream = list.parallelStream();@b@@b@ String[] strs = new String[]{"hello", "world"};@b@ //通过Arrays提供的stream()方法创建流@b@ Stream<String> strStreamWithOfArray = Arrays.stream(strs);@b@ //通过Stream类提供的of()、iterate()和generate()方法创建流@b@ Stream<String> strStreamWithOf = Stream.of(strs);@b@ //创建无限流0、100、200、300、……,但仅仅获取前5个元素@b@ Stream<Integer> strStreamWithIterate = Stream.iterate(0, (x) -> ++x).limit(5);@b@ //创建无限流(包含无限个UUID),但仅仅获取前3个@b@ Stream<UUID> uUidStreamWithGenerate = Stream.generate(UUID::randomUUID).limit(3);@b@ //创建IntStream流@b@ IntStream intStream = IntStream.of(new int[]{1, 2, 3});@b@@b@ System.out.println("test01------------------------------------");@b@ }@b@@b@ //转换Stream操作@b@ public void test02() {@b@ //----------------limit()操作-------------------------@b@ //产生以0开始偶数组成的流,并且只使用前5个数字@b@ Stream<Integer> stream = Stream.iterate(0, x -> x + 2).limit(5);@b@ System.out.println("limt(5),截取无限流中的前5个元素:");@b@ stream.forEach(x -> System.out.print(x + "\t"));@b@@b@ @b@// 注意:一个Stream对象只能被终端操作使用一次,而上述的forEach()就是一个终端操作(用于打印流中的各个元素)。@b@// 因此,后续如果还要使用Stream对象,就必须重新生成。@b@@b@ @b@ //----------------filter()操作-------------------------@b@ @b@// 对产生的流进行过滤filter操作:筛选出比5大的数字;@b@// 以下语句等价于stream.filter( (x)->x>5 ).forEach( (x) -> System.out.println(x) );@b@ @b@ Stream<Integer> stream1 = Stream.iterate(0, x -> x + 2).limit(5);@b@ System.out.println("\nfilter((x) -> x > 3),筛选无限流中,大于3的元素:");@b@ stream1.filter((x) -> x > 3).forEach(x -> System.out.print(x + "\t"));@b@ //----------------limit()操作-------------------------@b@ //一个 Stream 只可以使用一次@b@ Stream<Integer> stream2 = Stream.iterate(0, x -> x + 2).limit(5);@b@ System.out.println("\nskip(2),跳过无限流中的前2个元素:");@b@ stream2.skip(2).forEach(x -> System.out.print(x + "\t"));@b@@b@ //----------------distinct()操作-------------------------@b@ Stream<Integer> stream3 = Stream.of(1, 1, 2, 2, 3, 4);@b@ //删除流中重复的元素:如果流中元素为简单类型(8个基本类型+String),则distinct()会自动去重@b@ System.out.println("\ndistinct(),删除无限流中的重复元素(简单类型):");@b@ stream3.distinct().forEach(x -> System.out.print(x + "\t"));@b@@b@ //删除流中重复的元素:如果流中元素为对象类型,需要通过“重写hashCode()和equals()”来告诉来告诉程序什么样的对象可以作为同一个元素(例如,可以认为:当name和age相同时,就作为同一个对象)@b@ Person[] pers = new Person[]{new Person("zs", 23), new Person("zs", 23), new Person("ls", 24)};@b@ System.out.println("\ndistinct(),删除无限流中的重复元素(对象类型):");@b@ Stream.of(pers).distinct().forEach(x -> System.out.print(x + "\t"));@b@@b@ //----------------map()操作:将每个元素进行了一次映射操作(转换操作),因为是每个元素都有映射后的产物,所以是map()是一对一的。-------------------------@b@ //将Stream中的每个单词,转为与之对应的大写单词@b@ Stream<String> stream4 = Stream.of("hello", "world", "hello", "stream");@b@ System.out.println("\nmap(),将Stream中的每个单词转为大写:");@b@ stream4.map(str -> str.toUpperCase()).forEach(x -> System.out.print(x + "\t"));@b@@b@ //map常用于部分内容的提取:例如,从Stream的各个Person对象中提取出name属性@b@ Person[] pers5 = new Person[]{new Person("ww", 25), new Person("zl", 26), new Person("zs", 23), new Person("ls", 24)};@b@ Stream<Person> stream5 = Stream.of(pers5);@b@ System.out.println("\nmap(),提取各个Person中的name属性:");@b@ stream5.map(per -> per.getName()).forEach(x -> System.out.print(x + "\t"));@b@@b@ //----------------flatMap()操作-------------------------@b@ //将Stream中所有单词转为字母形式,并删除重复的字母。例如,将"ab","bc"转为"a","b","b","c",再删除一个重复的"b",最终显示"a","b","c"@b@ Stream<String> stream6 = Stream.of("hello", "world", "hello", "stream");@b@ System.out.println("\nflatMap(),打印所有字符串中出现的字母,要求不重复:");@b@ //将流中的每个字符串,都映射成为Stream<String[]>,即{"h","e","l","l","o"},{"w","o","r","l","d"},...,即每个流元素都是一个String数组@b@ stream6.map(str -> str.split(""))@b@ //将上一步map()后的产物,全部纳入到一个“容器”中,即{"h","e","l","l","o","w","o","r","l","d",..,"e","a","m"},注意此时只有一个数组。可以发现,flatMap()是将多个String数组,转为了一个String数组,因此是多对一的。@b@ .flatMap(str -> Arrays.stream(str))@b@ //对上一步flatMap()的产物去重@b@ .distinct().forEach(x -> System.out.print(x + "\t"));@b@@b@ @b@// 排序操作:@b@// 在Stream中,可以使用sorted()或sorted(Comparator<T>)进行排序@b@// 1.如果调用sorted(),则使用的是Comparable排序;@b@// sorted()方法会调用排序元素所重写的comparator()方法,根据comparator()中的规则进行排序。@b@// 例如,如果排序的是Person类型的元素,就需要先让Person实现则使用的是Comparable排序接口,并重写comparator()方法,如下@b@ @b@ //----------------内部排序sorted()操作-------------------------@b@ Person[] pers7 = new Person[]{new Person("ww", 25), new Person("zs", 23), new Person("ww", 22), new Person("ls", 24)};@b@ System.out.println("\nsorted(),使用Comparable中的comparator()方法,对流中的Person对象排序(按age从小到大):");@b@ Stream.of(pers7).sorted().forEach(System.out::println);@b@ //JDK提供的很多类(如String)自身已经实现了Comparable接口,因此可以直接对其进行sort()排序,如下:@b@@b@ String[] strs = new String[]{"bb", "cc", "aa", "dd"};@b@ System.out.println("\nsorted(),对流中的字符串进行排序(String自身实现了Comparable接口,可以按字典顺序排序):");@b@ Stream.of(strs).sorted().forEach(str -> System.out.print(str + "\t"));@b@@b@ @b@// 2.如果调用sorted(Comparator<T>),则使用的是Comparator排序;@b@// sorted(Comparator<T>)方法会使用参数中Comparator接口的compare()方法进行排序。@b@ @b@ System.out.println("\nsorted(Comparator<T>),使用Comparator中的compare()方法,对流中的Person对象排序(按age从小到大):");@b@ Stream.of(pers7).sorted((a, b) -> Integer.compare(a.getAge(), b.getAge())).forEach(System.out::println);@b@@b@ //还可以使用sorted()或sorted(Comparator<T>)进行多次排序,例如:对流中的Person对象,先按name排序,如果name相同再按age排序,如下@b@ System.out.println("\nsorted(Comparator<T>),二次排序(先name,再age):");@b@ Stream.of(pers7).sorted((a, b) ->@b@ {@b@ if (!a.getName().equals(b.getName())) {//排序规则:先name,再age@b@ //调用String内部提供的比较方法@b@ return String.CASE_INSENSITIVE_ORDER.compare(a.getName(), b.getName());@b@ } else {@b@ //调用Integer提供的比较方法@b@ return Integer.compare(a.getAge(), b.getAge());@b@ }@b@ })@b@ .forEach(System.out::println);@b@@b@ System.out.println("test02------------------------------------");@b@ }@b@@b@ static Person[] pers = null;@b@@b@ static {@b@ pers = new Person[]{new Person("ww", 25), new Person("zl", 26), new Person("zl", 22), new Person("zs", 23), new Person("ls", 24)};@b@ }@b@@b@ //终端操作@b@ public void test03() {@b@ //判断是否全部人的age都大于24@b@ boolean result = Stream.of(pers).map(per -> per.getAge()).allMatch(age -> age > 24);@b@ System.out.println("allMatch():" + result);@b@@b@ //判断是否存在大于24的age (即只要有比24大的age即可)@b@ boolean result1 = Stream.of(pers).map(per -> per.getAge()).anyMatch(age -> age > 24);@b@ System.out.println("anyMatch():" + result1);@b@@b@ //判断是否没有age比24大(即不存在大于24的age)@b@ boolean result2 = Stream.of(pers).map(per -> per.getAge()).noneMatch(age -> age > 24);@b@ System.out.println("noneMatch():" + result2);@b@@b@ //获取流中第一个元素@b@ Optional<Integer> firstAge = Stream.of(pers).map(per -> per.getAge()).findFirst();@b@ System.out.println("firstAge():" + firstAge.get());@b@@b@ //获取流中任一个元素(不是随机一个元素,而是根据某个算法找到的一个元素;即:如果对同一个流多次进行findAny()操作,那么得到的将是同一个元素)@b@ Optional<Integer> certainAge = Stream.of(pers).map(per -> per.getAge()).findAny();@b@ System.out.println("findAny():" + certainAge.get());@b@@b@ //获取“最大”的元素。“最大”是由max(Comparator<T>)方法的参数约定@b@ Optional<Person> maxPerson = Stream.of(pers).max((a, b) -> a.getAge() > b.getAge() ? 1 : (a.getAge() < b.getAge() ? -1 : 0));@b@ System.out.println("max():" + maxPerson.get().getAge());@b@@b@ //reduce,聚合流中的所有元素:本次是将流中的全部age值,聚合为一个值(所有age之和)@b@ Integer reduceAge = Stream.of(pers).map(per -> per.getAge()).reduce(0, (a, b) -> a + b);@b@ System.out.println("reduce():" + reduceAge);@b@ @b@// 本程序中的reduce( 0,(a,b)->a+b )表示求和,类似于以下for()求和方式。其中,a相当于sum,b相当于i。@b@// int sum = 0;@b@// for(int i=0;i<100;i++){@b@// sum += i ;@b@// }@b@ @b@@b@ //求名字中s出现的次数@b@ Integer sCount = Stream.of(pers).map(per -> per.getName()).map(str -> str.split(""))@b@ .flatMap(str -> Arrays.stream(str))@b@ //先将每个字母映射数字0或1(如果是s,则映射为1;否则为0),再累加全部的数字(只有s才是有效的累加;因为其他字母是0,对0进行累加是没有效果的)@b@ .map(a -> a.equals("s") ? 1 : 0).reduce(0, (x, y) -> x + y);@b@ System.out.println("s出现的次数是:" + sCount);@b@@b@// ----collect()聚合操作:将流的元素聚合成一个集合(或一个值)----- @b@ //聚合成一个List集合@b@ List<String> nameList = Arrays.stream(pers).map(per -> per.getName()).collect(Collectors.toList());@b@ System.out.println("collect(Collectors.toList():" + nameList);@b@@b@ //聚合成一个Map集合:实现按key分组(根据年龄分组)@b@ Map<Integer, List<Person>> ageMap = Arrays.stream(pers).collect(Collectors.groupingBy(Person::getAge));@b@ System.out.println("Collectors.groupingBy(Person::getAge):\n" + ageMap);@b@@b@ //聚合成一个Map集合:实现按key分区(根据age是否大于24)@b@ Map<Boolean, List<Integer>> agePartition = Arrays.stream(pers).map(Person::getAge).collect(Collectors.partitioningBy(age -> age > 24));@b@ System.out.println("Collectors.partitioningBy( age -> age>24 ):" + agePartition);@b@@b@ //聚合成一个值:求最小值(也可以是最大值、个数、求和等聚合计算)@b@ Optional<Integer> minAge = Arrays.stream(pers).map(per -> per.getAge()).collect(Collectors.minBy(Integer::min));@b@ System.out.println("Collectors.minBy(Integer::min):" + minAge);@b@@b@ //聚合成一个值:连接操作,将流中的多个值连接成一个字符串,并加上前缀和后缀。@b@ String allNameInOneStr = Arrays.stream(pers).map(Person::getName).collect(Collectors.joining(",", "**prefix**", "**suffix**"));@b@ System.out.println("Collectors.joining(...)" + allNameInOneStr);@b@@b@ System.out.println("test03------------------------------------");@b@ }@b@@b@@b@ public static void main(String[] args) {@b@ new StreamAPITest().test01() ;@b@ new StreamAPITest().test02() ;@b@ new StreamAPITest().test03();@b@ }@b@}
控制台运行结果
test01------------------------------------@b@limt(5),截取无限流中的前5个元素:@b@0 2 4 6 8 @b@filter((x) -> x > 3),筛选无限流中,大于3的元素:@b@4 6 8 @b@skip(2),跳过无限流中的前2个元素:@b@4 6 8 @b@distinct(),删除无限流中的重复元素(简单类型):@b@1 2 3 4 @b@distinct(),删除无限流中的重复元素(对象类型):@b@com.xwood.demo.java8.Person@16b98e56 com.xwood.demo.java8.Person@7ef20235 com.xwood.demo.java8.Person@27d6c5e0 @b@map(),将Stream中的每个单词转为大写:@b@HELLO WORLD HELLO STREAM @b@map(),提取各个Person中的name属性:@b@ww zl zs ls @b@flatMap(),打印所有字符串中出现的字母,要求不重复:@b@h e l o w r d s t a m @b@sorted(),使用Comparable中的comparator()方法,对流中的Person对象排序(按age从小到大):@b@com.xwood.demo.java8.Person@7291c18f@b@com.xwood.demo.java8.Person@34a245ab@b@com.xwood.demo.java8.Person@7cc355be@b@com.xwood.demo.java8.Person@6e8cf4c6@b@@b@sorted(),对流中的字符串进行排序(String自身实现了Comparable接口,可以按字典顺序排序):@b@aa bb cc dd @b@sorted(Comparator<T>),使用Comparator中的compare()方法,对流中的Person对象排序(按age从小到大):@b@com.xwood.demo.java8.Person@7cc355be@b@com.xwood.demo.java8.Person@34a245ab@b@com.xwood.demo.java8.Person@6e8cf4c6@b@com.xwood.demo.java8.Person@7291c18f@b@@b@sorted(Comparator<T>),二次排序(先name,再age):@b@com.xwood.demo.java8.Person@6e8cf4c6@b@com.xwood.demo.java8.Person@7cc355be@b@com.xwood.demo.java8.Person@7291c18f@b@com.xwood.demo.java8.Person@34a245ab@b@test02------------------------------------@b@allMatch():false@b@anyMatch():true@b@noneMatch():false@b@firstAge():25@b@findAny():25@b@max():26@b@reduce():120@b@s出现的次数是:2@b@collect(Collectors.toList():[ww, zl, zl, zs, ls]@b@Collectors.groupingBy(Person::getAge):@b@{22=[com.xwood.demo.java8.Person@238e0d81], 23=[com.xwood.demo.java8.Person@31221be2], 24=[com.xwood.demo.java8.Person@377dca04], 25=[com.xwood.demo.java8.Person@728938a9], 26=[com.xwood.demo.java8.Person@21b8d17c]}@b@Collectors.partitioningBy( age -> age>24 ):{false=[22, 23, 24], true=[25, 26]}@b@Collectors.minBy(Integer::min):Optional[24]@b@Collectors.joining(...)**prefix**ww,zl,zl,zs,ls**suffix**@b@test03------------------------------------@b@@b@Process finished with exit code 0