Java’s Linq equivalent, Streams

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.