[java8] To understand the Stream API

It's been 4 months since I changed jobs to an engineer with no experience and was assigned to the java team. I'm already used to java, but I'm using the extended for statement to expand list. I want to get along with Stream API, so I summarized it.

We plan to add methods as needed.

What is Stream API?

Overview

As a starting point, I think it's good to have an impression of "** something that allows you to easily operate the array **". Lazy evaluation and asynchronous processing are described below, but you do not need to know at first. (I don't understand much, so I want to think so ..)

Stream API features

Stream can operate arrays with a small amount of description, and has the following functions.

Asynchronous processing

Stream API can perform the asynchronous processing. Asynchronous processing, as the name implies, is not executing a series of processing sequentially (synchronizing), but performing it in parallel (asynchronous). When performing asynchronous processing with StreamAPI, use list.parallelStream () or List.stream (). Parallel () instead of the usual List.stream ().

For example, if there is a process to output the following list elements to the screen,

List<Integer> demoList = Arrays.asList(1, 2, 3, 4, 5);

If done synchronously, the output will be in the order of the array as it will be executed sequentially.

    for(Integer i : demoList) {
      System.out.print(i);
    }
    // 12345

However, if you do it asynchronously, it will be processed in parallel, so the output will be different from the array order.

    demoList.stream().parallel().forEach(System.out::print);
    // 32415

Also, by performing asynchronous processing, it is possible to process faster than turning the list with For. I actually measured the time.


    //Target List
    List<Integer> demoList = Stream.iterate(1, n -> n + 1).limit(100000).collect(Collectors.toList());

    //For Get the time before processing
    long startTimeFor = System.currentTimeMillis();

    //Output with For
    for(Integer i : demoList) {
      System.out.println(i);;
    }

    //Get the time after For processing
    long endTimeFor = System.currentTimeMillis();

    //Get the time before Stream processing
    long startTimeStream = System.currentTimeMillis();
    
    //Output with Stream
    demoList.parallelStream().forEach(System.out::println);

    //Get the time after Stream processing
    long endTimeStream = System.currentTimeMillis();

    System.out.println("Processing time For:" + (endTimeFor - startTimeFor) + " ms");
    System.out.println("Processing time Stream:" + (endTimeStream - startTimeStream) + " ms");

The results are as follows. The difference is not as great as I expected, but the above process was about 100ms faster on average.

Processing time For: 686 ms
Processing time Stream: 573 ms

Lazy evaluation

The Stream API allows lazy evaluation of functional languages. What is lazy evaluation?

In programming, formulas are often calculated when they appear, but lazy evaluation is the process of not calculating them until they are actually needed.

It is. In StreamAPI, expressions are not evaluated during intermediate operations (map and filter) described later. It is evaluated only when the termination operation is performed. Let's actually move it and verify it.

    //Target List
    List<Integer> demoList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

    //Streaming only even numbers Since it is an intermediate process, it has not been evaluated yet.
    Stream<Integer> oddListStream = demoList.stream().filter(n -> n % 2 == 0);

    //Add element to demoList
    demoList.add(6);
    demoList.add(7);
    demoList.add(8);

    //Output Stream
    oddListStream.forEach(System.out::print);

If you think about it normally, the oddListStream that is generating the Stream should contain 2 and 4. However, Stream's intermediate operations are lazy and will not be evaluated until the termination operation forEach is called. So the output is ...

$  2468

And, 6,7,8 added to demoList after Stream generation is processed.

Process flow

From here, we will actually look at the Stream operation in the order of generation → intermediate operation → termination operation.

1. Stream generation

First, create a Stream that is the basis for performing the operations described below. In addition to the commonly used List.stream (), Stream has various methods such as using a constructor and using a builder.

    //From list type
    Stream<Integer> numberStreamFromList = Arrays.asList(8, 1, 4, 2, 9).stream();

    // Stream.with of
    Stream<Integer> numberStreamFromStreamOf = Stream.of(8, 1, 4, 2, 9);

    //Using builder
    Builder<String> builder = Stream.builder();
    Stream<String> stringStream = builder.add("hoge").add("fuga").build();

    //Empty Stream
    Stream<String> emptyStream = Stream.empty();

    //With iterate
    Stream<Integer> numberStreamFromIterate = Stream.iterate(1, n -> n * 10).limit(5);

Only the method of using iterate is a little difficult to understand, so it is a supplement. The basic syntax is as follows.

Stream.iterate(initial value, initial valueが入る変数 ->Processing for variables).limit(Number of repetitions)

The reason why limit is applied is that if limit is not used, it will be generated infinitely.

You can easily do this output with iterate.

Say a number from 1 and become stupid only when it is a multiple of 3 (feel the times ..)

    Stream.iterate(1, n -> n + 1).limit(100)
        .map(n -> n % 3 == 0 ? "Stupid" : n)
        .forEach(System.out::println);

2. Intermediate operation

Intermediate operations are processing such as filtering and executing functions for each element of the array. The intermediate operation can be repeated many times. After filtering, process with map etc. Please note that the return value of the intermediate operation will be stream type. It doesn't return an array in list.map like ruby. In order to make it other than stream type, the termination operation described later is required.

Element selection [filter]

You can * filter * elements under certain conditions by using filter (). The following is a usage example.

Output only even numbers from the array

    //Target list
    List<Integer> numberList = Arrays.asList(8, 1, 4, 2, 9);

    //Output even numbers for statement
    for (Integer number : numberList) {
      if (number % 2 == 0) {
        System.out.println(number);
      }
    }

    //Output even numbers Stream
    numberList.stream()
        .filter(n -> n % 2 == 0)
        .forEach(System.out::println);

Edit element [map]

Doubles each element of the array and outputs it

    List<Integer> numberList = Arrays.asList(8, 1, 4, 2, 9);

    //Output by doubling each element for statement
    for (Integer number : numberList) {
      System.out.println(number * 2);
    }

    //Double each element for output Stream
    numberList.stream()
        .map(n -> n * 2)
        .forEach(System.out::println);

Sorting elements [sort]

Sorting elements is also easy if you use sort.

    List<Integer> numberList = Arrays.asList(8, 1, 4, 2, 9);

    List<Integer> sortListAsc = numberList.stream().sorted().collect(Collectors.toList());

    List<Integer> sortListDesc = numberList.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());

    System.out.println(sortListAsc);
    // [1, 2, 4, 8, 9]

    System.out.println(sortListDesc);
    // [9, 8, 4, 2, 1]

3. Termination operation

For the termination operation, you can execute the function sequentially using stream processed by map, filter, etc., or convert it to the specified type. The difference from the intermediate operation is that the return value is not Stream.

The following is a typical example.

Receive the result in the specified type [collect]

You can use collect to convert a Stream to various types and get the result.

Receive as an array [Collectors.toList ()]

Double the element and receive the result as an array

    List<Integer> numberList = Arrays.asList(8, 1, 4, 2, 9);

    List<Integer> doubleList = numberList.stream()
        .map(n -> n * 2)
        .collect(Collectors.toList());

    System.out.println(doubleList); //[16, 2, 8, 4, 18]

Receive on Map [Collectors.toMap ()]

Judge the value and create a map called [value, "even" or "odd"].

    List<Integer> numberList = Arrays.asList(8, 1, 4, 2, 9);

    Map<Integer, String> demoMap  = numberList.stream()
        .collect(Collectors.toMap(
            n -> n,
            s -> s % 2 == 0 ? "Even" : "Odd"));

    System.out.println(demoMap); //{1=Odd, 2=Even, 4=Even, 8=Even, 9=Odd}

Process each element [forEach]

Standard output as it is

    List<Integer> numberList = Arrays.asList(8, 1, 4, 2, 9);

    //Both are the same
    numberList.stream().forEach(n -> System.out.println(n));
    numberList.stream().forEach(System.out::println);

reference

http://www.task-notes.com/entry/20150518/1431918000 https://qiita.com/nmby/items/52d1b0e2dad5df475737 http://aoking.hatenablog.jp/entry/20110810/1312970979 https://qiita.com/kumazo/items/104fa685da8705b8cfd8#36-flatmap

Recommended Posts

[java8] To understand the Stream API
[Java] Introduction to Stream API
[Introduction to Java] About Stream API
Java Stream API
Java 8 ~ Stream API ~ to start now
Java reference to understand in the figure
Try using the Stream API in Java
I tried to summarize the Stream API
[Java] Stream API / map
Java8 Stream API practice
[Java] How to operate List using Stream API
Java Stream API cheat sheet
Java Stream API in 5 minutes
[Java] Stream API --Stream termination processing
[Java] Stream API --Stream intermediate processing
Java thread to understand loosely
[Java] Stream API intermediate operation
Input to the Java console
[For beginners] How to operate Stream API after Java 8
Use Java lambda expressions outside of the Stream API
Java classes and instances to understand in the figure
Java: Use Stream to sort the contents of the collection
[Must-see for apprentice java engineer] How to use Stream API
I want to use the Java 8 DateTime API slowly (now)
I tried using Java8 Stream API
Welcome to the Java Library Swamp! !!
Parsing the COTOHA API in Java
List processing to understand with pictures --java8 stream / javaslang --bonus
Now is the time to get started with the Stream API
The road from JavaScript to Java
Convert 2D array to csv format with Java 8 Stream API
How to play MIDI files using the Java Sound API
Sample code to call the Yahoo! Local Search API in Java
Leverage Either for individual exception handling in the Java Stream API
Articles to learn more about Stream API
[Java] How to use the File class
Data processing using stream API from Java 8
Introduction to java for the first time # 2
[Java] How to use the hasNext function
Call the Windows Notification API in Java
Java SE8 Silver ~ The Road to Pass ~
Nowadays Java lambda expressions and Stream API
[Java] How to use the HashMap class
About the procedure for java to work
[Java] How to use the toString () method
Hit the Salesforce REST API from Java
Studying how to use the constructor (java)
[Processing × Java] How to use the loop
[Java] How to set the Date time to 00:00:00
Try various Java Stream API methods (now)
[Java] How to get the current directory
Java 8 to start now ~ Date time API ~
[Java] Map # merge is hard to understand.
The Java EE Security API is here!
[Processing × Java] How to use the class
How to install the legacy version [Java]
Anonymous class (aiming to introduce stream api)
How to get the date in java
Output of the book "Introduction to Java"
[Processing × Java] How to use the function
I went to the Java Women's Club # 1