Stream API

Published in the Random EN group
Stream API - 1

What is Stream API?

The Stream API is a new way to work with data structures in a functional style. A Stream API (a description of the ways in which one computer program can communicate with another program) is, at its core, a stream of data. The term "thread" itself is quite vague in programming in general and in Java in particular.
Stream API - 1
With the advent of Java 8, the Stream API allowed programmers to write much more briefly what previously took many lines of code, namely, to simplify work with data sets, in particular, to simplify filtering, sorting and other data manipulation operations. If you don’t have intermediate operations, you can and should often do without a stream, otherwise the code will be more complicated than without a stream.
Stream API - 2
Where, exactly, should I start? From the creation of a Stream instance, which is based on the collection, array or method we need and where the data will be taken from accordingly:
List<String> list = new ArrayList<String>();
       list.add("One");
       list.add("Two");
       list.add("Three");
       list.add("Four");
       list.add("Five");
       list.add("Six");
       list.add("Seven");
       list.add("Eight");
       list.add("Nine");
       list.add("Ten");
       Stream stream = list.stream();
As mentioned above, the Stream API allows you to reduce the number of lines of code. Example with a stream:
IntStream.of(50, 60, 70, 80, 90, 100, 110, 120).filter(x -> x < 90).map(x -> x + 10)
.limit(3).forEach(System.out::print);
Example without thread:
int[] arr = {50, 60, 70, 80, 90, 100, 110, 120
	int count = 0;
	for (int x : arr) {
	    if (x >= 90) continue;
	    x += 10;
	    count++;
	    if (count > 3) break;
	    System.out.print(x);
	}
Possible ways to create a Stream:
Stream API - 3
  • Empty stream:Stream.empty()
  • Stream from List:list.stream()
  • Stream from Map:map.entrySet().stream()
  • Stream from the array:Arrays.stream(array)
  • Stream from the specified elements:Stream.of("1", "2", "3")
Further, there is such a thing as operators (essentially methods of the Stream class). Operators can be divided into two groups:
  • Intermediate (also called “lazy”) - process incoming elements and return the stream. There can be many intermediate operators in the element processing chain.
  • Terminal (“terminal”, also called “eager”) - process elements and terminate the stream, so there can only be one terminal operator in the chain.
Example:
1.List<String> list = new ArrayList<String>();
2.list.add("One");11.list.add("Ten");
12.Stream stream = list.stream();
13.stream.filter(x-> x.toString().length() == 3).forEach(System.out::println);
What's going on here:
  • 1 - create a list list;
  • 2-11 - fill it with test data;
  • 12 - create an object Stream;
  • 13 - method filter(filter) - intermediate operator, xequates to one element of the collection for enumeration (as with for each) and after -> we indicate how our collection is filtered and since this is an intermediate operator, the filtered collection goes further into the method, forEachwhich in turn is terminal (final) analogue of enumeration for each(Expression System.out::printlnshort for:, x-> System.out.println(x))which in turn goes through all the elements of the collection passed to it and displays it)
Stream API - 5
Important points:
  • Processing will not begin until the terminal operator is called. list.stream().filter(s -> s > 5)(will not take a single element from the list);
  • An instance of a stream cannot be used more than once =( ;
  • Stream API - 6

    Therefore, every time it’s new:

    list.stream().filter(x-> x.toString().length() == 3).forEach(System.out::println);
    list.stream().forEach(x -> System.out.println(x));
  • There can be many intermediate operators called on one stream, while there is only one terminal operator:

    stream.filter(x-> x.toString().length() == 3).map(x -> x + " - the length of the letters is three").forEach(x -> System.out.println(x));
Next, let's look at some intermediate operators:
Stream API - 7
  • filter(Predicate predicate)filters the stream, passing only those elements that pass the condition (Predicate is a built-in functional interface added to the package in Java SE 8. java.util.functionChecks the value for “ true ” and “ false ”);
  • map(Function mapper)makes it possible to create a function with which we will change each element and skip it further (The functional interface Function<T,R>represents the function of transition from an object of type T to an object of type R)
  • flatMap(Function<T, Stream<R>> mapper)- as in the case with map, they are used to convert to a primitive stream.
When working, for example, with an array of streams (arrays, lists, and so on), it converts them into one stream (array, list, and so on [stream1,stream2,stream3,stream4] => stream:
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Convert the word to an array of letters
        .flatMap(Arrays::stream).distinct() //aligns each generated thread into a single thread
        .collect(Collectors.toList()).forEach(System.out::println);
While mapit converts to a list of threads (more precisely <Stream>threads) [stream1,stream2,stream3,stream4] =>Stream.of(stream1,stream2,stream3,stream4):
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Convert the word to an array of letters
        .map(Arrays::stream).distinct() //Make the array into a separate thread
        .collect(Collectors.toList()).forEach(System.out::println);
Another difference compared to map, you can convert one element to zero, one or many others. In order to convert one element into zero elements, you need to return null, or an empty stream. To convert to one element, you need to return a stream from one element, for example, via Stream.of(x). To return several elements, you can create a stream with these elements by any means. The same flatMap method, but for Double, Integer and Long:
  • flatMapToDouble(Function mapper)
  • flatMapToInt(Function mapper)
  • flatMapToLong(Function mapper)
And another example for comparison, flatMap:
Stream.of(2, 3, 0, 1, 3)
        .flatMapToInt(x -> IntStream.range(0, x))
        .forEach(System.out::print);// 010120012
  • IntStream.range(0,x) – outputs elements from 0 (inclusive) to x (not inclusive) to the stream;

    map:

    Stream.of(2, 3, 0, 1, 3)
            .map(x -> IntStream.range(0, x))
            .forEach(System.out::print);//list of streams (streams);
  • limit(long maxSize) – limits the stream by the number of elements:

    stream.limit(5).forEach(x -> System.out.println(x));
  • skip(long n) – skip n elements:

    stream.skip(3).forEach(x -> System.out.println(x));
  • sorted()

  • sorted(Comparator comparator) – sorts the stream (sorting like TreeMap):

    stream.sorted().forEach(x -> System.out.println(x));
  • distinct() — checks the stream for uniqueness of elements (removes repetitions of elements);

  • dropWhile(Predicate predicate) - skips elements that satisfy the condition (appeared in java 9, The Predicate<T> functional interface checks whether some condition is met. If it is met, then true is returned. The lambda expression takes an object of type T as a parameter:

    Predicate<Integer> isPositive = x -> x > 0;
           System.out.println(isPositive.test(3)); // true
           System.out.println(isPositive.test(-9)); // false
Terminal operators:
Stream API - 8
  • forEach(Consumer action) – analogue of for each (Consumer<T> performs some action on an object of type T, without returning anything);

  • count() – returns the number of stream elements:

    System.out.println(stream.count());

  • collect(Collector collector) – method collects all elements into a list, set or other collection, groups elements according to some criterion, combines everything into a string, etc.:

    List<String> list = Stream.of(One,Two,Three).collect(Collectors.toList());
  • collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)— the same as , collect(collector)only the parameters are broken down for convenience ( suppliersupplies new objects (containers), for example new ArrayList(), accumulatoradds an element to the container, combinercombines parts of the stream together);

  • reduce(T identity, BinaryOperator accumulator) - converts all elements of the stream into one object (calculate the sum of all elements, or find the minimum element), first take the object identityand the first element of the stream, apply the function accumulatorand identitybecome its result. Then everything continues for the remaining elements.

    int sum = Stream.of(1, 2, 3, 4, 5).reduce(10, (acc, x) -> acc + x);// = 25
  • reduce(BinaryOperator accumulator)— the same method as above but the initial one is missing identity, it is the first element of the stream

    Optional min(Comparator comparator)
    Optional max(Comparator comparator) searches for the minimum/maximum element based on the passed comparator;

  • findFirst()– pulls out the first element of the stream:

    Stream.of(1, 2, 3, 4, 9).findFirst();
  • allMatch(Predicate predicate)— returns true if all elements of the stream satisfy the condition. If any element is encountered for which the result of calling the predicate function is false , then the operator stops scanning the elements and returns false :

    Stream.of(1, 2, 3, 4, 9).allMatch(x -> x <= 7);//false
  • anyMatch(Predicate predicate)— will return true if at least one element of the stream satisfies the condition predicate:

    Stream.of(1, 2, 3, 4, 9).anyMatch(x -> x >= 7);//true
  • noneMatch(Predicate predicate)— will return true if, having gone through all the elements of the stream, none of them satisfied the condition predicate:

    Stream.of(1, 2, 3, 4, 9).noneMatch(x -> x >= 7);//false
And finally I would like to look at some methods Collectors:
  • toList()— collects elements into List:

    List<Integer> list = Stream.of(99, 2, 3).collect(Collectors.toList());
  • toSet()— collects elements into a set:

    Set<Integer> set = Stream.of(99, 2, 3).collect(Collectors.toSet());
  • counting()— Counts the number of elements:

    Long count = Stream.of("1", "2", "3", "4").collect(Collectors.counting());
  • joining()

  • joining(CharSequence delimiter)

  • joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)— collects elements into one line. Additionally, you can specify a separator, as well as a prefix and suffix for the entire sequence:

    String a = Stream.of("s", "u" ,"p", "e", "r").collect(Collectors.joining());
           System.out.println(a); // super
    
           String b = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining("-"));
           System.out.println(b); // s-u-p-e-r
    
           String c = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining(" -> ", "[ ", " ]"));
           System.out.println(c);  // [ s -> u -> p -> e -> r ]
  • summingInt(ToIntFunction mapper)

  • summingLong(ToLongFunction mapper)

  • summingDouble(ToDoubleFunction mapper)- a collector that converts objects to int/long/double and calculates the sum.

Useful links: PS: don’t be shy about showering us with likes ^ : ^
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION