Detailed explanation of stream usage in [Java]-Java8

Posted by MrKaraokeSteve on Fri, 18 Feb 2022 04:50:54 +0100


Stream is an abstract concept of processing sets in Java 8, which can perform complex operations such as finding, filtering and mapping. stay

Operation API

The Stream API provides an efficient and easy-to-use way to process data:

  • It is not a data structure and will not save data;
  • If the data source is not modified, the operation result will be saved to the result object;
  • Inert evaluation: the intermediate processing process is only an operation record and will not be executed immediately; Instead, the actual calculation will not be carried out until the operation is terminated;

Function parameters in the interface can pass Lambd expressions or class functions with the same signature (ClsName::funName style is required at this time). Take groupingBy as an example:

// When the stream element is a string, the following two are equivalent
groupingBy(String::length);
groupingBy(z->{return z.length;});

classification

Operation interfaces can be divided into:

  • Stateless class: processing operations are not affected by previous elements;
  • Stateful class: the operation will not proceed to the next step until all elements are obtained;
  • Non short circuit operation: all elements must be processed to get the final result;
  • Short circuit operation: find the qualified elements to get the final result;
Stream API
Intermediate operationStateless
  • unordered
  • Filter: filter elements. Only those that meet the conditions can be put into the result set
  • map
  • mapToXX(Int/Long/Double)
  • faltMap
  • peek
Stateful
  • distinct: remove duplicate elements according to hashCode and equals of elements
  • sorted: the Comparable interface is used by default, or the Comparator interface can be passed to customize sorting
  • limit: get n elements
  • Skip: skip n elements and combine with limit to realize paging
End operationNon short circuit operation
  • forEach
  • forEachOrdered
  • toArray
  • reduce
  • Collect: collect results, often used in conjunction with Collectors
  • max/min/count
Short circuit operation
  • anyMatch
  • allMatch
  • nonMatch
  • findFirst
  • findAny

Interface description

mapping

  • map: receive the elements in the source and return the elements in the result set;

  • flatMap: similar to map, but when the element is stream, synthesize multiple streams into one and return the result.

List<String> lstAll = Arrays.asList("hello", "world");
// Output two numbers: [h, e, l, l, o] and [w, o, r, l, d]
lstAll.stream()
        .map(s->{return s.split("");})
        .forEach(s->{
            System.out.println(Arrays.toString(s));
        });

// Output each character: h\n e\n...
lstAll.stream()
        .flatMap(s->{return Stream.of(s.split(""));})
        .forEach(System.out::println);

Create stream

Most collections in Java 8 have a stream() interface, which can directly obtain the stream.

Collection.stream

Collections in Java inherit or implement collection Stream () interface:

Arrays.asList(3, 5, 7, 16, 18)
        .stream()
        .filter(z->{return z%2==0;})
        .forEach(System.out::println); // Output even

Arrays.stream

Via arrays Stream() generates an array of streams:

Integer[] array = new Integer[]{3, 4, 8, 16, 19};
long count = Arrays.stream(array)
        .filter(i -> i > 10)
        .count();

Stream.of

Through stream Of() can turn a specified element (single, or multiple) into a stream:

List<Integer> lstAll = Stream.of(1, 3, 5, 7)
        .map(z -> {
            return z * 2;
        })
        .collect(Collectors.toList());

Infinite flow

For infinite flow, you need to limit the length of the final flow through limit.

Stream.generate

Through stream Generate() generates a stream of infinite length (according to the specified rules):

Stream.generate(new Random()::nextInt)
        .limit(5).forEach(System.out::println);
        // Output 5 random numbers

Stream.iterate

Through stream Iterate() can also generate a stream of infinite length, which accepts a parameter and a generating function:

Set<Integer> setAll =  Stream.iterate(1, n->{return n*2;})
        .limit(5)
        .collect(Collectors.toSet());
System.out.println(setAll);

Collectors

Collect elements according to different strategies. For example, the simplest and most common method is to load elements into variable containers such as Map, Set and List.

Merge to set

toXXX

  • toCollection: place all the elements in the stream into a collection (the specific collection type is determined by parameters, such as Collectors.toCollection(LinkedList::new));
  • toList: converted to List and returned;
  • toSet: convert to Set and return;
  • toMap: convert to Map and return;
List<String> lstTest = Arrays.asList("a123", "a456", "b789", "b890");
lstTest.stream()
        .collect(Collectors.toMap(
                e -> e.substring(0, 1), // Key
                e -> e,         // value
                (a, b) -> b,    // Replace the processing method when the key is repeated
                HashMap::new)   // Optional, use map type
        )
        .forEach((k, v) -> System.out.println(k + "=" + v));

mapping

It is equivalent to converting to a map and then to a set: Map (XX) Colcollect(Collectors.toXX())

lstTest.stream().collect(
        Collectors.mapping(
                Integer::valueOf,	// map mode
                Collectors.toList()));

grouping

groupingBy

Generate a Collector with grouping function: the default is to generate HashMap, and the elements in the same group are ArrayList.

List<String> lstTest = Arrays.asList("a123", "a4561", "b789", "b8901");
lstTest.stream().collect(
        Collectors.groupingBy(
                String::length,     // Grouping mode
                HashMap::new,       // Result set Map type
                Collectors.toSet())) // Value (elements in the same group) collection type in Map
        .forEach((k, v) -> System.out.println(k + "=" + v));

partitioningBy

The elements in the flow are divided into two parts according to the results of the given verification rules: those that meet the conditions and those that do not meet the conditions; The key values of Map are true and false.

List<String> lstTest = Arrays.asList("a123", "a4561", "b789", "b8901");
lstTest.stream().collect(
        Collectors.partitioningBy(
                e -> e.length() > 4,    // Classification method
                Collectors.toSet()))    // The Value (elements in the same group) collection type in the Map. The default is List
        .forEach((k, v) -> System.out.println(k + "=" + v));

Calculation and statistics

  • Counting: counting
  • minBy/MaxBy: obtain the Optional result of min / max value;
  • summingInt/summingLong/summingDouble: sum;
  • averagingInt/averagingLong/averagingDouble: average;

reduce

reducing is a collector (operation), which can be used in multi-layer streams, downstream data packets or partitions. count(),max(),min(),sum() are predefined collectors.

Comparator<Person> funHeight = Comparator.comparingInt(Person::getHeight);
Map<City, Optional<Person>> tallestByCity = personList.stream().
                collect(groupingBy(
					Person::getCity, 
					reducing(BinaryOperator.maxBy(funHeight))));

Get the highest in each city

collectingAndThen

After merging the results, the results will be further processed.

lstTest.stream().collect(
    Collectors.collectingAndThen(
            Collectors.groupingBy(String::length),
            z -> z.size()));

After grouping, get the number of groups (there are several groups in total).

Topics: Java stream