SoFunction
Updated on 2025-04-28

In-depth explanation of Java Stream Stream Use Cases

Preface

The project has been using streams, but it is only a little bit of aware, so I can learn more about it here.
Usually, I will use a few new knowledge of streaming to design Java 8. I will briefly explain these knowledge below, and then learn streams after understanding them or use them more easily.

  • Lambda Expressions
  • Method reference
  • Option
  • stream

1. Lambda

It is recommended to understand functional interfaces first

1.1 Syntax

parameter -> expression body;

1.2 There is no parameter and only one statement or multiple statements

()->("baicaizhi");
()->{
	("baicaizhi1");
	("baicaizhi1");
}

1.3 There is only one statement or multiple statements for a parameter

a->(a);
a->{
	(a);
	(a);
}

1.4 There is only one statement or multiple statements if multiple parameters are

(a,b)->a+b;
(a,b)->{
	int c = a+b;
	(c);
}
  • Optional parameter type declaration: No need to declare the type of the parameter. The compiler can infer the same value from the value of the parameter.
  • Brackets around optional parameters (): If there is only one parameter, the brackets around the parameter can be ignored. But if there are multiple parameters, you must add brackets.
  • Optional braces {}: If a Lambda expression contains only one statement, braces can be omitted. But if there are multiple statements, you must add braces.
  • Optional return keywords: If the Lambda expression has only one statement, the compiler will automatically return the last result of the statement. But if the return statement is explicitly used, you must add curly braces {}, even if there is only one statement.

2. Method citation

Use: (used when using static methods or new)

Test::new
Test::getName

Interface name Brief description of function
Optional empty() Build an empty Optional object
Optional of(T value) Build a non-empty Optional object, if it is empty, an error will be reported!
Optional ofNullable(T value) Build an Optional object, allow empty!
T get() Get the value of a generic object. If the value is empty, an error will be reported.
boolean isPresent() Query empty, if not null, true
boolean isEmpty() Query empty, if null, true
ifPresent(Consumer) Pass an interface function pair, and execute this function when the data is not empty
ifPresentOrElse(Consumer, Runnable) There are two parameters, the first one is executed when it is not empty, and the second one is executed when it is empty. All are interface functions.
Optional filter A filter for an object
Optional map(Function) Conversion method
Optional flatMap(Function) Conversion method, commonly used to convert one layer with multiple layers
Optional or(Supplier) When the object is empty, create a new Optional object based on the interface function
T orElse(T) Get a specified generic object when the object is empty
T orElseThrow() Not empty Returns the object, if empty, NoSuchElementException
T orElseThrow(Supplier) Not empty Returns the object, if empty, specifies an exception

4.1Stream Overview

4.1.1 What is steam

Stream treats the set of elements to be processed as a stream. During the process of the stream, the elements in the stream are operated on by the Stream API, such as: filtering, sorting, aggregation, etc.

4.1.2Stream can be created by arrays and collections, and convection operations are divided into two categories

4.1.2.1 Intermediate Operation

Each time a new stream is returned, there can be multiple.

4.1.2.2 Terminal operation

Terminal operation, each stream can only perform terminal operation once, and the stream cannot be used again after the terminal operation is completed. Terminal operations will produce a new set or value

4.1.3 Features

Instead of storing data, the data is calculated according to specific rules, and the results are generally output.
The data source does not change, and usually a new set or a value will be generated.
It has the feature of delayed execution, and intermediate operations will only be executed when the terminal operation is called.

3.2Stream creation

3.2.1 Create a stream using the () method

  	List<String> list = ("a","b","c");        //Create sequential stream    Stream<String> stream = ();        //Create concurrent stream    Stream<String> stringStream = ();

3.2.2 Use the (T[] array) method to create a stream

  //Array Creation Stream  int[] array = {1,2,3};        
  IntStream stream1 = (array);

3.2.3 Static methods using Stream: of(), iterate(), generate()

 //stream static method creates stream   Stream<Integer> integerStream = (1, 2);        
   Stream<Integer> iterate = (0, x -> x = 3);        
   Stream<Double> limit = (Math::random).limit(3);

3.2.4 Convert sequential streams into concurrent streams

  //Sequential streams are converted into concurrent streams  Optional<String> first = ().parallel().filter(x -> x > 6).findFirst();

4.3 Use

Learn about Optional before using

4.3.1 Data preparation

class Person {
 private String name;  // Name private int salary; // Salary private int age; // age private String sex; //gender private String area;  // area // Construct method public Person(String name, int salary, int age,String sex,String area) {
   = name;
   = salary;
   = age;
   = sex;
   = area;
 }
 // Get and set are omitted, please add it yourself}

4.3.2 Use

4.3.2.1 Traversal/match (foreach/find/match)

Stream also supports traversal and matching elements similar to collections, but the elements in Stream exist in Optional type. Stream traversal and matching is very simple

List<Integer> list = (1,2,3,4,7,6,5,8);
        // traverse the output elements that meet the criteria        ().filter(x->x>6).forEach(::println);
        // Match the first one        Optional<Integer> first = ().filter(x -> x > 6).findFirst();
        // Match any (suitable for parallel streams)        Optional<Integer> any = ().filter(x -> x > 6).findAny();
        // Whether to include elements that meet specific conditions        boolean b = ().anyMatch(x -> x < 6);
        ("Match the first value"+());
        ("Match any value"+());
        ("Whether there is a value greater than 6"+b);

4.3.2.2 Filter

Filtering is an operation to verify elements in the stream according to certain rules and extract elements that meet the conditions into the new stream.

4.3.2.3 Aggregation (max/min/count)

List<Person> personList = new ArrayList<Person>();
        (new Person("Tom", 8900, 11,"male", "New York"));
        (new Person("Jack", 7000, 12,"male", "Washington"));
        (new Person("Lily", 7800, 13,"female", "Washington"));
        (new Person("Anni", 8200, 14,"female", "New York"));
        (new Person("Owen", 9500, 15,"male", "New York"));
        (new Person("Alisa", 7900, 16,"female", "New York"));
        List<Integer> list = (1,2,3,4,7,6,5,8);
        //Filter out elements greater than 7 in the Integer collection and print them out        ().filter(x->x>7).forEach(::println);
        //Screen employees with salary above 8,000 and form a new set.  Form a new collection dependency collect (collect)        List<String> collect = ().filter(value -> () > 8000).map(Person::getName).collect(());
        ("Salary is above 8,000"+collect);

4.3.2.4 Map (map/flatMap)

Mapping, you can map elements of a stream to another stream according to certain mapping rules. It is divided into map and flatMap:

  • map: Receive a function as a parameter, which will be applied to each element and map it into a new element.
  • flatMap: receives a function as a parameter, swaps each value in the stream for another stream, and then connects all streams into one stream.
 List<Person> personList = new ArrayList<Person>();
        (new Person("Tom", 8900, 11,"male", "New York"));
        (new Person("Jack", 7000, 12,"male", "Washington"));
        (new Person("Lily", 7800, 13,"female", "Washington"));
        (new Person("Anni", 8200, 14,"female", "New York"));
        (new Person("Owen", 9500, 15,"male", "New York"));
        (new Person("Alisa", 7900, 16,"female", "New York"));
        List<Integer> list = (1,2,3,4,7,6,5,8);
        List<String> strList = ("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
        //All elements of the English string array are changed to capitalization.  Integer array +3 per element        List<Integer> collect = ().map(x -> x + 3).collect(());
        List<String> collect1 = ().map(String::toUpperCase).collect(());
        // Increase all employees' salaries by 1,000        //Do not change the way the source collection        List<Person> collect2 = ().map(person -> {
            Person person1 = new Person((), 0, (), (), ());
            (() + 1000);
            return person1;
        }).collect(());
        //Change the way of source collection        List<Person> collect3 = ().map(person -> {
            (() + 1000);
            return person;
        }).collect(());
        //Combine two character arrays into a new character array        List<String> collect4 = ().flatMap(s -> {
            String[] s2 = (",");
            return (s2);
        }).collect(());
        ("Each element capitalization:" + collect1);
        ("Each element +3:" + collect);
        //Note that the execution is performed separately during execution, otherwise the effect will not be seen.        ("Before one change:" + (0).getName() + "-->" + (0).getSalary());
        ("After one change:" + (0).getName() + "-->" + (0).getSalary());
        ("Before the second change:" + (0).getName() + "-->" + (0).getSalary());
        ("After the second change:" + (0).getName() + "-->" + (0).getSalary());
        ("Preprocessed collection:" + strList);
        ("Processed collection:" + collect4);

4.3.2.5 Reduce

Reduction, also known as reduction, as the name implies, is to reduce a stream into a value, which can realize the operation of summing the set, finding the product sum and finding the most value of the set.

List<Person> personList = new ArrayList<Person>();
        (new Person("Tom", 8900, 11,"male", "New York"));
        (new Person("Jack", 7000, 12,"male", "Washington"));
        (new Person("Lily", 7800, 13,"female", "Washington"));
        (new Person("Anni", 8200, 14,"female", "New York"));
        (new Person("Owen", 9500, 15,"male", "New York"));
        (new Person("Alisa", 7900, 16,"female", "New York"));
        List<Integer> list = (1,2,3,4,7,6,5,8);
        List<String> strList = ("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
// Find the sum of the elements, the product sum of the Integer set        //Sum method 1        Optional<Integer> reduce = ().reduce((x, y) -> x + y);
        //Sum method 2        Optional<Integer> reduce1 = ().reduce(Integer::sum);
        //Sum method 3        Integer reduce2 = ().reduce(0, Integer::sum);
        // Find the product        Optional<Integer> reduce3 = ().reduce((x, y) -> x * y);
        // Find the maximum value method 1        Optional<Integer> reduce4 = ().reduce((x, y) -> x > y ? x : y);
        // Find the maximum value writing method 2        Integer reduce5 = ().reduce(1, Integer::max);
// Ask for the sum of wages and maximum wages of all employees        //Sum method 1        Optional<Integer> reduce7 = ().map(Person::getSalary).reduce(Integer::sum);
        //Sum method 2        Integer reduce6 = ().reduce(0, (sum, p) -> sum += (),(sum1,sum2)->sum1+sum2);
        //Sum method 3        Integer reduce8 = ().reduce(0, (sum, p) -> sum += (), Integer::sum);
        // How to get the maximum salary 1:        Integer reduce9 = ().reduce(0, (max, p) -> max > () ? max : (),Integer::max);
        // How to get the maximum salary 2:        Integer reduce10 = ().reduce(0, (max, p) -> max > () ? max : (), (max1, max2) -> max1 > max2 ? max1 : max2);
        ("list sum:" + () + "," + () + "," + reduce2);
        ("list finds the source:" + ());
        ("List finds the maximum value:" + () + "," + reduce5);
        ("Sum of wages:" + () + "," + reduce6 + "," + reduce8);
        ("Maximum wage:" + reduce9 + "," + reduce10);

4.3.2.6 Collect

explain

  • collect, collect, can be said to be the most diverse and functional part. Literally, it is to collect a stream, which can eventually be collected into a value or a new set
  • Collect mainly depends on the built-in static methods of the class

4.3.2.6.1 Collection (toList/toSet/toMap)

Because the stream does not store data, after the data in the stream is processed, the data in the stream needs to be re-collected into a new set. toList, toSet and toMap are commonly used, and there are also more complex uses such as toCollection and toConcurrentMap.

 List<Person> personList = new ArrayList<Person>();
        (new Person("Tom", 8900, 11,"male", "New York"));
        (new Person("Jack", 7000, 12,"male", "Washington"));
        (new Person("Lily", 7800, 13,"female", "Washington"));
        (new Person("Anni", 8200, 14,"female", "New York"));
        (new Person("Owen", 9500, 15,"male", "New York"));
        (new Person("Alisa", 7900, 16,"female", "New York"));
        List<Integer> list = (1,2,3,4,7,6,5,8);
        List<String> strList = ("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
        List<Integer> collect = ().filter(x -> x % 2 == 0).collect(());
        Set<Integer> collect1 = ().filter(x -> x % 2 == 0).collect(());
        Map<String, Person> collect2 = ().filter(p -> () > 8000).collect((Person::getName, p -> p));
        ("toList:" + collect);
        ("toSet:" + collect1);
        ("toMap:" + collect2);

4.3.2.6.2 Statistics (count/averaging)

Collectors provides a series of static methods for data statistics

  • Count: count
  • Average: averagingInt, averagingLong, averagingDouble
  • Most value: maxBy, minBy
  • Summing: summingInt, summingLong, summingDouble
  • Statistics all of the above: summarizingInt, summarizingLong, summarizingDouble
List&lt;Person&gt; personList = new ArrayList&lt;Person&gt;();
        (new Person("Tom", 8900, 11,"male", "New York"));
        (new Person("Jack", 7000, 12,"male", "Washington"));
        (new Person("Lily", 7800, 13,"female", "Washington"));
        (new Person("Anni", 8200, 14,"female", "New York"));
        (new Person("Owen", 9500, 15,"male", "New York"));
        (new Person("Alisa", 7900, 16,"female", "New York"));
        List&lt;Integer&gt; list = (1,2,3,4,7,6,5,8);
        List&lt;String&gt; strList = ("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
// Statistics the number of employees, average salary, total salary, maximum salary        // Find the total number        Long collect = ().collect(());
        // Find an average salary        Double collect1 = ().collect((Person::getSalary));
        // Ask for maximum salary        Optional&lt;Integer&gt; collect2 = ().map(Person::getSalary).collect((Integer::compare));
        // Ask for the sum of wages        Integer collect3 = ().collect((Person::getSalary));
        // All information is counted at once        DoubleSummaryStatistics collect4 = ().collect((Person::getSalary));
        ("Total number of employees:" + collect);
        ("Average employee salary:" + collect1);
        ("Sum of employee wages:" + ());
        ("All statistics on employee wages:" + collect3);

4.3.2.6.3 Grouping (partitioningBy/groupingBy)

explain

  • Partition: Divide the stream into two maps according to conditions, such as whether the salary is higher than 8,000.
  • Grouping: Divide the set into multiple maps, such as employees grouping by gender. There are single-level grouping and multi-level grouping.
List&lt;Person&gt; personList = new ArrayList&lt;Person&gt;();
        (new Person("Tom", 8900, 11,"male", "New York"));
        (new Person("Jack", 7000, 12,"male", "Washington"));
        (new Person("Lily", 7800, 13,"female", "Washington"));
        (new Person("Anni", 8200, 14,"female", "New York"));
        (new Person("Owen", 9500, 15,"male", "New York"));
        (new Person("Alisa", 7900, 16,"female", "New York"));
        List&lt;Integer&gt; list = (1,2,3,4,7,6,5,8);
        List&lt;String&gt; strList = ("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
        //Divide employees into two parts according to whether their salary is higher than 8,000; group employees by gender and region        // Group employees by whether their salary is higher than 8,000        Map&lt;Boolean, List&lt;Person&gt;&gt; collect = ().collect((person -&gt; () &gt; 8000));
        // Group employees by gender        Map&lt;String, List&lt;Person&gt;&gt; collect1 = ().collect((Person::getSex));
        // Group employees by gender first, then by region        Map&lt;String, Map&lt;String, List&lt;Person&gt;&gt;&gt; collect2 = ().collect((Person::getSex, (Person::getArea)));
        ("Whether employees are grouped by salary is greater than 8,000:" + collect);
        ("Employees are grouped by gender:" + collect1);
        ("Employee by gender, region:" + collect2);

4.3.2.6.4 Joining

Joining can connect elements in the stream into a string with a specific connector (if not, it is directly connected).

  List&lt;Person&gt; personList = new ArrayList&lt;Person&gt;();
        (new Person("Tom", 8900, 11,"male", "New York"));
        (new Person("Jack", 7000, 12,"male", "Washington"));
        (new Person("Lily", 7800, 13,"female", "Washington"));
        (new Person("Anni", 8200, 14,"female", "New York"));
        (new Person("Owen", 9500, 15,"male", "New York"));
        (new Person("Alisa", 7900, 16,"female", "New York"));
        List&lt;Integer&gt; list = (1,2,3,4,7,6,5,8);
        List&lt;String&gt; strList = ("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
        //String stitching        String collect = ().collect(("-"));
        //The names of all employees        String collect1 = ().map(Person::getName).collect((","));
        ("Name of all employees:" + collect1);
        ("Split string:" + collect);

4.3.2.6.5 Reducing

The reducing method provided by the Collectors class has increased support for custom reduction compared to the reduce method of the stream itself.

 List&lt;Person&gt; personList = new ArrayList&lt;Person&gt;();
        (new Person("Tom", 8900, 11,"male", "New York"));
        (new Person("Jack", 7000, 12,"male", "Washington"));
        (new Person("Lily", 7800, 13,"female", "Washington"));
        (new Person("Anni", 8200, 14,"female", "New York"));
        (new Person("Owen", 9500, 15,"male", "New York"));
        (new Person("Alisa", 7900, 16,"female", "New York"));
        List&lt;Integer&gt; list = (1,2,3,4,7,6,5,8);
        List&lt;String&gt; strList = ("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
        // The sum of salary after each employee is minus the threshold (this example is not rigorous, but I didn't expect a good example)        Integer collect = ().collect((0, Person::getSalary, (i, j) -&gt; i + j - 5000));
        ("Sum of employee tax deduction salary:" + collect);
        // stream's reduce        Optional&lt;Integer&gt; reduce = ().map(Person::getSalary).reduce(Integer::sum);
        ("Sum of employee tax deduction salary:" + ());

4.3.2.7 Sort (sorted)

explain

  • sorted(): natural sorting, elements in the stream need to implement the Comparable interface
  • sorted(Comparator com): Comparator sorter custom sorting
List&lt;Person&gt; personList = new ArrayList&lt;Person&gt;();
        (new Person("Tom", 8900, 11,"male", "New York"));
        (new Person("Jack", 7000, 12,"male", "Washington"));
        (new Person("Lily", 7800, 13,"female", "Washington"));
        (new Person("Anni", 8200, 14,"female", "New York"));
        (new Person("Owen", 9500, 15,"male", "New York"));
        (new Person("Alisa", 7900, 16,"female", "New York"));
        List&lt;Integer&gt; list = (1,2,3,4,7,6,5,8);
        List&lt;String&gt; strList = ("ad,nm", "adm,mt", "p,ot", "xb,angd", "weou,jgsd");
        // Sort by salary increase order        List&lt;String&gt; newList = ().sorted((Person::getSalary)).map(Person::getName)
                .collect(());
        // Sort by salary in reverse order        List&lt;String&gt; newList2 = ().sorted((Person::getSalary).reversed())
                .map(Person::getName).collect(());
        // Order naturally by salary first and then by age (from small to old)        List&lt;String&gt; newList3 = ().sorted((Person::getSalary).reversed())
                .map(Person::getName).collect(());
        // Custom sort by salary first and then by age (from large to small)        List&lt;String&gt; newList4 = ().sorted((p1, p2) -&gt; {
            if (() == ()) {
                return () - ();
            } else {
                return () - ();
            }
        }).map(Person::getName).collect(());
        ("Sorted by salary:" + newList);
        ("Sorted by descending wages:" + newList2);
        ("Sorting naturally by salary first and then by age:" + newList3);
        ("Sorting by salary first and then by age custom descending order:" + newList4);

4.3.2.8 Extraction/combination (distinct, skip, limit)

The stream can also be merged, deduplicated, restricted, skipped and other operations.

String[] arr1 = { "a", "b", "c", "d" };
        String[] arr2 = { "d", "e", "f", "g" };
        Stream&lt;String&gt; stream1 = (arr1);
        Stream&lt;String&gt; stream2 = (arr2);
        // concat: merge two streams distinct: deduplication        List&lt;String&gt; newList = (stream1, stream2).distinct().collect(());
        // limit: limit the first n data obtained from the stream        List&lt;Integer&gt; collect = (1, x -&gt; x + 2).limit(10).collect(());
        // skip: skip the first n data        List&lt;Integer&gt; collect2 = (1, x -&gt; x + 2).skip(1).limit(5).collect(());
        ("Flow merge:" + newList);
        ("limit:" + collect);
        ("skip:" + collect2);

This is the end of this article about the in-depth explanation of Java Stream usage cases. For more related Java Stream content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!