Java Stream 流式编程

哈根达斯
2021-09-01 / 0 评论 / 80 阅读 / 正在检测是否收录...

前言

在很多语言中都会有 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);

实例讲解

如下代码实现的功能为:

  1. 将人员数组按照年龄设置额外字段
  2. 将数组中人员按照城市分组
  3. 组内结果如有多人取身高最高的一员
// 需要关于身高的 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

评论 (0)

取消