Java8中Stream是对集合进行操作,可以执行非常复杂的查找、过滤、映射等操作。使用Stream API可以像SQL执行的数据库查询一样对集合进行操作。也可以进行并行操作。
Stream API提供了一种高效且易于实现的处理数据的方式。
集合讲的是数据,流讲的时计算!
**
Stream操作过程:
- 创建流
- (中间操作)处理流
- 终止操作
Stream特点:
- Stream不会存储元素
- Stream不会修改源数据,最终返回一个持有结果的新Stream
Stream操作时延迟的,这意味着它们会等到需要结果的时候才会执行。
创建Stream流
通过 Collection 系列集合提供的 stream() 方法或 parallelStream()方法创建流
- 通过Arrays 中静态方法 stream() 获取数组流
- 通过Stream 类的静态方法 of() 创建
- 创建无限流 Stream.iterate()
生产流 Stream.generate()
@Testpublic void test05(){// 方式一Integer[] integers = new Integer[10];Stream<Integer> stream1 = Arrays.stream(integers);// 方式二List<String> list = new ArrayList<>();Stream<String> stream2 = list.stream();// 方式三Stream<String> integerStream = Stream.of("aa","bb","cc");// 方式四Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);// 方式五Stream<Double> generate = Stream.generate(Math::random);}
筛选与切片
filter 从流中排除某些元素
filter方法需要传入一个函数接口
Predicate,通过Lambda表达式对流中每个数据进行判断,满足条件则添加到新的流中。Stream<T> filter(Predicate<? super T> predicate);
@Testpublic void test06(){Integer[] integers = new Integer[]{1,2,3,4,5,6,7,8,9,10};// 创建流Stream<Integer> stream = Arrays.stream(integers);// 返回的是一个新的流,中间操作时不执行的Stream<Integer> integerStream = stream.filter(integer -> integer % 2 == 0);// 终止操作,输出流中内容integerStream.forEach(integer -> System.out.print(integer+" "));}
对于流的操作也可以写成
@Testpublic void test06(){Integer[] integers = new Integer[]{1,2,3,4,5,6,7,8,9,10};Arrays.stream(integers).filter(integer -> integer%2==0).forEach(integer -> System.out.println(integer+" "));}
limit 截断流,使其元素不超过给定数量
比如说,找到所需要的数据条数后,后续的操作就不再执行了,这个操作被称为(短路)
@Testpublic void test06(){Integer[] integers = new Integer[]{1,2,3,4,5,6,7,8,9,10};Arrays.stream(integers).filter(integer -> integer%2==0).limit(2).forEach(integer -> System.out.print(integer+" "));}
skip 跳过指定数量
@Testpublic void test06(){Integer[] integers = new Integer[]{1,2,3,4,5,6,7,8,9,10};Arrays.stream(integers).filter(integer -> integer%2==0).skip(2).forEach(integer -> System.out.print(integer+" "));}
distinct 去重
通过流所生成对象的hashCode() 和 equals() 去重元素
@Testpublic void test06(){Integer[] integers = new Integer[]{1,2,3,4,5,6,7,8,9,10,10,8,9};Arrays.stream(integers).filter(integer -> integer%2==0).skip(2).distinct().forEach(integer -> System.out.print(integer+" "));}

这里之所以可以去重,使用为 Integer类重写了hashCode() 和 equals() 方法。映射
map
接收Lambda(函数接口),将元素转换成其它形式或提取数据。接受一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。
@Testpublic void test07(){List<String> list = Arrays.asList("aaa","bbb","ccc");// 将流中每个元素转为大写list.stream().map(s -> s.toUpperCase()).forEach(System.out::println);}

嵌套流@Testpublic void test08(){List<Integer> list = Arrays.asList(123,456,789);Stream<Stream<Integer>> streamStream = list.stream().map(integer -> filterCharacter(integer));streamStream.forEach(s->s.forEach(System.out::println));}// 将数进行分解放入list中public static Stream<Integer> filterCharacter(Integer integer){List<Integer> list = new ArrayList<>();while (integer%10 != 0){list.add(integer%10);integer = integer/10;}return list.stream();}
flatMap
将流中每个元素转换成另一个流,然后把所有的流连接起来
@Testpublic void test09(){List<Integer> list = Arrays.asList(123,456,789);list.stream().flatMap(integer -> filterCharacter(integer)).forEach(i-> System.out.print(i+" "));}// 将数进行分解放入list中public static Stream<Integer> filterCharacter(Integer integer){List<Integer> list = new ArrayList<>();while (integer%10 != 0){list.add(integer%10);integer = integer/10;}return list.stream();}
排序
sorted() 自然排序
按字典排序,其内部时调用`compareTo() 方法进行排序
@Testpublic void test10(){List<String> list = Arrays.asList("ddd","bbb","ccc");list.stream().sorted().forEach(System.out::println);}
sorted(Comparator com) 定制排序
自己传入的排序方式进行排序
int compare(T o1, T o2);
该方法是根据放回来判断o1和o2的大小:
- 返回值小于0:o1<o2
- 返回值大于0:o1>o2
返回值等于0:o1=o2
@Testpublic void test08(){ArrayList<UserEntity> userEntities = new ArrayList<>();userEntities.add(new UserEntity("小明",12));userEntities.add(new UserEntity("小红",22));userEntities.add(new UserEntity("小蓝",13));userEntities.add(new UserEntity("小绿",16));userEntities.add(new UserEntity("小紫",21));userEntities.sort(new Comparator<UserEntity>() {@Overridepublic int compare(UserEntity o1, UserEntity o2) {return o1.getAge()- o2.getAge();}});userEntities.forEach((u)-> System.out.println(u.toString()));}
查找与匹配(终止操作)
- allMatch:所有都匹配则为true
- anyMatch:任意一个匹配则为true
- noneMatch:都没有匹配则为true
- findFirst:查找第一个元素
- findAny:查找任意一个元素
- count:返回元素数量
- max:范围自定义判断中最大的
min:范围自定义判断中最小的
@Testpublic void test11(){Integer[] integers = new Integer[]{1,2,3,4,5,6,7,8,9,10,10,8,9};// 所有元素都匹配则为trueboolean b = Arrays.stream(integers).allMatch(x -> x % 2 == 0);System.out.println(b);// 任意一个匹配则为trueboolean b1 = Arrays.stream(integers).anyMatch(x -> x % 2 == 0);System.out.println(b1);// 都没有匹配则为trueboolean b2 = Arrays.stream(integers).noneMatch(x -> x % 2 == 0);System.out.println(b2);Optional<Integer> first = Arrays.stream(integers).findFirst();System.out.println(first.get());Optional<Integer> any = Arrays.stream(integers).findAny();System.out.println(any.get());long count = Arrays.stream(integers).count();System.out.println(count);Optional<Integer> max = Arrays.stream(integers).max((x, y) -> x.compareTo(y));System.out.println(max.get());Optional<Integer> min = Arrays.stream(integers).min((x, y) -> x.compareTo(y));System.out.println(min.get());}
归约与收集
reduce 归约
可以将流中元素反复结合起来,得到一个值
T reduce(T identity, BinaryOperator
accumulator); Optional
reduce(BinaryOperator accumulator);** @Testpublic void test12(){List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);Integer reduce = list.stream().reduce(0, (x, y) -> x + y);System.out.println(reduce);Optional<Integer> reduce1 = list.stream().reduce((x, y) -> x + y);System.out.println(reduce1.get());}
第一个参数为起始值
**0**,然后将**0**赋值个x,在将流中每一个元素赋值给y,在执行方法体。最后算出累加和。而对于没有起始值的方法,它累加和是有可能为空,所以返回的是一个Optional类。collect 收集
将流转换为其它形式。接受一个Collector接口的实现类,用于给Stream中元素做魏总的方法。
Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但Collectors实现类提供了很多静态方法,可以方法的创建常见收集器示例,具体方方法与示例如下表:
将Peson list中的姓名提取出来放入一个新的list中。
@Testpublic void test13(){List<Person> peoples = Arrays.asList(new Person(1,"张三",29),new Person(2,"李四",20),new Person(3,"王五",25),new Person(4,"小王",23),new Person(5,"小陈",16));List<String> collect = peoples.stream().map(p -> p.getName()).collect(Collectors.toList());collect.forEach(System.out::println);}
将List转为set,注意,set内部依赖于map去重,map依赖equals 和 hashCode 方法进行去重
@Testpublic void test14(){List<Person> peoples = Arrays.asList(new Person(1,"张三",29),new Person(2,"李四",20),new Person(3,"王五",25),new Person(4,"小王",23),new Person(5,"小陈",16));Set<Person> collect = peoples.stream().collect(Collectors.toSet());collect.forEach(System.out::println);}
如果People类中没有重写equals 和 hashCode 这两个方法,则去不了所谓的重复。
放入指定集合中
@Testpublic void test15(){List<Person> peoples = Arrays.asList(new Person(1,"张三",29),new Person(2,"李四",20),new Person(3,"王五",25),new Person(4,"小王",23),new Person(5,"小陈",16));Set<String> collect = peoples.stream().map(x->x.getName()).collect(Collectors.toCollection(HashSet::new));collect.forEach(System.out::println);}
分组,根据id分组,也可以进行多级分组,groupingBy中存在两个参数的方法
@Testpublic void test16(){List<Person> peoples = Arrays.asList(new Person(1,"张三",29),new Person(1,"李四",20),new Person(2,"王五",25),new Person(2,"小王",23),new Person(3,"小陈",16));Map<Integer, List<Person>> collect = peoples.stream().collect(Collectors.groupingBy(p -> p.getId()));System.out.println(collect);}
分区
@Testpublic void test17(){List<Person> peoples = Arrays.asList(new Person(1,"张三",29),new Person(1,"李四",20),new Person(2,"王五",25),new Person(2,"小王",23),new Person(3,"小陈",16));Map<Boolean, List<Person>> collect = peoples.stream().collect(Collectors.partitioningBy(x -> x.getAge() > 25));}
