A Guide to Java Streams

  1. java stream is not Java I/O streams, streams are wrappers around a data source, allowing us to operate with that data source and making bulk processing convenient and fast.
    A stream does not store data and, in that sense, is not a data structure. It also never modifies the underlying data source.

  2. Obtain a stream from an existing list:

private static List<Employee> empList = Arrays.asList(arrayOfEmps);
empList.stream();
  1. Use stream builder to obtain a stream
Stream.Builder<Employee> empStreamBuilder = Stream.builder();

empStreamBuilder.accept(arrayOfEmps[0]);
empStreamBuilder.accept(arrayOfEmps[1]);
empStreamBuilder.accept(arrayOfEmps[2]);

Stream<Employee> empStream = empStreamBuilder.build();
  1. Stream operation: forEach, map, collect, filter, findFirst, toArray, flatMap, peek

4.1) forEach: loop the stream elements
4.2) map: map() produces a new stream after applying a function to each element of the original stream. The new stream could be of different type.

@Test
public void whenMapIdToEmployees_thenGetEmployeeStream() {
    Integer[] empIds = { 1, 2, 3 };
    
    List<Employee> employees = Stream.of(empIds)
      .map(employeeRepository::findById)
      .collect(Collectors.toList());
    
    assertEquals(employees.size(), empIds.length);
}

Each Integer is passed to the function employeeRepository::findById() – which returns the corresponding Employee object;

4.3) collect: collect(Collectors.toList()) repackaging elements to some data structures and applying some additional logic, concatenating them, etc.

4.4) filter: produces a new stream that contains elements of the original stream that pass a given test (specified by a Predicate).

4.5) findFirst: returns an Optional for the first entry in the stream.

4.6) toArray: Use collect() to get data out of the stream. But if we need to get an array out of the stream, we can simply use toArray():

4.7) flatMap: A stream can hold complex data structures like Stream<List<String>> to Stream<String>

@Test
public void whenFlatMapEmployeeNames_thenGetNameStream() {
    List<List<String>> namesNested = Arrays.asList( 
      Arrays.asList("Jeff", "Bezos"), 
      Arrays.asList("Bill", "Gates"), 
      Arrays.asList("Mark", "Zuckerberg"));

    List<String> namesFlatStream = namesNested.stream()
      .flatMap(Collection::stream)
      .collect(Collectors.toList());

    assertEquals(namesFlatStream.size(), namesNested.size() * 2);
}

4.8) peek: like forEach, but forEach is terminal option, but peek is an intermediate option.

@Test
public void whenIncrementSalaryUsingPeek_thenApplyNewSalary() {
    Employee[] arrayOfEmps = {
        new Employee(1, "Jeff Bezos", 100000.0), 
        new Employee(2, "Bill Gates", 200000.0), 
        new Employee(3, "Mark Zuckerberg", 300000.0)
    };

    List<Employee> empList = Arrays.asList(arrayOfEmps);
    
    empList.stream()
      .peek(e -> e.salaryIncrement(10.0))
      .peek(System.out::println)
      .collect(Collectors.toList());

    assertThat(empList, contains(
      hasProperty("salary", equalTo(110000.0)),
      hasProperty("salary", equalTo(220000.0)),
      hasProperty("salary", equalTo(330000.0))
    ));
}
  1. Why stream needed?
    One of the most important characteristics of Java streams is that they allow for significant optimizations through lazy evaluations.
    All intermediate operations are lazy, so they’re not executed until a result of a processing is actually needed.

eg.

@Test
public void whenFindFirst_thenGetFirstEmployeeInStream() {
    Integer[] empIds = { 1, 2, 3, 4 };
    
    Employee employee = Stream.of(empIds)
      .map(employeeRepository::findById)
      .filter(e -> e != null)
      .filter(e -> e.getSalary() > 100000)
      .findFirst()
      .orElse(null);
    
    assertEquals(employee.getSalary(), new Double(200000));
}

By lazy evaluation, stream performs the map and two filter operations, one element at a time. (comparing to direct array operation need 4 times)

  1. Method type and pipelines
    Terminal operations, such as forEach(), mark the stream as consumed, after which point it can no longer be used further.
    Intermediate operations such as filter() return a new stream on which further processing can be done.
    A stream pipeline consists of a stream source, followed by zero or more intermediate operations, and a terminal operation.

  2. Comparison based stream operations:
    containing: sorted, min, max, distinct, allMatch, anyMatch, noneMatch

  3. Stream specialization:
    IntStream, DoubleStream, LongStream etc.

refer:
!https://stackify.com/streams-guide-java-8/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容