Commonly used streams for collection processing


Stream streams are often used, but when encountering some stream operations, you may not know which one to use. Here is a summary to facilitate your own or readers’ search.

1. Introduction to Stream API

The Stream API is an important feature introduced in Java 8, which provides a new way of processing collection data. Stream can be regarded as an advanced iterator, which allows various operations on collections in a declarative manner, such as filtering, mapping, sorting, reduction, etc. It simplifies code for collection processing and has performance benefits when working with large data sets.
Personal understanding: A stream is like a continuous assembly line or pipeline. Raw materials enter the production line from one end, and after a series of processing and processing, the final product is output from the other end. In this process, each worker (method) is responsible for its own task and passes the results to the next worker (method), forming a continuous chain of operations. The final result will not be generated until the termination method is encountered.

2. Commonly used Stream methods for List collections

1. stream(): returns a sequential stream (Stream). parallelStream(): Returns a parallel stream (Stream).

Parallel processing: The Stream API provides parallel processing capabilities and can use multi-threading to accelerate the processing of large data sets. By calling the parallelStream() method, the stream can be converted into a parallel stream so that operations can be performed in parallel.

List<String> list = Arrays.asList("apple", "banana", "cat");
Stream<String> stream = list.stream();
Stream<String> parallelStream = list.parallelStream();

2. filter (Predicate predicate): Filter elements and retain elements that meet the conditions.The input is a Predicate functional interface, returning true: retain, false: discard

List<String> list = Arrays.asList("apple", "banana", "cat");
Stream<String> filteredStream = list.stream().filter(s -> s.startsWith("a"));

3. distinct(): Remove duplicate elements.

List<String> list = Arrays.asList("apple", "banana", "apple");
Stream<String> distinctStream = list.stream().distinct();

4. sorted(): Sort elements, using natural order by default.

List<Integer> list = Arrays.asList(3, 1, 2);
Stream<Integer> sortedStream = list.stream().sorted();

4.1 You can also customize the comparator, that is, you need to fill in a comparator "sorted(Comparator<? super T> comparator)" in the parameter. For example:

//字符串忽略大小写并排序
List<String> names = Arrays.asList("John", "Alice", "Bob", "Charlie");
List<String> sortedNames = names.stream().sorted((a, b) -> a.compareToIgnoreCase(b)).collect(Collectors.toList());

//对引用类型排序,通过其中的一个属性排序
class Person {
    
    
    private String name;
    private int age;

    // 省略构造函数和其他方法

    // Getter和Setter方法

    // ...
}
List<Person> persons = Arrays.asList(
        new Person("Alice", 25),
        new Person("Bob", 30),
        new Person("Charlie", 20)
);

List<Person> sortedPersons = persons.stream()
        .sorted(Comparator.comparingInt(Person::getAge))
        .collect(Collectors.toList());

5. limit(long maxSize): Limit the number of elements in the stream.

List<String> list = Arrays.asList("apple", "banana", "cat");
Stream<String> limitedStream = list.stream().limit(2);

6. forEach(Consumer action): Perform the given operation on each element. Just traverse

List<String> list = Arrays.asList("apple", "banana", "cat");
list.stream().forEach(System.out::println);

7. map(Function<T, R> mapper): Map the elements to get a new stream. This is not converted to a map. This method accepts a Function<T, R> function interface as a parameter. This function accepts an element of input type T , and returns a result of output type R.

List<String> list = Arrays.asList("apple", "banana", "cat");
Stream<Integer> lengthStream = list.stream().map(String::length);

7.1 The map() method allows us to perform customized conversion operations on each element in the stream and generate a new stream. By passing the appropriate Function function interface implementation, we can implement various conversion operations, such asType conversion, attribute extraction, calculation conversionwait. For example:

class Person {
    
    
    private String name;
    // ...
}

List<Person> persons = Arrays.asList(
        new Person("Alice"),
        new Person("Bob"),
        new Person("Charlie")
);
//提取name,生成一个新的List<String>
List<String> names = persons.stream()
        .map(Person::getName)
        .collect(Collectors.toList());
//将一个person转换为一个student
 List<Student> students = persons.stream()
                .map(person -> {
    
    
                    String name = person.getName();
                    int age = person.getAge();
                    String school = getSchoolBasedOnAge(age); // 自定义的逻辑方法
                    return new Student(name, age, school);
                })
                .collect(Collectors.toList());
 private static String getSchoolBasedOnAge(int age) {
    
    
        if (age < 18) {
    
    
            return "High School";
        } else {
    
    
            return "University";
        }
    }

8. collect(Collector<? super T, A, R> collector): Collect elements in the stream into a collection or other variable result container. The simplest is to return a new List. The above methods are all

List<String> list = Arrays.asList("apple", "banana", "cat");
List<String> collectedList = list.stream().collect(Collectors.toList());

8.1. collect(Collector<? super T, A, R> collector) is a terminal operation method in the Stream API, which is used to collect elements in the stream into a collection or other variable result container. This method accepts a Collector object as a parameter to define the rules for collecting elements. Collector objects can be created through the static methods of the Collectors factory class, or you can customize the implementation.

The generic parameters in Collector<? super T, A, R> represent the following:
T: Represents the element type in the stream. ? super T represents any supertype of type T, which allows the Collector to handle elements of type T and its subtypes.
A: Represents the type of variable result container (accumulator) used to accumulate stream elements. During the collection process, the Collector accumulates elements into a container of type A one by one.
R: Indicates the final result type of the collection operation. Collector finally converts the accumulated results to type R and returns the results.
In Collector<? super T, A, R>, ? super T allows processing of elements of type T and its subtypes. This design makes Collector more versatile and can handle different types of elements, not just T types. Type A of the accumulation result container, and type R of the final result of the collection operation

For example: commonly used list to map

public static void main(String[] args) {
    
    
        List<Person> persons = Arrays.asList(
                new Person("Alice", 25),
                new Person("Bob", 30),
                new Person("Charlie", 35)
        );

        Map<String, Integer> nameToAgeMap = persons.stream()
                .collect(Collectors.toMap(Person::getName, Person::getAge));

        System.out.println(nameToAgeMap);
    }

Convert to < id:entity >

//在toMap()方法中,我们传递了三个参数:Person::getName用于提取姓名作为键,Function.identity()
//用于将Person对象本身作为值,以及一个合并函数 (existingValue, newValue) -> newValue 来处理
//重复的键。在合并函数中,我们选择使用新值作为合并后的值。
public static void main(String[] args) {
    
    
        List<Person> persons = Arrays.asList(
                new Person("Alice", 25),
                new Person("Bob", 30),
                new Person("Alice", 35)
        );

        Map<String, Person> nameToPersonMap = persons.stream()
                .collect(Collectors.toMap(Person::getName, Function.identity(), (existingValue, newValue) -> newValue));

        System.out.println(nameToPersonMap);
    }

8.2 Use the collect() method to group by age

public static void main(String[] args) {
    
    
        List<Person> persons = Arrays.asList(
                new Person("Alice", 25),
                new Person("Bob", 30),
                new Person("Charlie", 35),
                new Person("Dave", 25)
        );

        Map<Integer, List<Person>> ageGroupMap = persons.stream()
                .collect(Collectors.groupingBy(Person::getAge));

        System.out.println(ageGroupMap);
    }

Multi-level grouping, multi-level grouping based on city and age.

public static void main(String[] args) {
    
    
        List<Person> persons = Arrays.asList(
                new Person("Alice", "New York", 25),
                new Person("Bob", "London", 30),
                new Person("Charlie", "New York", 35),
                new Person("Dave", "London", 25)
        );

        Map<String, Map<String, List<Person>>> cityToAgeGroupMap = persons.stream()
                .collect(Collectors.groupingBy(Person::getCity,
                        Collectors.groupingBy(person -> person.getAge() < 30 ? "Young" : "Old")));

        System.out.println(cityToAgeGroupMap);

A nested Map named resultMap is obtained, in which the outer key is the name, the inner key is the age, and the value is the corresponding Person object.

public static void main(String[] args) {
    
    
        List<Person> persons = Arrays.asList(
                new Person("Alice", 25),
                new Person("Bob", 30),
                new Person("Charlie", 35),
                new Person("Dave", 25)
        );

        Map<String, Map<Integer, Person>> resultMap = persons.stream()
                .collect(Collectors.groupingBy(
                        Person::getName,
                        Collectors.toMap(
                                Person::getAge,
                                person -> person
                        )
                ));

        System.out.println(resultMap);
    }

You can also do these things:

Statistics and summary:
Collectors.counting(): Count the number of elements in the stream.
Collectors.summingInt(toIntFunction): Performs an integer sum of the elements in the stream.
Collectors.averagingInt(toIntFunction): Calculate the average of the elements in the stream.
Collectors.summarizingInt(toIntFunction): Generates summary statistics of elements in the stream, including quantity, sum, average, maximum and minimum values.

String splicing and joining:
Collectors.joining(): Join the elements in the stream into a string according to the specified delimiter.
Collectors.joining(delimiter, prefix, suffix): Join the elements in the stream into a string according to the specified delimiter, prefix and suffix.

9. allMatch(Predicate<? super T> predicate): Check whether all elements in the stream meet the given conditions. Return boolean

List<Integer> list = Arrays.asList(2, 4, 6);
boolean allEven = list.stream().allMatch(n -> n % 2 == 0);

10. skip(long n): Skip the first n elements in the stream. This can be used forList paging
The code is as follows: skip the elements in front of the current page, and then limit the size of each page through limit
Insert image description here
11. reduce (BinaryOperator accumulator): Convection according to the given accumulator function Perform a reduction operation on the elements in .

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = list.stream().reduce(0, (a, b) -> a + b);

Find the oldest Person in the list

List<Person> people = Arrays.asList(
    new Person("John", 25),
    new Person("Alice", 30),
    new Person("Bob", 20)
);
Person oldestPerson = people.stream().reduce((p1, p2) -> p1.getAge() > p2.getAge() ? p1 : p2).orElse(null);

Of course, other aggregation and accumulation operations can also be performed. Specifically, when encountering aggregation or accumulation, you can think of the .reduce method.

12. distinct(): remove duplicate elements.

List<String> list = Arrays.asList("apple", "banana", "apple");
Stream<String> distinctStream = list.stream().distinct();

13. flatMap(Function<? super T, ? extends Stream<? extends R>> mapper): Map each element in the stream and flatten it into a stream. This is also a very useful method

List<List<Integer>> nestedList = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4));
List<Integer> flattenedList = nestedList.stream().flatMap(Collection::stream).collect(Collectors.toList());

13.1. The flatMap() method is very useful when dealing with nested structures and processing mapping relationships between multiple collections or streams. It can expand nested collections or streams into a simpler structure to facilitate subsequent processing and operations.

List<List<List<String>>> nestedList = Arrays.asList(
    Arrays.asList(
        Arrays.asList("apple", "banana"),
        Arrays.asList("cherry", "date")
    ),
    Arrays.asList(
        Arrays.asList("grape", "kiwi"),
        Arrays.asList("lemon", "mango")
    )
);

List<String> flattenedList = nestedList.stream()
    .flatMap(List::stream)
    .flatMap(List::stream)
    .collect(Collectors.toList());

System.out.println(flattenedList); // 输出:[apple, banana, cherry, date, grape, kiwi, lemon, mango]

Suppose you have a Person type where each person can have multiple hobbies. Each hobby can have multiple tags. We can use the flatMap() method to handle this nested reference type structure.

public static void main(String[] args) {
    
    
        List<Person> people = Arrays.asList(
                new Person("John", Arrays.asList("Reading", "Painting")),
                new Person("Alice", Arrays.asList("Music", "Cooking", "Hiking")),
                new Person("Bob", Arrays.asList("Photography"))
        );

        List<String> allHobbies = people.stream()
                .flatMap(person -> person.getHobbies().stream())
                .collect(Collectors.toList());

        System.out.println(allHobbies);
    }

Using the flatMap() method, we stream the hobbies of each person in the people list and flatten them into a single stream. Finally, we collect the streams into a list allHobbies, which contains everyone's hobbies.

More useful ones will be added later.

Guess you like

Origin blog.csdn.net/qq_40454136/article/details/131576878