前言
在很多语言中都会有 map、reduce、filter 等高阶函数对应的流式编程。那么对应 Java 中的功能就是 Stream 操作。
// 生成 1357 并打印
Arrays.stream(new int[] {1, 3, 5, 7}).forEach(System.out::println);
复制代码
所以今天就整理一下关于 Java Stream 流式编程。
关于 Stream
- Stream 是 Java8 添加的一个新的抽象称为流,可以让你以一种声明的方式处理数据。
- Stream 可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
- Stream 流的操作是以管道的方式串起来的。管道以数据源开始,包含若干个中间操作,最终以终点操作结束。
简单使用
下面介绍一下在 Java 中简单的使用:
Map Filter Reduce
List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
// 求和
// Integer sumResult = list.stream().reduce(0, (a, b) -> a + b);
Integer sumResult = list.stream().reduce(0, Integer::sum);
// 45
System.out.println(sumResult);
// 遍历数组
list.forEach(System.out::print);
// 123456789
System.out.println();
// 返回数组元素的平方
List<Integer> numbersList = list.stream().map(i -> i * i).collect(Collectors.toList());
// [1, 4, 9, 16, 25, 36, 49, 64, 81]
System.out.println(numbersList);
List<Integer> evenNumbersList = list.stream().filter(i -> i % 2 == 0).collect(Collectors.toList());
// 筛选出数组中的偶数 [2, 4, 6, 8]
System.out.println(evenNumbersList);
// 筛选出数组中的奇数并返回元素的平方
List<Integer> numbers = list.stream().filter(i -> i % 2 != 0).map(i -> i * i).collect(Collectors.toList());
System.out.println(numbers);
Collector
一般用于 stream 操作的结束,用于对结果集做返回值的定义或高级操作。常见操作用于返回特定的集合:
Collectors.toList()
Collectors.toMap()
Collectors.toSet()
Collectors.toCollection()
Collectors.toConcurrentMap()
下面列举常见 demo :
List<String> language = List.of("Java", "Python", "Rust", "Go", "C++", "C", "C#", "JavaScript");
// 将数组中元素转化成大写字母并用逗号拼接
String collect1 = language.stream().collect(Collectors.collectingAndThen(Collectors.joining(","), String::toUpperCase));
// JAVA,PYTHON,RUST,GO,C++,C,C#,JAVASCRIPT
System.out.println(collect1);
// 实现按数组元素进行分组
Map<Integer, List<String>> collect2 = language.stream().collect(Collectors.groupingBy(String::length));
// {1=[C], 2=[Go, C#], 3=[C++], 4=[Java, Rust], 6=[Python], 10=[JavaScript]}
System.out.println(collect2);
// 转换成字符串长度与字符串的 hash map 有冲突后者覆盖前者
Set<String> collect3 = language.stream().collect(Collectors.toCollection(HashSet::new));
// language.stream().collect(Collectors.toSet());
// [C#, Java, C++, Rust, C, JavaScript, Go, Python]
System.out.println(collect3);
// 转换成字符串长度与字符串的 hash map 有冲突后者覆盖前者
Map<Integer, String> collect4 = language.stream().collect(Collectors.toMap(String::length, String::new,(existing, replacement) -> existing));
// {1=C, 2=Go, 3=C++, 4=Java, 6=Python, 10=JavaScript}
System.out.println(collect4);
进阶使用
在简单使用中都是比较常见且统一理解的例子。下面看一下一些比较复杂的例子。
数据准备
Person 类用到了 Lombok 的 Builder、Data 注解。
@Builder(toBuilder = true)
@Data
class Person {
private Integer height;
private Integer age;
private String name;
private String city;
}
Person p1 = new Person.PersonBuilder().name("bob").height(150).city("shanghai").age(15).build();
Person p2 = new Person.PersonBuilder().name("andy").height(160).city("beijing").age(18).build();
Person p3 = new Person.PersonBuilder().name("tom").height(170).city("xian").age(19).build();
Person p4 = new Person.PersonBuilder().name("cat").height(180).city("shanghai").age(25).build();
ArrayList<Person> persons = new ArrayList<>();
persons.add(p1);
persons.add(p2);
persons.add(p3);
persons.add(p4);
实例讲解
如下代码实现的功能为:
- 将人员数组按照年龄设置额外字段
- 将数组中人员按照城市分组
- 组内结果如有多人取身高最高的一员
// 需要关于身高的 Comparator
Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
Map<String, Person> collect = persons.stream().peek(item -> {
String temp = item.getAge() >= 18 ? "成年" : "未成年";
item.setExtra(temp);
}).collect(
Collectors.groupingBy(
Person::getCity,
Collectors.reducing(p1, BinaryOperator.maxBy(byHeight))
)
);
// {xian=Person(height=170, age=19, name=tom, city=xian, extra=成年), shanghai=Person(height=180, age=25, name=cat, city=shanghai, extra=成年), beijing=Person(height=160, age=18, name=andy, city=beijing, extra=成年)}
System.out.println(collect);
评论 (0)