Useful stream utilities not found in Java
Tags: java, java8, functional, streams
Published: 2019-01-15 18:18:49

---
title: Useful stream utilities not found in Java
published: true
description: Imagining some useful stream utilities not found in the Java standard library, and making them available in Mill, an open-source library.
tags: java, java8, functional, streams
cover_image: https://thepracticaldev.s3.amazonaws.com/i/g8luu29tnuy1r6icw2th.jpg
---

_Photo by Karan Chawla on Unsplash_

## A bit of context
The standard Java library makes a reasonable attempt to provide useful utility methods for Java's functional [Stream](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Stream.html) object. For example, if a Stream contains null objects a quick filter can remove them with a method reference to the handy library-provided [Objects.nonNull](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Objects.html#nonNull(java.lang.Object)) method. Furthermore, perhaps you want to obtain a comma-delimited list of the objects' String representation. The standard library provides the [Collectors.joining](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Collectors.html#joining()) collector to facilitate that.

You can put these standard library methods together and you get some level of elegance in streams that you otherwise wouldn't. And they allow programmers to address common use cases such as the following example, which is to display the list of fruit available in the produce section of the local grocery store:

**The old imperative way**
```java
StringBuilder produceDescImperative = new StringBuilder();
for(Fruit fruit : fruits) {
  if(fruit != null) {
    produceDescImperative.append(fruit).append(", ");
  }
}
produceDescImperative.deleteCharAt(produceDescImperative.lastIndexOf(", "));
return produceDescImperative.toString();
```

**The new functional way**
```java
return fruits.stream()
        .filter(Objects::nonNull)
        .map(Object::toString)
        .collect(Collectors.joining(", "));
```

Methods such as `Objects::nonNull` and `Collectors.joining()` point the way toward a _readable_, _maintainable_ functional style in Java, which allows the language to maintain its personality while expanding it to include functional idioms.

## Some shortcomings

Unfortunately, the standard library often seems to stop partway to a developer-first orientation. For example, is there really a need to always map the Stream of objects to a String manually, as in line 3:

```java
return fruits.stream()
        .filter(Objects::nonNull)
        .map(Object::toString) // why ?
        .collect(Collectors.joining(", "));
```

Why can't the Collector returned by `Collectors.joining(", ")` figure out the `toString` call for itself? Almost anywhere else in the Java standard library, when an obvious String result is expected, the `toString()` call is made invisibly. (For example, `System.out.println(someObject)` is a valid call with the expected result, and saves the programmer from typing out "`System.out.println(someObject.toString())`."

It's likely that the library implementers didn't have the time or the context to use these utilities day-to-day and experience their shortcomings. Unfortunately, the rest of us have. That's not to say I blame them for not having the time or the context, just that there seems to be room for a better way.

## Introducing Mill

I'd rather offer solutions than problems and I'd like to do so with [Mill](https://github.com/scottashipp/mill), an open-source library that, among other things, makes working with streams in Java a little more elegant. With a `MoreCollectors.joining()` call in [Mill](https://github.com/scottashipp/mill), the prior example doesn't need the extra mapping to the `Object::toString`:

```java
import com.scottshipp.code.mill.stream.MoreCollectors;

// ...

return fruits.stream()
        .filter(Objects::nonNull)
        .collect(MoreCollectors.joining(", "));
```

[Mill](https://github.com/scottashipp/mill) also expands on the standard library offerings in various other ways. I'd like to run through some of them quickly.

### Concatenate More Than Two Streams
Two streams can be concatenated with [Stream.concat](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Stream.html#concat(java.util.stream.Stream,java.util.stream.Stream)). I always wondered why they didn't make this a method with varargs, allowing me to concatenate any number of streams?

In [Mill](https://github.com/scottashipp/mill), such a method exists.

```java
Stream<Fruit> fruitInStore = StreamOps.concat(fruitInDeli, fruitInProduceSection, fruitOnEndCaps);
```

### Non-empty Strings
A lot of existing methods in Java's standard library can be used as Predicates for filtering streams. For example, you can use `String::isEmpty` as a predicate in a filter. But why would you want to? The most common `String::isEmpty` usage in normal code is to make sure that a given string is _not empty_!

Which prompted this depressing [Stack Overflow question](https://stackoverflow.com/questions/21488056/how-to-negate-a-method-reference-predicate) showing that Java 8 doesn't even provide such a thing. Nor does Java 9 or 10.

In the Java 11 standard library, there's a clumsy `Predicate.not` utility to get the equivalent:

```java
long nonEmptyStrings = s.filter(Predicate.not(String::isEmpty)).count();
```

[Mill](https://github.com/scottashipp/mill), however, offers such a predicate:

```java
s.filter(StringPredicates.nonEmpty());
```
### Filtering by comparison
Another common use case is to filter a list down to a given range of the objects. Continuing our fruit example, let's say we want to list only the fruits that start with A-H.

The easiest way I know with the standard library is something like this (assuming moreFruits is a Stream<String>):

```java
moreFruits.stream()
    .filter(s -> String.CASE_INSENSITIVE_ORDER.compare(s, "h") <= 0)
    .collect(Collectors.joining(", ")));
```

It feels rather clumsy, and has some cognitive overhead where we remember that thing about how comparators return integers and negative numbers means less than.

How about the [Mill](https://github.com/scottashipp/mill) way, instead?

```java
moreFruits.stream()
    .filter(where(String.CASE_INSENSITIVE_ORDER).isLessThanOrEqualTo("h"))
    .collect(MoreCollectors.joining(", ")));
```

As you can see, [Mill](https://github.com/scottashipp/mill) offers a [fluent interface](https://www.martinfowler.com/bliki/FluentInterface.html) for constructing such range-based filters.

## But, wait, there's more
Rather than continue to belabor the point, I'll refer you to [Mill's Javadoc](https://code.scottshipp.com/mill-javadocs/) where you can find out more about what the library has to offer.

If you think Mill can be useful to you, you will want to use [Jitpack](https://jitpack.io/) to set [Mill](https://github.com/scottashipp/mill) as one of your application's dependencies, which is as easy as adding both of the following blocks in your pom:

**pom.xml**
```
<repositories>
    <repository>
      <id>jitpack.io</id>
      <url>https://jitpack.io</url>
    </repository>
  </repositories>

<dependencies>
    <dependency>
      <groupId>com.github.scottashipp</groupId>
      <artifactId>mill</artifactId>
      <version>v1.0</version>
    </dependency>

  </dependencies>
```

See the [Jitpack](https://jitpack.io/) site for Gradle directions.

### Contributors
Mill is also open to contributors. For example, it may make sense one day to get the library distributed via Maven Central. I plan on opening some `Help Wanted` issues soon for things I think could be useful. One of these is a String predicate for not null _and_ not empty. I'm not sure why I haven't included that yet. Another one is, maybe it makes sense to make a MoreCollectors.joining() that takes no arguments and defaults to a comma-delimited list.

### Final words
If you're interested, I also described how Mill offers something similar to the null-conditional operator in "[Better null-checking in Java](https://dev.to/scottshipp/better-null-checking-in-java-ngk)."

{% github scottashipp/mill %}