MZ

Streams in Java

Creating a Stream Application

  • A stream application typically starts with a public static void main method.

  • Streams are often used with collections, such as lists.

  • Example: A list of strings called names.

    • java List<String> names = new ArrayList<>();
  • Import necessary classes from java.util (e.g., List, ArrayList).

Populating the List

  • A method, populateNames, can be created to add names to the list.

    • java private static void populateNames(List<String> names) { // Add names to the list }
  • Using a random name generator to get a variety of names for the list.

Introduction to Streams

  • Streams were introduced in Java 8.

  • Streams are specifically used on collections.

  • Streams provide a way to iterate through data structures.

Iterating Through a List: Old Way vs. New Way

  • Old Way: Using a for-each loop.

    • java for (String name : names) { System.out.println(name); }
  • New Way: Using streams.

    • java names.stream().forEach(name -> System.out.println(name));
  • names.stream() returns a Stream<String>. There are two versions of this method.

  • After obtaining a stream, various operations can be performed on it.

Stream Syntax and Readability

  • For multiple operations on a stream, align the dots vertically for readability.

    • java names.stream() .forEach(name -> System.out.println(name));

Lambda Expressions with Streams

  • The forEach method takes a Consumer.

  • A Consumer is a functional interface with one abstract method called accept. It's a void method.

  • Using lambda expressions to implement the Consumer interface.

    • java names.stream().forEach(name -> System.out.println(name));
  • Can also be written with a code body

    • java names.stream().forEach(name -> {System.out.println(name);});
  • Can also be written with data type

    • java names.stream().forEach((String name) -> {System.out.println(name);});

Concise Lambda Syntax

  • The data type of the parameter in the lambda expression does not need to be specified.

  • If there is only one parameter, the brackets are not needed.

  • If the body of the lambda expression is a single line, the curly brackets and semicolon can be omitted.

  • Example:

    • java names.stream().forEach(name -> System.out.println(name));
  • The variable name in the lambda expression can be any valid name, but it should be meaningful.

Parallel Streams for Multithreading

  • Using parallelStream for multithreading.

    • java names.parallelStream().forEach(name -> System.out.println(name));
  • Multithreading can improve performance by utilizing multiple CPU cores.

  • With parallel streams, the order of elements may not be preserved due to asynchronous execution.

Understanding Multithreading

  • Modern CPUs often have multiple cores.

  • Multithreading allows utilizing these cores simultaneously.

  • Parallel streams make use of all the cores to the the for each looped code.

Asynchronous Nature of Parallel Streams

  • Parallel streams introduce asynchronous processing.

  • Asynchronous means operations don't necessarily execute in a sequential order.

  • Be cautious when using parallel streams due to potential asynchronous issues.

Alternatives to Lambda Expressions

  • Using the Consumer interface directly (less concise).

    • java names.stream().forEach(new Consumer<String>() { @Override public void accept(String t) { System.out.println(t); } });
  • Using lambda expressions is cleaner and more concise.

Conclusion

  • Streams provide a powerful way to process collections in Java.

  • Lambda expressions are commonly used with streams for concise code.

  • Parallel streams enable multithreading for improved performance.