Use JAVA 8's Stream to process data

foreword

What is Java's Stream stream?

It is a new way of dealing with collections in java. It allows us to process the elements in the collection, convert or filter them, and return the result.
We can easily use Stream to process the collection.
在使用stream流的同时,很经常的会和lambda表达式配合使用

Three-step operation of stream flow

When we first came into contact with stream, we definitely need to know how to use it, which can be roughly divided into three steps

Create Stream

A Stream can be created using the collection's stream() method or the Arrays.stream() method

Intermediate operation

Intermediate operations can be performed on the Stream to filter, transform, or perform other operations. Common intermediate operations include filter(), map(), flatMap(), distinct(), sorted(), and peek(), etc., which will be explained in detail later

terminal operation

Executing a terminal operation triggers the processing of the Stream, returns a result or occurs a side effect. Common terminal operations include forEach(), count(), reduce(), collect(), anyMatch(), allMatch(), and noneMatch(), etc., which will be described in detail later

common intermediate operations

filter(Predicate predicate)filter

This intermediate operation filters the elements in the Stream, leaving only eligible elements, and returns a new Stream composed of eligible elements

map(Function Mapper)convert

This intermediate operation performs conversion operations on the elements in the Stream, performs corresponding processing on each element, and returns a new Stream.

flatMap(Function mapper)Convert to Stream

This intermediate operation converts each element in the Stream into a Stream, and then merges these converted Streams into a new Stream and returns

distinct()Deduplication

This intermediate operation removes duplicate elements in the Stream and returns a new Stream without duplicate elements

sorted()to sort

This intermediate operation sorts the elements in the Stream and returns a new sorted Stream.

peek(Consumer action)consumption operation

This intermediate operation performs a consumption operation on each element in the Stream, returning a still original Stream.

limit(long maxSize)intercept data

This intermediate operation intercepts the first maxSize elements in the Stream and returns a new Stream.

skip(long n)skip element

This intermediate operation skips the first n elements in the Stream and returns a new Stream.


需要注意的是,这些Stream中间操作可以任意串联,形成一条Stream流水线,每一个中间操作都会返回一个新的Stream,而不会改变原Stream中的元素。在使用Stream时,需要注意Stream流的特殊性质:它们只能被“消费”一次。如果需要对Stream中的数据进行多次操作,需要重新生成一个新的Stream对象。


Common Terminal Operations

forEach()iterative operation

This terminal operation iterates over each element in the Stream and invokes the specified operation to process each element

count()return quantity

The terminal operation converts the parallel Stream to a normal Stream, which can be processed by a single thread.

reduce()accumulate

This terminal operation accumulates the elements in the Stream through the specified operation and returns the calculation result.

collect()Turn collection or array

The terminal operation converts the elements in the Stream into a collection or a value, and returns the collection or value.

max()take the largest element

This terminal operation takes the largest element in the Stream.

min()take the smallest element

This terminal operation takes the smallest element in Stream.

allMatch()Whether to meet the conditions

This terminal operation checks whether all elements in the Stream satisfy the specified condition.

anyMatch()either meet the conditions

This terminal operation checks whether any element in the Stream satisfies the specified condition.

noneMatch()None meet the conditions

This terminal operation checks if none of the elements in the Stream satisfy the specified condition.


Special terminal operations: In addition to the above terminal operations, there are these special terminal operations: findFirst(), findAny(),toArray()

Intermediate operation example

Here will introduce how to use intermediate operations and demonstrate with examples

filter(Predicate predicate)

example:

// 转换集合
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Ella");
// 过滤拿取长度大于4的数据
List<String> longNames = names.stream()
                        .filter(name -> name.length() > 4)
                        .collect(Collectors.toList());
// 打印结果
System.out.println(longNames);

result:

[Alice, Charlie, David]

map(Function Mapper)

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
//将 Stream 中原有的整数元素转换为它们的平方数,最终将转换后的元素收集到一个新的 List 中。
List<Integer> squares = numbers.stream()
                                .map(num -> num * num)
                                .collect(Collectors.toList());
打印结果
System.out.println(squares);

result:

[1, 4, 9, 16, 25, 36, 49, 64, 81]

flatMap(Function mapper)

example:

// 转换嵌套了多个 List 的 List 
List<List<String>> nestedList = Arrays.asList(
                                    Arrays.asList("apple", "banana", "orange"),
                                    Arrays.asList("cat", "dog", "bird"),
                                    Arrays.asList("Java", "Kotlin", "Python")
                                );
// 使用 flatMap() 方法将嵌套了多个 List 的 List 转换为一个扁平化的 Stream,
//然后使用 collect() 方法将转换后的所有元素收集到一个新的 List 中。
List<String> flatList = nestedList.stream()
                                    .flatMap(list -> list.stream())
                                    .collect(Collectors.toList());
// 打印结果
System.out.println(flatList);

result:

[apple, banana, orange, cat, dog, bird, Java, Kotlin, Python]

distinct()

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 4, 5, 5, 6, 3, 7, 8, 9, 9);
// 使用 distinct() 方法将 Stream 中的重复元素去除,然后使用 collect() 方法将所有的不同元素收集到一个新的 List 中
List<Integer> uniqueNumbers = numbers.stream()
                                      .distinct()
                                      .collect(Collectors.toList());
// 打印结果     
System.out.println(uniqueNumbers);

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

sorted()

example:

// 转换集合
List<String> names = Arrays.asList("Alice", "bob", "Charlie", "david", "Ella");
// 按照字母顺序排序
List<String> sortedNames = names.stream()
                                .sorted()
                                .collect(Collectors.toList());
// 打印结果
System.out.println(sortedNames);

result:

[Alice, Charlie, Ella, bob, david]

若想按照自定义规则进行排序,可以在 sorted() 方法中传入一个自定义的 Comparator。以下为带Comparator的例子

example:

// 转换集合
List<String> names = Arrays.asList("Alice", "bob", "Charlie", "david", "Ella");
// 定义自定义Comparator
Comparator<String> lengthComparator = (str1, str2) -> Integer.compare(str1.length(), str2.length());
// 按照字母长度排序
List<String> sortedNames = names.stream()
                                .sorted(lengthComparator)
                                .collect(Collectors.toList());
// 打印结果
System.out.println(sortedNames);

result:

[bob, Ella, Alice, david, Charlie]

peek()

example:

// 转换集合
List<String> names = Arrays.asList("Alice", "bob", "Charlie", "david", "Ella");
// 使用 peek() 方法在 Stream 中打印每个元素的原始名称和名称转换为大写后的名称。
//在执行完 peek() 方法后,Stream 仍然保持不变,我们可以继续对 Stream 进行其他操作,
//例如使用 map() 方法将名称转换为大写字母,并将所有元素收集到一个新的 List 对象中
List<String> resultNames = names.stream()
                                .peek(name -> System.out.println("原始值: " + name))
                                .map(name -> name.toUpperCase())
                                .peek(name -> System.out.println("处理值: " + name))
                                .collect(Collectors.toList());

ps: 该stream执行完,names 和resultNames 的值是一样的

result:

原始值: Alice
处理值: ALICE
原始值: bob
处理值: BOB
原始值: Charlie
处理值: CHARLIE
原始值: david
处理值: DAVID
原始值: Ella
处理值: ELLA

limit(long maxSize)

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 获取前三条数据
List<Integer> limitedNumbers = numbers.stream()
                                      .limit(3)
                                      .collect(Collectors.toList());
// 打印结果
System.out.println(limitedNumbers);

result:

[1, 2, 3]

skip(long n)

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 跳过前2个元素
List<Integer> resultNumbers = numbers.stream()
                                     .skip(2)
                                     .collect(Collectors.toList());
// 打印结果
System.out.println(resultNumbers);

result:

[3, 4, 5]

Example of terminal operation

Here I will introduce how to use the terminal operation and demonstrate it with examples. Note that since it is a terminal operation,使用该操作处理完数据之后stream无法再使用

forEach()

example:

// 转换集合
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Ella");
// 打印大写字符
names.stream()
     .forEach(name -> System.out.println("Hello, " + name.toUpperCase() + "!"));

result:

Hello, ALICE!
Hello, BOB!
Hello, CHARLIE!
Hello, DAVID!
Hello, ELLA!

count()

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 计算长度
long count = numbers.stream()
                    .count();
// 打印结果
System.out.println("长度为: " + count);

result:

长度为:5

reduce()

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 求和,需要两个参数,初始值和 BinaryOperator 对象
// 本实例用的sum()方法
int sum = numbers.stream()
                 .reduce(0, Integer::sum);
System.out.println("求和: " + sum);

result:

求和:15

max()

example:

// 转换集合
List<Integer> numbers = Arrays.asList(10, 20, 30, 40, 50);
// 求最大值
Optional<Integer> max = numbers.stream()
                               .max(Integer::compareTo);
// 判空
if (max.isPresent()) {
    
    
    System.out.println("最大值: " + max.get());
} else {
    
    
    System.out.println("空值");
}

result:

最大值:50

min()

example:

// 转换集合
List<Integer> numbers = Arrays.asList(10, 20, 30, 40, 50);
// 求最大值
Optional<Integer> min= numbers.stream()
                               .min(Integer::compareTo);
// 判空
if (max.isPresent()) {
    
    
    System.out.println("最小值: " + min.get());
} else {
    
    
    System.out.println("空值");
}

result:

最小值:10

allMatch()

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 判断所有元素是否都大于0
boolean allGreaterThanZero = numbers.stream()
                                    .allMatch(n -> n > 0);
System.out.println("所有元素是否都大于0: " + allGreaterThanZero);

result:

所有元素是否都大于0:true

anyMatch()

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 判断是否有任一元素为偶数
boolean hasEvenNumber = numbers.stream()
                               .anyMatch(n -> n % 2 == 0);
// 打印结果
System.out.println("是否有任一元素为偶数: " + hasEvenNumber);

result:

是否有任一元素为偶数:true

noneMatch()

example:

// 转换集合
List<String> fruits = Arrays.asList("apple", "banana", "pear", "orange");
// 判断元素都不包含字母a
boolean noneContainsA = fruits.stream()
                             .noneMatch(fruit -> fruit.contains("a"));
System.out.println("元素都不包含字母a: " + noneContainsA);

result:

元素都不包含字母a:false

collect()

The operation of the terminal is to convert the processed data into collections, the following are different collection processing examples

Turn to List example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 转List
List<Integer> evenNumbers = numbers.stream()
                                   .filter(n -> n % 2 == 0)
                                   .collect(Collectors.toList());
// 打印结果
System.out.println(evenNumbers);

result:

[2, 4]

Transfer Set example:

// 转换集合
List<String> fruits = Arrays.asList("apple", "banana", "pear", "banana", "orange");
// 转Set
Set<String> fruitSet = fruits.stream()
                             .collect(Collectors.toSet());
// 打印结果 
System.out.println(fruitSet);

result:

[banana, apple, pear, orange]

Example of turning to Map:

// 转换集合
List<Person> persons = Arrays.asList(
        new Person("Alice", 25),
        new Person("Bob", 30),
        new Person("Charlie", 35),
        new Person("David", 40)
);
// 转Map
Map<String, Integer> nameToAgeMap = persons.stream()
                                           .collect(Collectors.toMap(Person::getName, Person::getAge));
System.out.println(nameToAgeMap);

result:

{
    
    Alice=25, Bob=30, Charlie=35, David=40}

findFirst()

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 查找第一个偶数
Optional<Integer> firstEvenNumber = numbers.stream()
                                            .filter(n -> n % 2 == 0)
                                            .findFirst();
// 打印结果
if (firstEvenNumber.isPresent()) {
    
    
    System.out.println("第一个偶数为: " + firstEvenNumber.get());
} else {
    
    
    System.out.println("空值");
}

result:

第一个偶数为:2

findAny()

example:

// 转换集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 查找任一一个偶数
Optional<Integer> anyEvenNumber = numbers.stream()
                                          .filter(n -> n % 2 == 0)
                                          .findAny();
// 打印结果
if (anyEvenNumber.isPresent()) {
    
    
    System.out.println("任一偶数: " + anyEvenNumber.get());
} else {
    
    
    System.out.println("空值");
}

result:

任一偶数:2

toArray()

example:

// 转换集合
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 转Arrary
String[] namesArray = names.stream()
                           .toArray(String[]::new);
// 打印结果
System.out.println(Arrays.toString(namesArray));

result:

[Alice, Bob, Charlie]

Common Stream processing

The following examples are some of the more commonly used Stream processing examples in my work process, which can be used for your reference and will be updated from time to time

List< Object > Get one of the fields as a List and remove the duplicates

example:

// 转换集合
List<Person> persons = Arrays.asList(
        new Person("Alice", 25),
        new Person("Bob", 30),
        new Person("Charlie", 35),
        new Person("David", 40)
);
// 获取名称
List<String> names = persons.stream()
                            .map(Person::getName)
                            .distinct()
                            .collect(Collectors.toList());
// 打印结果
System.out.println(names);

result:

[Alice, Bob, Charlie, David]

List<Object> grouped by one of its fields

example:

// 转换集合
List<Person> persons = Arrays.asList(
        new Person("Alice", 25),
        new Person("Bob", 30),
        new Person("Charlie", 35),
        new Person("David", 40),
        new Person("Alice", 45)
);
// 根据名称分组
Map<String, List<Person>> personsByName = persons.stream()
                                                 .collect(Collectors.groupingBy(Person::getName));

// 打印结果
System.out.println(personsByName);

result:

{
    
    
Alice=[Person{
    
    name='Alice', age=25}, Person{
    
    name='Alice', age=45}],
 Bob=[Person{
    
    name='Bob', age=30}],
 Charlie=[Person{
    
    name='Charlie', age=35}],
 David=[Person{
    
    name='David', age=40}]
 }

List<Object> sorted according to one of the fields

example:

// 转换集合
List<Person> persons = Arrays.asList(
        new Person("Alice", 25),
        new Person("Bob", 30),
        new Person("Charlie", 35),
        new Person("David", 40),
        new Person("Alice", 45)
);
// 根据年龄排序
List<Person> sortedPersons = persons.stream()
                                    .sorted(Comparator.comparing(Person::getAge))
                                    .collect(Collectors.toList());
// 打印结果
System.out.println(sortedPersons);

result:

[Person{
    
    name='Alice', age=25}, Person{
    
    name='Bob', age=30}, Person{
    
    name='Charlie', age=35}, Person{
    
    name='David', age=40}, Person{
    
    name='Alice', age=45}]

List and List get a piece of data with exactly the same field attribute in the two collections

将两个 List 转换为 Stream,使用 flatMap 将两个 Stream 合并。

使用 filter 方法过滤其中一个字段属性一模一样的数据。可以使用 equals 方法进行比较,或者使用自定义的比较器。

如果存在匹配的数据,使用 findFirst 方法获取第一个匹配的元素。

example:

Optional<Object1> result = list1.stream()
        .flatMap(o1 -> list2.stream()
                .filter(o2 -> o2.getField().equals(o1.getField()))
                .map(o2 -> o1))
        .findFirst();

Among them, getField() is a method used to obtain a property in the object. Object1 and Object2
respectively represent the types of the two classes, which need to be replaced with your own defined class name and property name. Use the Optional type for the return value because there may be cases where there is no match.

epilogue

The above is the usage of stream in JAVA 8

Guess you like

Origin blog.csdn.net/xc9711/article/details/131332028