Java8 Stream 总结
Posted 在奋斗的大道
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java8 Stream 总结相关的知识,希望对你有一定的参考价值。
Java8 Stream 思维导图
目录
2.6.3分组(partitioningBy/groupingBy)
1、Stream 创建
方式一:通过 java.util.Collection.stream() 方法用集合创建流
/**
* 创建方式一:通过 java.util.Collection.stream() 方法用集合创建流
*/
List<String> list = Arrays.asList("a", "b", "c", "d");
// 创建一个顺序流
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
// 创建一个并行流
Stream<String> parallelStream = list.parallelStream();
parallelStream.forEach(System.out::println);
方式二:通过java.util.Arrays.stream(T[] array)方法用数组创建流
int[] array = 1,2,3,4,5,6;
IntStream intStream = Arrays.stream(array);
intStream.forEach(System.out::println);
方式三:通过Stream的静态方法:of()、iterate()、generate()
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
integerStream.forEach(System.out::println);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println);
Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);
stream和parallelStream区分:
1、stream是顺序流,由主线程按顺序对流执行操作。
2、parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,前提是流中的数据处理没有顺序要求。
运行流程图说明:
知识点拓展:
通过parallel()把顺序流转换成并行流。
2、Stream 使用
员工类实体定义:
package com.zzg.entity;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@SuppressWarnings("serial")
public class Person implements Serializable
private String name; // 姓名
private int salary; // 薪资
private int age; // 年龄
private String sex; //性别
private String area; // 地区
2.1遍历/匹配(foreach/find/match)
Stream
支持类似集合的遍历和匹配元素。
/**
* 温馨提示:Stream中的元素是以Optional类型存在
*/
// List<Integer> list = Arrays.asList(1,2,3,4,5);
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
/**
* 遍历输出符合条件的元素
*/
list.stream().filter(x -> x > 6).forEach(System.out::println);
/**
* 输出符合条件的第一个元素
*/
Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
/**
* 输出符合条件的任意元素(适用于并行流)
*/
Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
/**
* 判断是否包含符合特定条件的元素
*/
boolean anyMatch = list.stream().anyMatch(x -> x > 6);
System.out.println("匹配第一个值:" + findFirst.orElse(0));
System.out.println("匹配任意一个值:" + findAny.orElse(0));
System.out.println("是否存在大于6的值:" + anyMatch);
2.2筛选(filter)
筛选,按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
/**
* 案例一:筛选出Integer集合中 大于8的元素,并打印出来
*/
list.stream().filter(x -> x > 8).forEach(System.out::println);
/**
* 案例二:筛选薪资大于8000的员工名称,构建新的集合 温馨提示:map 用于获取指定对象的属性值 collect 用于构建新的集合
*/
List<Person> dataList = init();
List<String> names = dataList.stream().filter(item -> item.getSalary() > 8000).map(item -> item.getName())
.collect(Collectors.toList());
names.stream().forEach(System.out::println);
public static List<Person> init()
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 25, "male", "New York"));
personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
personList.add(new Person("Anni", 8200, 31, "female", "New York"));
personList.add(new Person("Owen", 9500, 35, "male", "New York"));
personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
return personList;
2.3聚合(max/min/count)
对集合、数组的数据进行统计操作。
/**
* 案例三:获取员工集合中姓名字符串最长。
*/
String name = dataList.stream().map(item -> item.getName()).collect(Collectors.toList()).stream()
.max(Comparator.comparing(String::length)).orElse("");
System.out.println("用户名称:" + name);
/**
* 案例四: 获取Integer 最大值
*/
List<Integer> sortList = Arrays.asList(7, 6, 9, 4, 11, 6);
// 自然排序
Optional<Integer> max = sortList.stream().max(Integer::compareTo);
// 自定义排序
Optional<Integer> max2 = sortList.stream().max(new Comparator<Integer>()
@Override
public int compare(Integer o1, Integer o2)
return o1.compareTo(o2);
);
System.out.println("自然排序的最大值:" + max.orElse(0));
System.out.println("自定义排序的最大值:" + max2.orElse(0));
/**
* 案例五: 获取员工集合中工资最高
*/
Optional<Person> salary = dataList.stream().max(Comparator.comparingInt(Person::getSalary));
/**
* 基于lombok 创建模式构建Person 对象并赋值Salary 初始值
*/
System.out.println("员工工资最大值:" + salary.orElse(Person.builder().salary(0).build()).getSalary());
/**
* 案例六:统计Integer集合中大于6的元素的个数
*/
List<Integer> integerList = Arrays.asList(7, 6, 4, 8, 2, 11, 9);
long integerCount = integerList.stream().filter(item -> item >= 6).count();
System.out.println("integer 集合大于6个数:" + integerCount);
public static List<Person> init()
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 25, "male", "New York"));
personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
personList.add(new Person("Anni", 8200, 31, "female", "New York"));
personList.add(new Person("Owen", 9500, 35, "male", "New York"));
personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
return personList;
2.4 映射(map/flatMap)
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map
和flatMap
:
map
:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。flatMap
:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
/**
* 案例七:遍历字符串列表,通过','逗号分隔符构建新列表
*/
List<String> strList = Arrays.asList("A,B,C", "D,E,F");
List<String> newStrList = strList.stream().flatMap(item ->
return Arrays.stream(item.split(","));
).collect(Collectors.toList());
newStrList.stream().forEach(System.out::println);
2.5归约(reduce)
实现对集合求和、求乘积和求最值操作
/**
* 案例八: 统计员工集合工资总数 温馨提示: 通过reduce 实现数值归纳总结,实现对集合求和、求乘积和求最值操作
*/
Integer totalSalary = dataList.stream().map(Person::getSalary).collect(Collectors.toList()).stream()
.reduce(Integer::sum).orElse(0);
System.out.println("员工集合工资总数:" + totalSalary);
/**
* reduce 归纳统计使用匿名函数
*/
Integer totalSalaryTwo = dataList.stream().map(Person::getSalary).collect(Collectors.toList()).stream()
.reduce((x, y) -> x + y).orElse(0);
System.out.println("员工集合工资总数:" + totalSalaryTwo);
/**
* reduce 归纳统计求最大值
*/
Integer totalSalaryThree = dataList.stream().map(Person::getSalary).collect(Collectors.toList()).stream()
.reduce(Integer::max).orElse(0);
System.out.println("员工工资最高:" + totalSalaryThree);
public static List<Person> init()
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 25, "male", "New York"));
personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
personList.add(new Person("Anni", 8200, 31, "female", "New York"));
personList.add(new Person("Owen", 9500, 35, "male", "New York"));
personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
return personList;
2.6收集(collect)
collect
就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。
collect
主要依赖java.util.stream.Collectors
类内置的静态方法。
2.6.1归集(toList/toSet/toMap)
List<String> nameList = dataList.stream().map(Person::getName).collect(Collectors.toList());
nameList.stream().forEach(System.out::println);
Map<String, Person> mapNameObject = dataList.stream().collect(Collectors.toMap(Person::getName, item -> item));
/**
* java8 遍历map
*/
mapNameObject.forEach((k, v) ->
System.out.println("员工姓名:" + k);
System.out.println("toString():" + v.toString());
);
Set<Person> setObject = dataList.stream().collect(Collectors.toSet());
/**
* java8 遍历set
*/
setObject.forEach(item ->
System.out.println("toString():" + item.toString());
);
public static List<Person> init()
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 25, "male", "New York"));
personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
personList.add(new Person("Anni", 8200, 31, "female", "New York"));
personList.add(new Person("Owen", 9500, 35, "male", "New York"));
personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
return personList;
2.6.2统计(count/averaging)
Collectors提供了一系列用于数据统计的静态方法:
- 计数:count
- 平均值:averagingInt、averagingLong、averagingDouble
- 最值:maxBy、minBy
- 求和:summingInt、summingLong、summingDouble
- 统计以上所有:summarizingInt、summarizingLong、summarizingDouble
// 求总数
Long count = dataList.stream().collect(Collectors.counting());
// 求平均工资
Double average = dataList.stream().collect(Collectors.averagingDouble(Person::getSalary));
// 求最高工资
Optional<Integer> max3 = dataList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
// 求工资之和
Integer sum = dataList.stream().collect(Collectors.summingInt(Person::getSalary));
// 一次性统计所有信息
DoubleSummaryStatistics collect = dataList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
System.out.println("员工总数:" + count);
System.out.println("员工工资最高:" + max3);
System.out.println("员工平均工资:" + average);
System.out.println("员工工资总和:" + sum);
System.out.println("员工工资所有统计:" + collect);
public static List<Person> init()
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 25, "male", "New York"));
personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
personList.add(new Person("Anni", 8200, 31, "female", "New York"));
personList.add(new Person("Owen", 9500, 35, "male", "New York"));
personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
return personList;
2.6.3分组(partitioningBy/groupingBy)
- 分区:将
stream
按条件分为两个Map
,比如员工按薪资是否高于8000分为两部分。 - 分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。
// 将员工按薪资是否高于8000分组
Map<Boolean, List<Person>> part = dataList.stream()
.collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
// 将员工按性别分组
Map<String, List<Person>> group = dataList.stream().collect(Collectors.groupingBy(Person::getSex));
// 将员工先按性别分组,再按地区分组
Map<String, Map<String, List<Person>>> group2 = dataList.stream()
.collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
System.out.println("员工按薪资是否大于8000分组情况:" + part);
System.out.println("员工按性别分组情况:" + group);
System.out.println("员工按性别、地区:" + group2);
public static List<Person> init()
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 25, "male", "New York"));
personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
personList.add(new Person("Anni", 8200, 31, "female", "New York"));
personList.add(new Person("Owen", 9500, 35, "male", "New York"));
personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
return personList;
2.6.4接合(joining)
joining
将stream中的元素用特定的连接符连接成一个字符串。
String nameJoin = dataList.stream().map(Person::getName).collect(Collectors.joining(","));
System.out.println("拼接员工姓名:" + nameJoin);
public static List<Person> init()
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 25, "male", "New York"));
personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
personList.add(new Person("Anni", 8200, 31, "female", "New York"));
personList.add(new Person("Owen", 9500, 35, "male", "New York"));
personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
return personList;
2.6.5归约(reducing)
Collectors
类提供的reducing
方法,相比于stream
本身的reduce
方法,增加了对自定义归约的支持。
Integer sum1 = dataList.stream().collect(Collectors.reducing(0, Person::getSalary, (i, j) -> (i + j - 5000)));
System.out.println("员工扣税薪资总和:" + sum1);
public static List<Person> init()
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 25, "male", "New York"));
personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
personList.add(new Person("Anni", 8200, 31, "female", "New York"));
personList.add(new Person("Owen", 9500, 35, "male", "New York"));
personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
return personList;
2.7排序(sorted)
sorted,排序操作。支持两种排序:
-
sorted():自然排序,流中元素需实现 Comparable 接口
-
sorted(Comparator com):Comparator 排序器自定义排序
// 按工资升序排序(自然排序)
List<String> newList = dataList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)
.collect(Collectors.toList());
// 按工资倒序排序
List<String> newList2 = dataList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
.map(Person::getName).collect(Collectors.toList());
// 先按工资再按年龄升序排序
List<String> newList3 = dataList.stream()
.sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
.collect(Collectors.toList());
// 先按工资再按年龄自定义排序(降序)
List<String> newList4 = dataList.stream().sorted((p1, p2) ->
if (p1.getSalary() == p2.getSalary())
return p2.getAge() - p1.getAge();
else
return p2.getSalary() - p1.getSalary();
).map(Person::getName).collect(Collectors.toList());
System.out.println("按工资升序排序:" + newList);
System.out.println("按工资降序排序:" + newList2);
System.out.println("先按工资再按年龄升序排序:" + newList3);
System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
public static List<Person> init()
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 25, "male", "New York"));
personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
personList.add(new Person("Anni", 8200, 31, "female", "New York"));
personList.add(new Person("Owen", 9500, 35, "male", "New York"));
personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
2.8提取/组合
流也可以进行合并、去重、限制、跳过等操作。
String[] arr1 = "a", "b", "c", "d" ;
String[] arr2 = "d", "e", "f", "g" ;
Stream<String> stream1 = Stream.of(arr1);
Stream<String> stream2 = Stream.of(arr2);
// concat:合并两个流 distinct:去重
List<String> newList1 = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
// limit:限制从流中获得前n个数据
List<Integer> collect1 = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
// skip:跳过前n个数据
List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
System.out.println("流合并:" + newList1);
System.out.println("limit:" + collect1);
System.out.println("skip:" + collect2);
以上是关于Java8 Stream 总结的主要内容,如果未能解决你的问题,请参考以下文章
Java8 Stream针对List先分组再求和最大值最小值平均值等