Week 48 — What are `Stream`s (from `java.util.stream`) and how can they process data?

Question of the Week #48
What are Streams (from java.util.stream) and how can they process data?
4 Replies
Eric McIntyre
Eric McIntyre13mo ago
Streams allow processing data in a declarative way. A Stream represents a pipeline that starts at a source specifying where the data is coming from and ends with a terminal operation that collects (some of) the data or performs operations on it. Streams utilize method chaining to chain together operations starting from the sink and ending at the terminal operation with an arbitrary amount of intermediate operations in between. It is possible to get a Stream from any Collection by calling Collection#stream. Similarly, it is possible to get a Stream from an array using Arrays.stream:
List<String> someList = List.of("Hello", "World");
Stream<String> listStream = someList.stream();

String[] someArray = new String[]{"Hello", "World"};
Stream<String> listStream = Arrays.stream(someArray);
List<String> someList = List.of("Hello", "World");
Stream<String> listStream = someList.stream();

String[] someArray = new String[]{"Hello", "World"};
Stream<String> listStream = Arrays.stream(someArray);
Common terminal operations include toList which gets a List with all elements of the Stream or collect which allows collecting the elements with a custom Collector.
List<String> streamConvertedToList = List.of("Hello", "World").stream().toList();//get a list back from the stream
Map<Character, List<String>> groupedByFirstCharacter = List.of("Hello", "World").stream().collect(Collectors.groupingBy(str -> str.charAt(0)));//{H=[Hello], W=[World]}
List<String> streamConvertedToList = List.of("Hello", "World").stream().toList();//get a list back from the stream
Map<Character, List<String>> groupedByFirstCharacter = List.of("Hello", "World").stream().collect(Collectors.groupingBy(str -> str.charAt(0)));//{H=[Hello], W=[World]}
Similarly, it is possible to use finyAny/findFirst which get a single element from the Stream wrapped in an Optional or Optional.empty() if there are no such elements:
List<String> someList = List.of("Hello", "World");
Optional<String> someElement = someList.stream().findAny();
List<String> someList = List.of("Hello", "World");
Optional<String> someElement = someList.stream().findAny();
Eric McIntyre
Eric McIntyre13mo ago
Between the source and the terminal operations, it is possible to add intermediate operations. For example, filter can be used to only include elements matching a condition:
List<String> streamConvertedToList = List.of("Hello", "World")
.stream()
.filter(str -> str.startsWith("H"))//ignore elements not starting with H
.toList();//List containing Hello
List<String> streamConvertedToList = List.of("Hello", "World")
.stream()
.filter(str -> str.startsWith("H"))//ignore elements not starting with H
.toList();//List containing Hello
Another common intermediate operations is map which transforms all object using a function:
List<Integer> lengths = List.of("Hello", "World")
.stream()
.map(str -> str.length())//convert all Strings to their lengths
.toList();//5, 5
List<Integer> lengths = List.of("Hello", "World")
.stream()
.map(str -> str.length())//convert all Strings to their lengths
.toList();//5, 5
Similar to that, the method flatMap accepts a function that converts each object to a Stream and allows processing all elements of all streams returned by the function.
List.of("Hello", "World")
.stream()
.flatMap(str -> str.chars().boxed())//chars().boxed() returns a Stream containing all chars of the String as Integer objects
.toList();//list of all characters/code points in the original Strings: [72, 101, 108, 108, 111, 87, 111, 114, 108, 100]
List.of("Hello", "World")
.stream()
.flatMap(str -> str.chars().boxed())//chars().boxed() returns a Stream containing all chars of the String as Integer objects
.toList();//list of all characters/code points in the original Strings: [72, 101, 108, 108, 111, 87, 111, 114, 108, 100]
📖 Sample answer from dan1st
Eric McIntyre
Eric McIntyre13mo ago
The stream package provides a variety of things, the Stream API's work is to process complex data and to sum it up the data can be processed sequentially or parallely, there are more ways to process the data. some key features are stream() this returns the source or collection or an array, and also i/o channels but we won't cover that and then there's parallelStream() to process parallely, the Stream API would also give us access to mappings, filtering and more of it's methods.
Eric McIntyre
Eric McIntyre13mo ago
List<String> myList = Arrays.asList("hey", "hello", "bonjour");

Stream<String> resultStream = myList.stream()
.filter(s -> s.startsWith("b")) // Filters the array elements that starts with b, here it's "bonjour"
.map(String::toUpperCase); // Maps it to uppercase, meaning bonjour -> BONJOUR
List<String> myList = Arrays.asList("hey", "hello", "bonjour");

Stream<String> resultStream = myList.stream()
.filter(s -> s.startsWith("b")) // Filters the array elements that starts with b, here it's "bonjour"
.map(String::toUpperCase); // Maps it to uppercase, meaning bonjour -> BONJOUR
⭐ Submission from xenofic
Want results from more Discord servers?
Add your server