Pages

Tuesday, July 3, 2018

How to use filter() method in Java 8

Java 8 Stream interface introduces filter() method which can be used to filter out some elements from object collection based on a particular condition. This condition should be specified as a predicate which the filter() method accepts as an argument.

The java.util.function.Predicate interface defines an abstract method named test() that accepts an object of generic type T and returns a boolean.

Let's do some coding to understand the filter method more clearly. Look at the following Dish class.

public class Dish {

     private String name;
     private Boolean vegitarian;
     private Integer calaries;
     private Type type;
 
     public Dish(String name, Boolean vegitarian, Integer calaries, Type type) {
          super();
          this.name = name;
          this.vegitarian = vegitarian;
          this.calaries = calaries;
          this.type = type;
     }

     public Boolean getVegitarian() {
         return vegitarian;
     }

     public void setVegitarian(Boolean vegitarian) {
         this.vegitarian = vegitarian;
     }

     public Type getType() {
         return type;
     }

     public void setType(Type type) {
         this.type = type;
     }

     public enum Type { MEAT, FISH, OTHER };
}


Let's think, we want to filter out only the vegetarian Dishes from a list of all Dishes. Following is the approach  before Java 8.

    List<Dish> vegetarianDishes = new ArrayList<Dish>(); 
    for(Dish d: menu) {
       if(d.getVegetarian()) { 
          vegetarianDishes.add(d);
       } 
    }

The above approach is called external iteration which we explicitly manage the iteration over the collection of data.

How this can be done with Java 8 ? It is just a matter of single line as follows.

List<Dish> menu = ....
List<Dish> vegitarianDishes = menu.stream()
                                    .filter(d -> d.getVegitarian())
                                    .collect(Collectors.toList());

We have passed a Predicate instance into the filter() method in a form of a Lambda expression.

Also, we can use java 8 method references to pass a Predicate instance to the filter() method as follows.
List<Dish> menu = ....
List<Dish> vegitarianDishes = menu.stream()
                                    .filter(Dish::getVegitarian)
                                    .collect(Collectors.toList());

Dish::getVegitarian is the syntax for Java 8 method references. It refers to the getVegitarian() method of Dish class. 

The filter() method returns a Stream of Dishes and the collect() method converts the Stream into a List. The 'collect' operation is called a terminal operation.

Now let's say, we want to get first three Dishes that have more than 300 calories. Streams support the limit(n) method, which returns another stream that’s no longer than a given size. The requested size is passed as argument to limit.

List<Dish> menu = ....
List<Dish> threeHighCalaricDish = menu.stream()
                                         .filter(d -> d.getCalaries() > 300)
                                         .limit(3)
                                         .collect(Collectors.toList());

Similarly, if we want to skip first 3 elements, streams support the skip(n) method to return a stream that discards the first n elements. If the stream has fewer elements than n, then an empty stream is returned. Note that limit(n) and skip(n) are complementary!

Now, an exercise for you ! How would you use streams to filter the first two meat dishes?
List<Dish> menu = ....
List<Dish> meatDishes = menu.stream()
                                  .filter(d -> d.getType() == Dish.Type.MEAT)
                                  .limit(2)
                                  .collect(Collectors.toList())

0 comments:

Post a Comment

Share

Widgets