What is a Stream

Stream is an interface that has been available since Version 1.8. It provides a way to operate on a collection of data using a Stream, in which elements are immutable and consumed only once. All methods are designed to support chained calls. Using the Stream API is a great way to be productive and write efficient, clean, and concise code.

How do I get a Stream instance

Stream provides static build methods that can create and return Stream instances based on different arguments. Stream instances can also be obtained by calling Stream() or parallelStream() methods using subclass instances of Collection. The difference between the two methods is whether the subsequent execution of other Stream methods is single-threaded or multi-threaded

Stream<String> stringStream = Stream.of("1"."2"."3");
// Infinitely long even stream
Stream<Integer> evenNumStream = Stream.iterate(0, n -> n + 2);

List<String> strList = new ArrayList<>();
strList.add("1");
strList.add("2");
strList.add("3");
Stream<String> strStream = strList.stream();
Stream<String> strParallelStream = strList.parallelStream();
Copy the code

filter

The filter method returns the streams that meet the specified criteria

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
PositiveNumStream -> (1,2,3)
Stream<Integer> positiveNumStream = numStream.filter(num -> num > 0);
Copy the code

map

The map method is used to perform the specified transformation logic for each element in the flow, returning a stream of other types of elements

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
// Convert to a string stream
Stream<String> strStream = numStream.map(String::valueOf);
Copy the code

mapToInt mapToLong mapToDouble

These three methods encapsulate the Map methods and return a Stream officially defined for each type, along with other operation methods appropriate for each type

Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
IntStream intStream = stringStream.mapToInt(Integer::parseInt);
LongStream longStream = stringStream.mapToLong(Long::parseLong);
DoubleStream doubleStream = stringStream.mapToDouble(Double::parseDouble);
Copy the code

flatMap

The flatMap method is used to convert each element in a stream to a stream of other types of elements. For example, if you have a list of orders and each Order contains multiple itemLists, you can use this method to get a summary of all items for all orders, as follows:

Stream<Item> allItemStream = orderList.stream().flatMap(order -> order.itemList.stream());
Copy the code

flatMapToInt flatMapToLong flatMapToDouble

These three methods encapsulate the flatMap method and return streams officially defined separately for each type, using the same method as above

distinct

The distinct method is used to de-duplicate elements in the flow, and the equals method is used to determine whether elements are reused

Stream<Integer> numStream = Stream.of(-2, -1.0.0.1.2.2.3);
// uniqueNumStream -> (-1, -1, 0, 1, 2, 3)
Stream<Integer> uniqueNumStream = numStream.distinct();
Copy the code

sorted

Sorted has one parameterless and one parameterized method for sorting elements in a stream. No arguments method requires the elements in the flow to achieve Comparable interface, or you will quote Java lang. ClassCastException

Stream<Integer> unorderedStream = Stream.of(5.6.32.7.27.4);
OrderedStream -> (4, 5, 6, 7, 27, 32)
Stream<Integer> orderedStream = unorderedStream.sorted();
Copy the code

Sorted (Comparator
Comparator) does not require the element to implement the Comparable interface, and sorts the elements within the stream through the specified element comparator

Stream<String> unorderedStream = Stream.of("1234"."123"."12"."12345"."123456"."1");
OrderedStream -> ("1", "12", "123", "1234", "12345", "123456") orderedStream -> ("1", "12", "123", "12345", "123456")
Stream<String> orderedStream = unorderedStream.sorted(Comparator.comparingInt(String::length));
Copy the code

peek

The peek method can consume each element without adjusting the order or number of elements, and then generate a new Stream. The peek method is mainly used for debugging the intermediate process of Stream execution, as described in the documentation. Since the Stream is usually used in chain calls, multiple streams may be executed. If you want to see the flow of each element between multiple stream operations, you can use this method

Stream.of("one"."two"."three"."four")
     .filter(e -> e.length() > 3)
     .peek(e -> System.out.println("Filtered value: " + e))
     .map(String::toUpperCase)
     .peek(e -> System.out.println("Mapped value: "+ e)) .collect(Collectors.toList()); Filtered value: three Mapped Value: three Mapped Value: four Mapped value: fourCopy the code

limit(long maxSize)

The limit method sequentially intercepts the flow, starting with the first element and reserving up to maxSize elements

Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
SubStringStream -> ("-2", "-1", "0")
Stream<String> subStringStream = stringStream.limit(3);
Copy the code

skip(long n)

The skip method is used to skip the first n elements and return an empty stream if there are less than n elements in the stream

Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
// Skip the first 3 elements, subStringStream -> ("1", "2", "3")
Stream<String> subStringStream = stringStream.skip(3);
Copy the code

forEach

The forEach method works like a regular for loop, except that it supports multithreaded traversal, but not in order

Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
// A single thread traverses the output element
stringStream.forEach(System.out::println);
// Multithreading traverses the output element
stringStream.parallel().forEach(System.out::println);
Copy the code

forEachOrdered

The forEachOrdered method can be used to guarantee sequential traversal, such as if the stream was passed in from outside and parallel was called before that to enable multi-threaded execution

Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
// Iterate over the output elements sequentially
stringStream.forEachOrdered(System.out::println);
// Multithreading through the output element, the following line is the same as the result of the above execution
//stringStream.parallel().forEachOrdered(System.out::println);
Copy the code

toArray

ToArray has one parameterless method and one parameterless method, which is used to convert elements in the stream into an Object array

Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
Object[] objArray = stringStream.toArray();
Copy the code

The parameter method toArray(IntFunction

Generator) supports converting elements in A stream to an array of elements of A specified type
[]>

Stream<String> stringStream = Stream.of("- 2"."1"."0"."1"."2"."3");
String[] strArray = stringStream.toArray(String[]::new);
Copy the code

reduce

Reduce has three overloaded methods that perform progressive operations on internal elements

First Reduce (BinaryOperator

Accumulator)

Accumulator is the specific calculation of the progressive operation

Single thread, etc

boolean foundAny = false;
T result = null;
for (T element : this stream) {
  if(! foundAny) { foundAny =true;
      result = element;
  }
  else
      result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();
Copy the code
Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
// Find the minimum value
Optional<Integer> min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo));
/ / output - 2
System.out.println(min.get());

// Filter out a stream of elements greater than 5
numStream = Stream.of(-2, -1.0.1.2.3).filter(num -> num > 5);
// Find the minimum value
min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo));
/ / output Optional. Empty
System.out.println(min);
Copy the code

Second Reduce (T identity, BinaryOperator

Accumulator)

Identity is the initial value of accumulator for the progressive operation

The single-thread equivalent is as follows

T result = identity;
for (T element : this stream)
  result = accumulator.apply(result, element)
return result;
Copy the code
Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
// Sum =3
int sum = numStream.reduce(0, Integer::sum);
Copy the code

Third reduce(U identity, BiFunction

accumulator, BinaryOperator
combiner)
,?>

Identity and Accumulator as above combiner is used to merge the final result in the case of multi-threaded execution

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
int sum = numStream.parallel().reduce(0, (a, b) -> {
    System.out.println("Accumulator execution." + a + "+" + b);
    return a + b;
}, (a, b) -> {
    System.out.println("Combiner execution." + a + "+" + b);
    return a + b;
});
System.out.println("Final result:"+sum); Accumulator0 + -1An accumulator to perform:0 + 1An accumulator to perform:0 + 0An accumulator to perform:0 + 2An accumulator to perform:0 + -2An accumulator to perform:0 + 3Combiner to perform:2 + 3Combiner execution: -1 + 0Combiner to perform:1 + 5Combiner execution: -2 + -1Combiner execution: -3 + 6Final result:3
Copy the code

collect

Collect has two overloaded methods that convert elements of a stream as a Collection to subclasses of other collections. The internal implementation is similar to the previous progressive operation

Collect (Supplier

Supplier, BiConsumer

accumulator, BiConsumer

combiner)
,>
,?>

Supplier needs to return the default result at the start of execution. Accumulator is used for progressive calculation and combiner is used for multi-thread merge results

Single-threaded execution is equivalent to the following code

R result = supplier.get();
for (T element : this stream)
  accumulator.accept(result, element);
return result;
Copy the code

The second collect (Collector
collector)

Collector is a wrapper around the above method arguments, and the internal execution logic is the same, except that the JDK provides some default Collector implementations

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
List<Integer> numList = numStream.collect(Collectors.toList());
Set<Integer> numSet = numStream.collect(Collectors.toSet());
Copy the code

min

The min method is used to calculate the minimum value of elements in the stream

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
Optional<Integer> min = numStream.min(Integer::compareTo);
Copy the code

max

The min method is used to calculate the maximum value of elements in the stream

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
Optional<Integer> max = numStream.max(Integer::compareTo);
Copy the code

count

The count method is used to count the total number of elements in the stream

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
//count=6
long count = numStream.count();
Copy the code

anyMatch

The anyMatch method is used to match whether any element in the checksum stream matches the specified condition

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
HasPositiveNum =true
boolean hasPositiveNum = numStream.anyMatch(num -> num > 0);
Copy the code

allMatch

The allMatch method is used to match whether all elements in the checksum stream match the specified condition

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
// Check whether all numbers are positive, allNumPositive=false
boolean allNumPositive = numStream.allMatch(num -> num > 0);
Copy the code

noneMatch

The noneMatch method is used to match if none of the elements in the checkstream match the specified condition

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
NoNegativeNum =false if there are no elements less than 0
boolean noNegativeNum = numStream.noneMatch(num -> num < 0);
Copy the code

findFirst

The findFirst method is used to get the first element and return optional.empty if the stream is empty

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
// get the first element firstNum=-2
Optional<Integer> firstNum = numStream.findFirst();
Copy the code

findAny

The findAny method is used to fetch any element in the stream, and returns Optional. Empty if the stream is empty. Since multiple threads may be used, there is no guarantee that the same element will be returned each time

Stream<Integer> numStream = Stream.of(-2, -1.0.1.2.3);
Optional<Integer> anyNum = numStream.findAny();
Copy the code