Writing a Function for parsing data – Functional style programming – extending API

183. Writing a Function<String, T> for parsing data

Let’s assume that we have the following text:

String text = “””
  test, a, 1, 4, 5, 0xf5, 0x5, 4.5d, 6, 5.6, 50000, 345,
  4.0f, 6$3, 2$1.1, 5.5, 6.7, 8, a11, 3e+1, -11199, 55                    
  “””;

And, the goal is to find a solution that extracts from this text only the numbers. Depending on a given scenario, we may need only the integers, or only the doubles, and so on. Sometimes, we may need to perform some text replacements before extraction (for instance, we may want to replace the xf characters with a dot, 0xf5 = 0.5).A possible solution to this problem is to write a method (let’s name it parseText()) that takes as argument a Function<String, T>. The Function<String, T> gives us the flexibility to shape any of the following:

List<Integer> integerValues
  = parseText(text, Integer::valueOf);
List<Double> doubleValues
  = parseText(text, Double::valueOf);

List<Double> moreDoubleValues
  = parseText(text, t -> Double.valueOf(t.replaceAll(
      “\\$”, “”).replaceAll(“xf”, “.”).replaceAll(“x”, “.”)));

The parseText() should perform several steps until it reaches the final result. Its signature can be as follows:

public static <T> List<T> parseText(
    String text, Function<String, T> func) {
  …
}

First, we have to split the received text by the comma delimiter and extract the items in a String[]. This way we have access to each item from the text.Second, we can stream the String[] and filter any empty items.Third, we can call the Function.apply() to apply the given function to each item (for instance, to apply Double::valueOf). This can be done via the intermediate operation map(). Since some items may be invalid numbers, we have to catch and ignore any Exception (it is a bad practice to swallow an exception like this but, in this case, there is really nothing else to do). For any invalid number, we simply return null.Fourth, we filter all null values. This means that the remaining stream contains only numbers that passed through Function.apply().Fifth, we collect the stream in a List and return it.Gluing these 5 steps will result in the following code:

public static <T> List<T> parseText(
    String text, Function<String, T> func) {
  return Arrays.stream(text.split(“,”)) // step 1 and 2
    .filter(s -> !s.isEmpty())
    .map(s -> {
       try {
         return func.apply(s.trim());   // step 3
       } catch (Exception e) {}
       return null;
    })
    .filter(Objects::nonNull)           // step 4
    .collect(Collectors.toList());      // step 5
}

Done! You can use this example to solve a wide range of similar problems.

Composing predicates in Stream’s filters – Functional style programming – extending API

184. Composing predicates in Stream’s filters

A predicate (basically, a condition) can be modeled as a boolean-valued function via java.util.function.Predicate functional interface. Its functional method is named test(T t) and returns a boolean.Applying predicates in a stream pipeline can be done via several stream intermediate operations but we are interested here only in the filter(Predicate p) operation. For instance, let’s consider the following class:

public class Car {
  private final String brand;
  private final String fuel;
  private final int horsepower;
  public Car(String brand, String fuel, int horsepower) {
    this.brand = brand;
    this.fuel = fuel;
    this.horsepower = horsepower;
  }
 
  // getters, equals(), hashCode(), toString()
}

If we have a List<Car> and we want to express a filter that produces all the cars that are Chevrolets then we can start by defining the proper Predicate:

Predicate<Car> pChevrolets
  = car -> car.getBrand().equals(“Chevrolet”);

Next, we can use this Predicate in a stream pipeline as follows:

List<Car> chevrolets = cars.stream()              
  .filter(pChevrolets)
  .collect(Collectors.toList());

A Predicate can be negated in at least three ways. We can negate the condition via the logical not (!) operator:

Predicate<Car> pNotChevrolets
  = car -> !car.getBrand().equals(“Chevrolet”);

We can call the Predicate.negate() method:

Predicate<Car> pNotChevrolets = pChevrolets.negate();     

Or, we can call the Predicate.not() method:

Predicate<Car> pNotChevrolets = Predicate.not(pChevrolets);

No matter which of these three approaches you prefer, the following filter will produce all cars that are not Chevrolets:

List<Car> notChevrolets = cars.stream()              
  .filter(pNotChevrolets)              
  .collect(Collectors.toList());

In the previous examples, we have applied a single predicate in a stream pipeline. But, we can apply multiple predicates as well. For instance, we may want to express a filter that produces all the cars that are not Chevrolets and have at least 150 horsepower. For the first part of this composite predicate, we can arbitrarily use pChevrolets.negate(), while for the second part, we need the following Predicate:

Predicate<Car> pHorsepower
  = car -> car.getHorsepower() >= 150;

We can obtain a composite predicate by chaining the filter() calls as follows:

List<Car> notChevrolets150 = cars.stream()              
  .filter(pChevrolets.negate())
  .filter(pHorsepower)
  .collect(Collectors.toList());

But, more shortly and expressive is to rely on Predicate#and(Predicate<? super T> other) which applies the short-circuiting logical AND between two predicates. So, the previous example is better expressed as follows:

List<Car> notChevrolets150 = cars.stream()              
  .filter(pChevrolets.negate().and(pHorsepower))
  .collect(Collectors.toList());

If we need to apply the short-circuiting logical OR between two predicates then relying on Predicate#or(Predicate<? super T> other) is the proper choice. For instance, if we want to express a filter that produces all Chevrolets or electric cars then we can do it as follows:

Predicate<Car> pElectric
  = car -> car.getFuel().equals(“electric”);
      
List<Car> chevroletsOrElectric = cars.stream()              
  .filter(pChevrolets.or(pElectric))
  .collect(Collectors.toList());

If we are in a scenario that heavily relies on composite predicates then we can start by creating two helpers that make our job easier:

@SuppressWarnings(“unchecked”)
public final class Predicates {
  
  private Predicates() {
    throw new AssertionError(“Cannot be instantiated”);
  }
  public static <T> Predicate<T> asOneAnd(
      Predicate<T>… predicates) {
    Predicate<T> theOneAnd = Stream.of(predicates)
      .reduce(p -> true, Predicate::and);
      
    return theOneAnd;
  }
  
  public static <T> Predicate<T> asOneOr(
      Predicate<T>… predicates) {
    Predicate<T> theOneOr = Stream.of(predicates)
      .reduce(p -> false, Predicate::or);
      
    return theOneOr;
  }
}

So, the goal of these helpers is to take several predicates and glue them into a single composite predicate via the short-circuiting logical AND and OR.Let’s assume that we want to express a filter that applies the following three predicates via the short-circuiting logical AND:

Predicate<Car> pLexus=car -> car.getBrand().equals(“Lexus”);
Predicate<Car> pDiesel=car -> car.getFuel().equals(“diesel”);      
Predicate<Car> p250=car -> car.getHorsepower() > 250;    

First, we join these predicates in a single one:

Predicate<Car> predicateAnd = Predicates
  .asOneAnd(pLexus, pDiesel, p250);

Afterward, we express the filter:

List<Car> lexusDiesel250And = cars.stream()              
  .filter(predicateAnd)              
  .collect(Collectors.toList());

How about expressing a filter that produces a stream containing all cars having horsepower between 100 and 200 or 300 and 400? The predicates are:

Predicate<Car> p100 = car -> car.getHorsepower() >= 100;
Predicate<Car> p200 = car -> car.getHorsepower() <= 200;
      
Predicate<Car> p300 = car -> car.getHorsepower() >= 300;
Predicate<Car> p400 = car -> car.getHorsepower() <= 400;

The composite predicate can be obtained as follows:

Predicate<Car> pCombo = Predicates.asOneOr(
  Predicates.asOneAnd(p100, p200),
  Predicates.asOneAnd(p300, p400)
);

Expressing the filter is straightforward:

List<Car> comboAndOr = cars.stream()              
  .filter(pCombo)              
  .collect(Collectors.toList());

You can find all these examples in the bundled code.

Streaming custom code to map – Functional style programming – extending API

179. Streaming custom code to map

Let’s assume that we have the following legacy class:

public class Post {
  
  private final int id;
  private final String title;
  private final String tags;
  public Post(int id, String title, String tags) {
    this.id = id;
    this.title = title;
    this.tags = tags;
  }
  …
  public static List<String> allTags(Post post) {
      
    return Arrays.asList(post.getTags().split(“#”));
  }
}

So, we have a class that shapes some blog posts. Each post has several properties including its tags. The tags of each post are actually represented as a string of tags separated by hashtag (#). Whenever we need the list of tags for a given post, we can call the allTags() helper. For instance, here is a list of posts and their tags:

List<Post> posts = List.of(
  new Post(1, “Running jOOQ”, “#database #sql #rdbms”),
  new Post(2, “I/O files in Java”, “#io #storage #rdbms”),
  new Post(3, “Hibernate Course”, “#jpa #database #rdbms”),
  new Post(4, “Hooking Java Sockets”, “#io #network”),
  new Post(5, “Analysing JDBC transactions”, “#jdbc #rdbms”)
);

Our goal is to extract from this list a Map<String, List<Integer>> containing for each tag (key) the list of posts (value). For instance, for tag #database, we have articles 1 and 3, for tag #rdbms, we have articles 1, 2, 3, and 5, and so on.Accomplishing this task in functional programming can be done via flatMap() and groupingBy(). Both of these have been covered in detail in Java Coding Problems, First Edition. In a nutshell, flatMap() is useful to flatten a nested Stream<Stream<R>> model, while groupingBy() is a collector useful to group data in a map by some logic/property.We need flatMap() because we have the List<Post> that, for each Post, nests via allTags() a List<String> (so, if we simply call stream() then we get back a Stream<Stream<R>>). After flattening, we wrap each tag in Map.Entry<String, Integer>. Finally, we group these entries by tags into a Map as follows:

Map<String, List<Integer>> result = posts.stream()
  .flatMap(post -> Post.allTags(post).stream()
  .map(t -> entry(t, post.getId())))
  .collect(groupingBy(Entry::getKey,
              mapping(Entry::getValue, toList())));

But, based on the previous problem, we know that starting with JDK 16, we can use mapMulti(). So, we can re-write the previous snippet as follows:

Map<String, List<Integer>> resultMulti = posts.stream()
  .<Map.Entry<String, Integer>>mapMulti((post, consumer) -> {
      for (String tag : Post.allTags(post)) {
             consumer.accept(entry(tag, post.getId()));
      }
  })
  .collect(groupingBy(Entry::getKey,
              mapping(Entry::getValue, toList())));

This time, we saved the map() intermediate operation and intermediate streams.

Filtering nested collections with Streams – Functional style programming – extending API

185. Filtering nested collections with Streams

This is a classical problem in interviews that usually starts from a model as follows (we assume that the collection is a List):

public class Author {
  private final String name;
  private final List<Book> books;
  …
}
public class Book {
  
  private final String title;
  private final LocalDate published;
  …
}

Having a List<Author> denoted as authors, write a stream pipeline that returns the List<Book> published in 2002. You already should recognize this as a typical problem for flatMap(), so without further details, we can write this:

List<Book> book2002fm = authors.stream()
  .flatMap(author -> author.getBooks().stream())
  .filter(book -> book.getPublished().getYear() == 2002)
  .collect(Collectors.toList());

From Problem 178, we know that where flatMap() is useful, we should consider the JDK 16’s mapMulti() as well. Before checking the following snippet of code, challenge yourself to re-write the previous code via mapMulti():

List<Book> book2002mm = authors.stream()
  .<Book>mapMulti((author, consumer) -> {
     for (Book book : author.getBooks()) {
       if (book.getPublished().getYear() == 2002) {
         consumer.accept(book);
       }
     }
   })
   .collect(Collectors.toList());

Ok, that’s crystal clear! How about finding the List<Author> having books published in 2002? Of course, mapMulti() can help us again. All we have to do is to loop the books and, when we find a book published in 2002, we simply pass the author to the consumer instead of the book. Moreover, after passing the author to the consumer, we can break the loop for the current author and take the next one:

List<Author> author2002mm = authors.stream()
  .<Author>mapMulti((author, consumer) -> {
     for (Book book : author.getBooks()) {
       if (book.getPublished().getYear() == 2002) {
         consumer.accept(author);
         break;
       }
     }
   })
   .collect(Collectors.toList());

Another approach can rely on anyMatch() and a predicate that produces a stream of books published in 2002 as follows:

List<Author> authors2002am = authors.stream()
  .filter(
     author -> author.getBooks()
                     .stream()
                     .anyMatch(book -> book.getPublished()
                       .getYear() == 2002)
  )
 .collect(Collectors.toList());

Typically, we don’t want to alter the given list, but if that is not an issue (or, is exactly what we want), then we can rely on removeIf() to accomplish the same result directly on the List<Author>:

authors.removeIf(author -> author.getBooks().stream()
  .noneMatch(book -> book.getPublished().getYear() == 2002));

Done! Now, you should have no issues caused by such problems in your interviews.

Using BiPredicate – Functional style programming – extending API

186 Using BiPredicate

Let’s consider the Car model and a List<Car> denoted as cars:

public class Car {
  private final String brand;
  private final String fuel;
  private final int horsepower;
  …
}

Our goal is to see if the following Car is contained in cars:

Car car = new Car(“Ford”, “electric”, 80);

We know that the List API exposes a method named contains(Object o). This method returns true if the given Object is present in the given List. So, we can easily write a Predicate as follows:

Predicate<Car> predicate = cars::contains;

Next, we call the test() method and we should get the expected result:

System.out.println(predicate.test(car)); // true

We can obtain the same result in a stream pipeline via filter(), anyMatch(), and so on. Here is via anyMatch():

System.out.println(
  cars.stream().anyMatch(p -> p.equals(car))
);

Alternatively, we can rely on BiPredicate. This is a functional interface representing a two-arity specialization of the well-known Predicate. Its test(Object o1, Object o2) method gets two arguments, so it is a perfect fit for our case:

BiPredicate<List<Car>, Car> biPredicate = List::contains;

And, we can perform the test as follows:

System.out.println(biPredicate.test(cars, car)); // true

In the next problem, you’ll see a more practical example of using a BiPredicate.

187. Building a dynamic predicate for a custom model

Let’s consider the Car model and a List<Car> denoted as cars:

public class Car {
  private final String brand;
  private final String fuel;
  private final int horsepower;
  …
}

And, let’s assume that we need to dynamically produce a wide range of predicates that applies the operators <, >, <=, >=,!=, and == to the horsepower field. It will be cumbersome to hardcode such predicates, so we have to come up with a solution that can build on the fly any predicate that involves this field and one of the comparison operators listed here.There are a few approaches to accomplish this goal, and one of them is to use a Java enum. We have a fixed list of operators that can be coded as enum elements as follows:

enum PredicateBuilder {
  GT((t, u) -> t > u),
  LT((t, u) -> t < u),
  GE((t, u) -> t >= u),
  LE((t, u) -> t <= u),
  EQ((t, u) -> t.intValue() == u.intValue()),
  NOT_EQ((t, u) -> t.intValue() != u.intValue());
  …

In order to apply any of these (t, u) lambdas, we need a BiPredicate constructor (see Problem 186) as follows:

  private final BiPredicate<Integer, Integer> predicate;
  private PredicateBuilder(
      BiPredicate<Integer, Integer> predicate) {
    this.predicate = predicate;
  }
  …

Now that we can define a BiPredicate, we can write the method that contains the actual test and returns a Predicate<T>:

  public <T> Predicate<T> toPredicate(
      Function<T, Integer> getter, int u) {
    return obj -> this.predicate.test(getter.apply(obj), u);
  }
  …

Finally, we have to provide here the Function<T, Integer> which is the getter corresponding to horsepower. We can do this via Java Reflection as follows:

public static <T> Function<T, Integer> getFieldByName(
    Class<T> cls, String field) {
  return object -> {
    try {
      Field f = cls.getDeclaredField(field);
      f.setAccessible(true);
      return (Integer) f.get(object);
    } catch (IllegalAccessException | IllegalArgumentException
           | NoSuchFieldException | SecurityException e) {              
      throw new RuntimeException(e);
    }
  };
}

Of course, it can be any other class and integer field as well, not only the Car class and the horsepower field. Based on this code, we can dynamically create a predicate as follows:

Predicate<Car> gtPredicate
  = PredicateBuilder.GT.toPredicate(
      PredicateBuilder.getFieldByName(
        Car.class, “horsepower”), 300);

Using this predicate is straightforward:

cars.stream()
    .filter(gtPredicate)
    .forEach(System.out::println);

You can use this problem as an inspiration point for implementing more types of dynamic predicates. For example, in the next problem, we use the same logic in another scenario.

Building a dynamic predicate from a custom map of conditions – Functional style programming – extending API

188. Building a dynamic predicate from a custom map of conditions

Let’s consider the Car model and a List<Car> denoted as cars:

public class Car {
  private final String brand;
  private final String fuel;
  private final int horsepower;
  …
}

And, let’s assume that we receive a Map of conditions of type field : value that should be used to build a dynamic Predicate. An example of such a Map is listed here:

Map<String, String> filtersMap = Map.of(
  “brand”, “Chevrolet”,
  “fuel”, “diesel”
);

As you can see, we have a Map<String, String>, so we are interested in an equals() comparison. This is useful to start our development via the following Java enum (we follow the logic from Problem 187):

enum PredicateBuilder {
  EQUALS(String::equals);
  …

Of course, we can add more operators such as startsWith(), endsWith(), contains(), and so on. Next, based on the experience gained in Problems 186 and 187, we need to add a BiPredicate constructor, the toPredicate() method, and the Java Reflection code for fetching the getters corresponding to the given fields (here, brand and fuel):

  private final BiPredicate<String, String> predicate;
  private PredicateBuilder(
      BiPredicate<String, String> predicate) {
    this.predicate = predicate;
  }
  public <T> Predicate<T> toPredicate(
      Function<T, String> getter, String u) {
    return obj -> this.predicate.test(getter.apply(obj), u);
  }
  public static <T> Function<T, String>
      getFieldByName(Class<T> cls, String field) {
    return object -> {
      try {
        Field f = cls.getDeclaredField(field);
        f.setAccessible(true);
        return (String) f.get(object);
      } catch (
          IllegalAccessException | IllegalArgumentException
          | NoSuchFieldException | SecurityException e) {              
        throw new RuntimeException(e);
      }
    };
  }      
}

Next, we have to define a predicate for each map entry and chain them via the short-circuiting AND operator. This can be done in a loop as follows:

Predicate<Car> filterPredicate = t -> true;
for(String key : filtersMap.keySet()){
  filterPredicate
    = filterPredicate.and(PredicateBuilder.EQUALS
      .toPredicate(PredicateBuilder.getFieldByName(
        Car.class, key), filtersMap.get(key)));           
}

Finally, we can use the resulting predicate to filter the cars:

cars.stream()
    .filter(filterPredicate)
    .forEach(System.out::println);

Done!

Logging in predicates 2 – Functional style programming – extending API

Exposing constainsAll/Any() via an extension of Stream

The previous solution can be considered more like a hack. A more logical and realistic solution will consist of extending the built-in Stream API and adding our containsAll/Any() methods as teammates next to the Stream operations. So, the implementation starts as follows:

@SuppressWarnings(“unchecked”)
public interface Streams<T> extends Stream<T> {      
  …
}

Before implementing the containsAll/Any() methods, we need to handle some aspects resulting from extending the Stream interface. First, we need to override in Streams each of the Stream methods. Since the Stream interface has a lot of methods, we list here only a few of them:

@Override
public Streams<T> filter(Predicate<? super T> predicate);
@Override
public <R> Streams<R> map(
  Function<? super T, ? extends R> mapper);

@Override
public T reduce(T identity, BinaryOperator<T> accumulator);

@Override
default boolean isParallel() {
  return false;
}

@Override
default Streams<T> parallel() {
  throw new UnsupportedOperationException(
    “Not supported yet.”); // or, return this
}
@Override
default Streams<T> unordered() {
  throw new UnsupportedOperationException(
    “Not supported yet.”); // or, return this
}

@Override
default Streams<T> sequential() {
  return this;
}

Since Streams can handle only sequential streams (parallelism is not supported), we can implement the isParallel(), parallel(), unordered(), and sequential() methods as default methods directly in Streams.Next, in order to use our Streams, we need a from(Stream s) method that is capable to wrap the given Stream as follows:

static <T> Streams<T> from(Stream<? extends T> stream) {
  if (stream == null) {
    return from(Stream.empty());
  }
  if (stream instanceof Streams) {
    return (Streams<T>) stream;
  }
  return new StreamsWrapper<>(stream);
}

The StreamsWrapper is a class that wraps the current Stream into sequential Streams. StreamsWrapper implements Streams, so it has to override all the Streams methods and properly wrap the Stream to Streams. Because Streams has quite a lot of methods (as a consequence of extending Stream), we list here only a few of them (the rest are available in the bundled code):

@SuppressWarnings(“unchecked”)
public class StreamsWrapper<T> implements Streams<T> {
  private final Stream<? extends T> delegator;
  public StreamsWrapper(Stream<? extends T> delegator) {
    this.delegator = delegator.sequential();
  }     
  @Override
  public Streams<T> filter(Predicate<? super T> predicate) {      
    return Streams.from(delegator.filter(predicate));
  }
  @Override
  public <R> Streams<R> map(
      Function<? super T, ? extends R> mapper) {
    return Streams.from(delegator.map(mapper));
  }
  …
  @Override
  public T reduce(T identity, BinaryOperator<T> accumulator) {
    return ((Stream<T>) delegator)
      .reduce(identity, accumulator);
  }
  …
}

Finally, we add in Streams the containsAll/Any() methods which are quite straightforward (since Streams extends Stream, we have access to all the Stream goodies without the need to write a stream() hack as in the previous solution). First we add the containsAll() methods:

default boolean contains(T item) {
  return anyMatch(isEqual(item));
}
default boolean containsAll(T… items) {
  return containsAll(Stream.of(items));
}
default boolean containsAll(List<? extends T> items) {
  return containsAll(items.stream());
}
default boolean containsAll(Stream<? extends T> items) {
  Set<? extends T> set = toSet(items);
  if (set.isEmpty()) {
    return true;
  }
  return filter(item -> set.remove(item))
    .anyMatch(any -> set.isEmpty());
}

Second, we add the containsAny() methods:

default boolean containsAny(T… items) {
  return containsAny(Stream.of(items));
}
default boolean containsAny(List<? extends T> items) {
  return containsAny(items.stream());
}
default boolean containsAny(Stream<? extends T> items) {
  Set<? extends T> set = toSet(items);
  if (set.isEmpty()) {
    return false;
  }
  return anyMatch(set::contains);
}

And, the toSet() method that you already know:

static <T> Set<T> toSet(Stream<? extends T> stream) {
  return stream.collect(Collectors.toSet());
}

Mission accomplished! Now, let’s write some examples:

boolean result = Streams.from(cars.stream())
  .filter(car -> car.getBrand().equals(“Mercedes”))
  .contains(car1);
boolean result = Streams.from(cars.stream())
  .containsAll(cars123);
boolean result = Streams.from(cars123.stream())
  .containsAny(cars.stream());

You can find more examples in the bunded code.

Logging in predicates – Functional style programming – extending API

189. Logging in predicates

We already know that the Predicate functional interface relies on its test() method to perform the given check and it returns a boolean value. Let’s suppose that we want to alter the test() method to log the failure cases (the cases that leads to the return of a false value).A quick approach is to write a helper method that sneaks the logging part as follows:

public final class Predicates {
  private static final Logger logger
    = LoggerFactory.getLogger(LogPredicate.class);
  private Predicates() {
    throw new AssertionError(“Cannot be instantiated”);
  }
  public static <T> Predicate<T> testAndLog(
      Predicate<? super T> predicate, String val) {
    return t -> {
      boolean result = predicate.test(t);
      if (!result) {
        logger.warn(predicate + ” don’t match ‘” + val + “‘”);
      }
      return result;
    };
  }
}

Another approach consists of extending the Predicate interface and providing a default method for testing and logging the failure cases as follows:

@FunctionalInterface
public interface LogPredicate<T> extends Predicate<T> {
  Logger logger = LoggerFactory.getLogger(LogPredicate.class);
 
  default boolean testAndLog(T t, String val) {
    boolean result = this.test(t);
    if (!result) {
      logger.warn(t + ” don’t match ‘” + val + “‘”);
    }
    return result;
  }
}

You can practice these examples in the bundled code.

190. Extending Stream with containsAll, containsAny

Let’s assume that we have the following code:

List<Car> cars = Arrays.asList(
  new Car(“Dacia”, “diesel”, 100),
  new Car(“Lexus”, “gasoline”, 300),
  …
  new Car(“Ford”, “electric”, 200)
);
     
Car car1 = new Car(“Lexus”, “diesel”, 300);
Car car2 = new Car(“Ford”, “electric”, 80);
Car car3 = new Car(“Chevrolet”, “electric”, 150);
List<Car> cars123 = List.of(car1, car2, car3);

Next, in the context of a stream pipeline, we want to check if cars contain all/any of the car1, car2, car3, or cars123.The Stream API comes with a rich set of intermediate and final operations but it doesn’t has a built-in containsAll()/containsAny(). So, it is our mission to provide the following final operations:

boolean contains(T item);
boolean containsAll(T… items);
boolean containsAll(List<? extends T> items);
boolean containsAll(Stream<? extends T> items);
boolean containsAny(T… items);
boolean containsAny(List<? extends T> items);
boolean containsAny(Stream<? extends T> items);

We highlighted the methods that get a Stream argument since these methods provide the main logic while the rest of the methods are just calling these ones after converting their arguments to a Stream.

Exposing constainsAll/Any() via a custom interface

The containsAll(Stream<? extends T> items) relies on a Set to accomplish its job as follows (you can challenge yourself to find an alternative implementation):

default boolean containsAll(Stream<? extends T> items) {
  Set<? extends T> set = toSet(items);
  if (set.isEmpty()) {
    return true;
  }
  return stream().filter(item -> set.remove(item))
                 .anyMatch(any -> set.isEmpty());
}

The containsAny(Stream<? extends T> items) relies also on a Set:

default boolean containsAny(Stream<? extends T> items) {
  Set<? extends T> set = toSet(items);
  if (set.isEmpty()) {
    return false;
  }
  return stream().anyMatch(set::contains);
}

The toSet() method is just a helper that collects the Stream items into a Set:

static <T> Set<T> toSet(Stream<? extends T> stream) {
  return stream.collect(Collectors.toSet());
}

Next, let’s sneak these codes into their final place which is a custom interface.As you can see, the containsAll(Stream<? extends T> items) and containsAny(Stream<? extends T> items) are declared as default which means that they are part of an interface. Moreover, both of them call the stream() method that is also part of this interface and hooks the regular Stream.Basically, a quick approach for solving this problem (especially useful in interviews) consists of writing this custom interface (let’s arbitrarily name it Streams) that has access to the original built-in Stream interface as follows:

@SuppressWarnings(“unchecked”)
public interface Streams<T> {
  Stream<T> stream();
  static <T> Streams<T> from(Stream<T> stream) {
    return () -> stream;
  }
  …

Next, the interface exposes a set of default methods that represent the containsAll()/containsAny() flavors as follows:

  default boolean contains(T item) {
    return stream().anyMatch(isEqual(item));
  }
  default boolean containsAll(T… items) {
    return containsAll(Stream.of(items));
  }
  default boolean containsAll(List<? extends T> items) {
    return containsAll(items.stream());
  }
  default boolean containsAll(Stream<? extends T> items) {
    … 
  }
  default boolean containsAny(T… items) {
    return containsAny(Stream.of(items));
  }
  default boolean containsAny(List<? extends T> items) {
    return containsAny(items.stream());
  }
  default boolean containsAny(Stream<? extends T> items) {
    …
  }
  static <T> Set<T> toSet(Stream<? extends T> stream) {
    …
  }
}

Done! Now, we can write different stream pipelines that use the brand new containsAll/Any() operations. For instance, if we want to check if cars contain all items from cars123, we express the stream pipeline as follows:

boolean result = Streams.from(cars.stream())
  .containsAll(cars123);

Here are several more examples:

boolean result = Streams.from(cars.stream())
  .containsAll(car1, car2, car3);
boolean result = Streams.from(cars.stream())
  .containsAny(car1, car2, car3);

Involving more operations can be done as in the following example:

Car car4 = new Car(“Mercedes”, “electric”, 200);      
boolean result = Streams.from(cars.stream()
    .filter(car->car.getBrand().equals(“Mercedes”))
    .distinct()
    .dropWhile(car -> car.getFuel().equals(“gasoline”))
  ).contains(car4);

A more expressive and complete solution to this problem will consist of extending the Stream interface. Let’s do it!

Extending Stream with removeAll, retainAll – Functional style programming – extending API

191. Extending Stream with removeAll, retainAll

Before reading this problem I strongly recommend you to read Problem 190.In Problem 190, we have extended the Stream API with two final operations named containsAll() and containsAny() via a custom interface and by extending the Stream API. In both cases, the resulting interface was named Streams. In this problem, we follow the same logic to implement two intermediate operations named removeAll() and retainAll() with the following signatures:

Streams<T> remove(T item);
Streams<T> removeAll(T… items);
Streams<T> removeAll(List<? extends T> items);
Streams<T> removeAll(Stream<? extends T> items);
Streams<T> retainAll(T… items);
Streams<T> retainAll(List<? extends T> items);
Streams<T> retainAll(Stream<? extends T> items);

Since removeAll() and retainAll() are intermediate operations they have to return Stream. More precisely, they have to return Streams which is our implementation based on a custom interface or an interface that extends Stream.

Exposing removeAll()/retainAll() via a custom interface

The removeAll(Stream<? extends T> items) relies on a Set to accomplish its job as follows (you can challenge yourself to find an alternative implementation):

default Streams<T> removeAll(Stream<? extends T> items) {
  Set<? extends T> set = toSet(items);
  if (set.isEmpty()) {
    return this;
  }
  return from(stream().filter(item -> !set.contains(item)));
}

The retainAll(Stream<? extends T> items) relies also on a Set:

default Streams<T> retainAll(Stream<? extends T> items) {
  Set<? extends T> set = toSet(items);
  if (set.isEmpty()) {
    return from(Stream.empty());
  }
  return from(stream().filter(item -> set.contains(item)));
}

The toSet() method is just a helper that collects the Stream items into a Set:

static <T> Set<T> toSet(Stream<? extends T> stream) {
  return stream.collect(Collectors.toSet());
}

Next, we can sneak these default methods in a custom interface named Streams exactly as we did in Problem 190:

@SuppressWarnings(“unchecked”)
public interface Streams<T> {
  Stream<T> stream();
  static <T> Streams<T> from(Stream<T> stream) {
    return () -> stream;
  }
  // removeAll()/retainAll() default methods and toSet()
}

There is a big problem with this implementation. The problem becomes obvious when we try to chain removeAll()/retainAll() in a stream pipeline next to other Stream operations. Because these two methods return Streams (not Stream) we cannot chain a Stream operation after them without calling before the Java built-in stream(). This is needed for switching from Streams to Stream. Here is an example (cars, car1, car2, car3, and car123 have been introduced in Problem 190):

Streams.from(cars.stream())
  .retainAll(cars123)
  .removeAll(car1, car3)
  .stream()
  .forEach(System.out::println);

The problem becomes even worse if we have to alternate between Streams and Stream multiple times. Check out this zombie:

Streams.from(Streams.from(cars.stream().distinct())
  .retainAll(car1, car2, car3)
  .stream()
  .filter(car -> car.getFuel().equals(“electric”)))
  .removeAll(car2)
  .stream()
  .forEach(System.out::println);

This hack is not a happy choice for enriching the Stream API with intermediate operations. However, it works quite well for terminal operations. So, the proper approach is to extend the Stream interface.

Exposing removeAll/retainAll() via an extension of Stream

We already know from Problem 190 how to extend the Stream interface. The implementation of removeAll() is also straightforward:

@SuppressWarnings(“unchecked”)
public interface Streams<T> extends Stream<T> { 
  
  default Streams<T> remove(T item) {
    return removeAll(item);
  }
 
  default Streams<T> removeAll(T… items) {
    return removeAll(Stream.of(items));
  }
  default Streams<T> removeAll(List<? extends T> items) {
    return removeAll(items.stream());
  }
  default Streams<T> removeAll(Stream<? extends T> items) {
    Set<? extends T> set = toSet(items);
    if (set.isEmpty()) {
      return this;
    }
    return filter(item -> !set.contains(item))
      .onClose(items::close);
  }     
  …

And, retainAll() follows in the same manner:

  default Streams<T> retainAll(T… items) {
    return retainAll(Stream.of(items));
  }
  default Streams<T> retainAll(List<? extends T> items) {
    return retainAll(items.stream());
  }
  default Streams<T> retainAll(Stream<? extends T> items) {
    Set<? extends T> set = toSet(items);
    if (set.isEmpty()) {
      return from(Stream.empty());
    }
    return filter(item -> set.contains(item))
      .onClose(items::close);
  }
  …
}  

As you know from Problem 190, next we have to override all the Stream methods to return Streams. While this part is available in the bundled code, here is an example of using removeAll()/retainAll():

Streams.from(cars.stream())
  .distinct()              
  .retainAll(car1, car2, car3)
  .filter(car -> car.getFuel().equals(“electric”))              
  .removeAll(car2)              
  .forEach(System.out::println);

As you can see, this time the stream pipeline looks quite good. There is no need to perform switches between Streams and Stream via stream() calls. So, mission accomplished!

Introducing stream comparators – Functional style programming – extending API

192. Introducing stream comparators

Let’s assume that we have the following three lists (a list of numbers, a list of strings, and a list of Car):

List<Integer> nrs = new ArrayList<>();
List<String> strs = new ArrayList<>();
List<Car> cars = List.of(…);
public class Car {
  private final String brand;
  private final String fuel;
  private final int horsepower;
  …
}

Next, we want to sort these lists in a stream pipeline.

Sorting via natural order

Sorting via natural order is very simple. All we have to do is to call the built-in intermediate operation, sorted():

nrs.stream()
   .sorted()
   .forEach(System.out::println);
strs.stream()
    .sorted()
    .forEach(System.out::println);

If nrs contains 1, 6, 3, 8, 2, 3, and 0 then sorted() will produce 0, 1, 2, 3, 3, 6, and 8. So, for numbers, the natural order is the ascending order by value.If strs contains “book”, “old”, “new”, “quiz”, “around”, and “tick” then sorted() will produce “around”, “book”, “new”, “old”, “quiz”, and “tick”. So, for strings, the natural order is the alphabetical order.The same result can be obtained if we explicitly call the Integer#compareTo() and String#compareTo() via sorted(Comparator<? super T> comparator):

nrs.stream()
   .sorted((n1, n2) -> n1.compareTo(n2))
   .forEach(System.out::println);
strs.stream()
    .sorted((s1, s2) -> s1.compareTo(s2))
    .forEach(System.out::println);

Or, we can use the java.​util.​Comparator functional interface, as follows:

nrs.stream()
   .sorted(Comparator.naturalOrder())
   .forEach(System.out::println);
strs.stream()
    .sorted(Comparator.naturalOrder())
    .forEach(System.out::println);

All these three approaches return the same result.

Reversing the natural order

Reversing the natural order can be done via Comparator.reverseOrder() as follows:

nrs.stream()
   .sorted(Comparator.reverseOrder())
   .forEach(System.out::println);
strs.stream()
    .sorted(Comparator.reverseOrder())
    .forEach(System.out::println);

If nrs contains 1, 6, 3, 8, 2, 3, and 0 then sorted() will produce 8, 6, 3, 3, 2, 1, and 0. Reversing the natural order of numbers results in descending order by value.If strs contains “book”, “old”, “new”, “quiz”, “around”, and “tick” then sorted() will produce “tick”, “quiz”, “old”, “new”, “book”, and “around”. So, for strings, reversing the natural order results in reversing the alphabetical order.

Sorting and nulls

If nrs/strs contains null values as well then all the previous examples will throw a NullPointerException. But, java.util.Comparator exposes two methods that allow us to sort null values first (nullsFirst(Comparator<? super T> comparator)) or last (nullsLast(Comparator<? super T> comparator)). They can be used as in the following examples:

nrs.stream()
   .sorted(Comparator.nullsFirst(Comparator.naturalOrder()))
   .forEach(System.out::println);
nrs.stream()
   .sorted(Comparator.nullsLast(Comparator.naturalOrder()))
   .forEach(System.out::println);
nrs.stream()
   .sorted(Comparator.nullsFirst(Comparator.reverseOrder()))
   .forEach(System.out::println);

The third example sorts the null values first followed by the numbers in reverse order.

Writing custom comparators

Sometimes we need a custom comparator. For instance, if we want to sort strs ascending by the last character then we can write a custom comparator as follows:

strs.stream()
    .sorted((s1, s2) ->
       Character.compare(s1.charAt(s1.length() – 1),
                         s2.charAt(s2.length() – 1)))
    .forEach(System.out::println);

If strs contains “book”, “old”, “new”, “quiz”, “around”, and “tick” then sorted() will produce “old”, “around”, “book”, “tick”, “new”, and “quiz”.But, custom comparators are typically used to sort our models. For instance, if we need to sort the cars list then we need to define a comparator. We cannot just say:

cars.stream()
    .sorted()
    .forEach(System.out::println);

This will not compile because there is no comparator for Car objects. An approach consists of implementing the Comparable interface and overriding the compareTo(Car c) method. For instance, if we want to sort cars ascending by horsepower then we start by implementing Comparable as follows:

public class Car implements Comparable<Car> {
  …
  @Override
  public int compareTo(Car c) {
    return this.getHorsepower() > c.getHorsepower()
      ? 1 : this.getHorsepower() < c.getHorsepower() ? -1 : 0;
  }
}

Now, we can successfully write this:

cars.stream()
    .sorted()
    .forEach(System.out::println);

Alternatively, if we cannot alter the Car code, we can try to use one of the existing Comparator methods that allow us to push a function that contains the sort key and returns a Comparator that automatically compares by that key. Since horsepower is an integer, we can use comparingInt(ToIntFunction<? super T> keyExtractor) as follows:

cars.stream()               
    .sorted(Comparator.comparingInt(Car::getHorsepower))
    .forEach(System.out::println);

Or, in reverse order:

cars.stream()
    .sorted(Comparator.comparingInt(
            Car::getHorsepower).reversed())
    .forEach(System.out::println);

You may also be interested in comparingLong(ToLongFunction) and comparingDouble(ToDoubleFunction). The ToIntFunction, ToLongFunction, and ToDoubleFunction are specializations of the Function. In this context, we can say that comparingInt(),comparingLong(), and comparingDouble() are specializations of comparing() which comes in two flavors: comparing(Function<? super T,? extends U> keyExtractor), and comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator).Here is an example of using the second flavor of comparing() for sorting cars ascending by fuel type (natural order) with null values placed at the end:

cars.stream()
    .sorted(Comparator.comparing(Car::getFuel,
            Comparator.nullsLast(Comparator.naturalOrder())))
    .forEach(System.out::println);

And, here is another example for sorting cars ascending by the last character of fuel type with null values placed at the end:

cars.stream()
    .sorted(Comparator.comparing(Car::getFuel,
            Comparator.nullsLast((s1, s2) ->
              Character.compare(s1.charAt(s1.length() – 1),
                                s2.charAt(s2.length() – 1)))))
    .forEach(System.out::println);

Done! In the next problem, we will sort a map.