Monday, August 28, 2017

Java 8 - Compound encapsulation


In previous articles , we know how to write method references and different method interfaces. Well , Those stuffs are only a substitute of java 7 syntax, it seems that doesn't bring much of convenience. 

In this article , I will make use of what we learn about method reference and method interfaces before and talk about how we use it in our real project scenarios.


Compound Comparator

In java 7 , if we want to sort a collection, we can't do so much but write a anonymous class of comparator interface and this can only compare once. like :

Comparator<String> com = new Comparator<String>() {
       @Override
       public int compare(String o1, String o2) {
          return 0;
 }
};

In java 8, you not only can encapsulate the comparator but can cascade the comparsion as well :


List<Apple> inventory = new ArrayList<>();

// if  ur comparator is complex, pick it out to encapsulate  
Comparator<Apple> c = Comparator.comparing(Apple::getWeight);

// if ur comparator is a reverse order of weight   
inventory.sort( Comparator.comparing(Apple::getWeight).reversed() );
  
// if u encounter same weight , u want to sort in country asc order again.
inventory.sort( Comparator.comparing(Apple::getWeight)
                          .reversed()
                          .thenComparing(Apple::getCountry));

Compound Predicate<T>

Predicate as we all know is a boolean judgement tool in previous article. Normally, we use boolean in if statement with lots of conditions :


if (apple.getWeight() > 120 && apple.getWeight() < 140 
                                                   || apple.getCountry().contains("US")) {
    ...
}

In Java 8 , it can fulfill all your requirements :


public static void main(String[] args) {
  
   // whether it is red apple.
   Predicate<Apple> redApple = Apple::getRedApple;
  
   // whether it is not red apple,  // math negation
   Predicate<Apple> notRedApple = redApple.negate();
  
   // whether it is red and heavy apple,  // math conjunction
   Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150);
  
   // whether it is red and heavy or green apple, // math conjunction and disjunction 
   Predicate<Apple> redAndHeavyAppleOrGreen = redApple.and(a -> a.getWeight() > 150)                                                    .or(a -> "green".equals(a.getColor()));
}

Note: and and or follow order from left to right , so a.or(b).and(c)  equals (a || b) && c

Compound Function<F,T> 

In previous article , we know that Function interface is used to retrive something from an Object. So of course, we can do some cascading manipulations like : retrive a from b after retrival  & validation from c. it has 2 default methods : andThen and compose.

This is call pipeline , or assembly line or flow line production.

public static void main(String[] args) {
  Function<Integer, Integer> f = x -> x + 1;
  Function<Integer, Integer> g = x -> x * 2;
  Function<Integer, Integer> h = f.andThen(g); // g(f(x)), do f first and g second
  int result = h.apply(1); // return 4 
}


public static void main(String[] args) {
   Function<Integer, Integer> f = x -> x + 1;
   Function<Integer, Integer> g = x -> x * 2;
   Function<Integer, Integer> h = f.compose(g); // f(g(x)), do g first f second
   int result = h.apply(1); // return 3
}

Alright , ok you may realise it is so simple , because in real project, we don't do math computation at all, the example below is how to use it in real project :

public class Letter {
  public static String addHeader(String text){
     return "From Raoul, Mario and Alan: " + text;
  }
  public static String addFooter(String text){
     return text + " Kind regards";
  }
  public static String checkSpelling(String text){
     return text.replaceAll("labda", "lambda");
  }
} 

Ok the above is the letter utility class, let's create our own  first flow line:


Function<String, String> addHeader = Letter::addHeader;
Function<String, String> transformationPipeline = addHeader.andThen(Letter::checkSpelling)
                                                           .andThen(Letter::addFooter);

Ok , we may need another flow line only needing addHeader and footer but without checkSpelling:


Function<String, String> addHeader = Letter::addHeader;
Function<String, String> transformationPipeline = addHeader.andThen(Letter::addFooter);

Conclusion 

From this article , you may find  lamda expression give much of help on the encapsulation of the flow and procedure, you may find it useful or useless, but try to approach the lamda way of encapsulation in your work ,  gradually you will realise the convenience and like it .

It is a process of thinking reformation and it need some time to practice.

No comments:

Post a Comment

Add Loading Spinner for web request.

when web page is busily loading. normally we need to add a spinner for the user to kill their waiting impatience. Here, 2 steps we need to d...