I was working on a previous post on Java and GraphQL and wanted to use a Linq query. Java doesn’t have Linq but it does have something equivalent (in Java 8) called Stream. For the examples within this post we’ll create the following simple method for generating our test data
private static List<String> getData() { return Arrays.asList( "2", "2", "2", "4", "4", "6", "7", "7", "9", "10"); }
Let’s look at some of the standard sort of functionality…
Distinct
We can get a distinct stream from our data using
Stream<String> distinct = getData() .stream() .distinct();
Selection/Filtering
If we want to filter our data to select only strings longer than one character, for example, then we can use the following
Stream<String> where = getData() .stream() .filter(s -> s.length() > 1);
Matching
There are several methods which return a Boolean, for example if all items in the Stream are of a certain value, or any of the values no matches, for example
boolean allMatch = getData() .stream() .allMatch(s -> s.contains("4")); boolean anyMatch = getData() .stream() .anyMatch(s -> s.contains("4")); boolean noneMatch = getData() .stream() .noneMatch(s -> s.contains("4"));
Map
In scenarios where we wish to change the data returned from a stream (i.e. like Select in Linq), for example we’ll simply loop through each item and return the length of each string as a Stream, we can use
Stream<Integer> select = getData() .stream() .map(String::length);
Reduce
If we want to take a stream and reduce it to a single value, for example taking our data and concatenating into a single String, we could use the following
String reduce = getData() .stream() .reduce("", (a, b) -> a + b);
The initial value “” in this case is a starting value for the reduced value, in this case we’re not wanting to prepend anything to our string. The result of the reduce is a String with the value 22244677910.
Creating an empty Stream
We can create an empty Stream (useful in those situations where we do not wish to return a null) using
Stream<String> empty = Stream.empty();
Iteration
We can iterate over the Stream using the forEach method, for example
getData() .stream() .forEach(s -> System.out.println(s));
Parallel Streams
We can also parallelize (is that a word) our Stream using the parallelStream, for example
Stream<Integer> parallel = getData() .parallelStream() .map(String::length);
As you’d expect the order or processing of the map in this instance is indeterminate.
Obviously there’s more to Stream than I’ve listed here, but you get the idea.