Wednesday, 8 July 2015

CompletableFuture VS ParallelStream

CompletableFuture can be a complex concept if taken by itself, so I will use a simple example here to show for one business requirement, how to use it, when to use it and what is the difference comparing to parallelStream.

The requirement is as follows :

Build a list of promotion Strings. For each one you need to send an email to all the customers with the promotion. You also need to send an email to the Boss saying that promotions have been applied today.

The boss email and the customers emails are independent to each others and should not wait on either completion.

The base algorithm is this one  :

public static void main(String[] args) throws InterruptedException {
 List<String> promotions = Arrays.asList("Pizza Discount : ",
                                                 "Beer Discount : ",  
                                                 "Coke Discount : ", 
                                                 "Service Discount : ");
 old(promotions);
}

public static void old(List<String> promotions) {
 for (String promotion : promotions) {
  promotion = promotion + "30%";
  promotion = promotion + " Valid only Today";
  sendEmailToCustomers(promotion);
 }

 sendEmailToTheBoss("Today discount was 30%");
}



Let assume that sending an email takes 1 second :

public static void sendEmailToCustomers(String promotion) {
 try {
  Thread.sleep(1000);
  System.out.println("Email sent to customer for promotion : " + promotion);
 } catch (InterruptedException e) {
 }
}

public static void sendEmailToTheBoss(String promotion) {
 try {
  Thread.sleep(1000);
  System.out.println("Email sent to Boss for promotion : " + promotion);
 } catch (InterruptedException e) {
 }
} 
 
For each promotion we add the discount percentage. Then we add the day of when the discount is valid. Lastly we send the emails to all the customers. At the end we send the email to the Boss.

We can improve the speed of the algorithm parallelizing the process of sending emails to the customers using parallelStream :

public static void ps(List<String> promotions) throws InterruptedException {
 promotions.parallelStream()
                .map(promotion -> promotion + "30%")
                .map(promotion -> promotion + " Valid only Today")
                .forEach(promotion -> sendEmailToCustomers(promotion)); 
 
        sendEmailToTheBoss("Today discount was 30%");
}

Fantastic, now the promotions are sent in parallel, so it will take much less.

But we still have a requirement to fulfill, customers and Boss don't want to wait on each other to receive their emails.

Here the CompletableFuture comes in handy :

public static void cf(List<String> promotions) throws InterruptedException {
       CompletableFuture[] futures = promotions.stream()
             .map(promotion -> CompletableFuture.supplyAsync(() -> promotion + "30%"))
             .map(future -> future.thenApplyAsync((promotion) -> promotion + " Valid only Today"))
             .map(future -> future.thenAcceptAsync(promotion -> {
                    sendEmailToCustomers((String) promotion);
                  }))
             .toArray(CompletableFuture[]::new);

 sendEmailToTheBoss("Today discount was 30%");

 CompletableFuture.allOf(futures).join();
}

We composed our completableFutures based on the steps necessary to build the promotion.
The last step of the chain is to send the emails to the customers.

Everything is asynchronous here and CompletableFuture[] futures holds the composed completableFutures.
When the jvm rich the line sendEmailToTheBoss("Today discount was 30%"); , some of the customers email will be already sent and some are still to be sent, but we don't care to wait, we just want to acknowledge our Boss that promotions were generated.

The last line CompletableFuture.allOf(futures).join(); is because before leaving this method we want to wait for all the emails to be sent to the customers.

So, running all the methods above :

System.out.println("-------OLD-------");
old(promotions);
System.out.println("-------PARALLEL STREAM-------");
ps(promotions);
System.out.println("-------COMPLETABLE FUTURE-------");
cf(promotions);

The output will be

-------OLD-------
Email sent to customer for promotion : Pizza Discount : 30% Valid only Today
Email sent to customer for promotion : Beer Discount : 30% Valid only Today
Email sent to customer for promotion : Coke Discount : 30% Valid only Today
Email sent to customer for promotion : Service Discount : 30% Valid only Today
Email sent to Boss for promotion : Today discount was 30%
-------PARALLEL STREAM-------
Email sent to customer for promotion : Service Discount : 30% Valid only Today
Email sent to customer for promotion : Coke Discount : 30% Valid only Today
Email sent to customer for promotion : Beer Discount : 30% Valid only Today
Email sent to customer for promotion : Pizza Discount : 30% Valid only Today
Email sent to Boss for promotion : Today discount was 30%
-------COMPLETABLE FUTURE-------
Email sent to customer for promotion : Pizza Discount : 30% Valid only Today
Email sent to customer for promotion : Beer Discount : 30% Valid only Today
Email sent to Boss for promotion : Today discount was 30%
Email sent to customer for promotion : Coke Discount : 30% Valid only Today
Email sent to customer for promotion : Service Discount : 30% Valid only Today







Thursday, 25 June 2015

Strategy Pattern in Java 8

These are two examples on how to implement a Strategy pattern design using Java 8 functional style together with Cyclops pattern matching and Hamcrest libraries.

PrintDependingOnInput method is a strategy that will System.println some message based on the log passed.

AddPrefix is another strategy that will add a prefix to a message based on the message content.

package com.marco.patternmatching; 

 

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.hamcrest.core.AllOf.allOf;
import java.util.ArrayList;
import java.util.List;
import com.aol.cyclops.matcher.builders.Matching; 

 

public class FunctionalStrategy {

  public static void main(String[] args) {
     List<String> toTest = new ArrayList<>();
     toTest.add("INFO everything is fine");
     toTest.add("WARN something weird happened");
     toTest.add("ERROR NullPointerException");
     toTest.add("ERROR IOException");
     
     toTest.stream().forEach(FunctionalStrategy::printDependingOnInput);

     System.out.println("--------------------");

     List<String> messages = new ArrayList<>();
     messages.add("everything is fine");
     messages.add("something weird happened");
     messages.add("NullPointerException");
     messages.add("IOException");

     messages.stream().map(FunctionalStrategy::addPrefix).forEach(System.out::println);
  }

        
  public static void printDependingOnInput(String log) {

     Matching
        .when().isMatch(startsWith("INFO"))
                   .thenConsume(System.out::println)
        .when().isMatch(startsWith("WARN"))
                   .thenConsume(message -> System.out.println("Found one warning : " + message))
        .when().isMatch(allOf(startsWith("ERROR"), containsString("NullPointerException")))
                   .thenConsume(message -> System.err.println(message))
        .when().isMatch(allOf(startsWith("ERROR"), containsString("IOException")))
                   .thenConsume(message -> System.err.println(message + " Retrying a couple of times"))
        .match(log);

   }

   public static String addPrefix(String log) {

     return Matching
        .when().isMatch(allOf(not(containsString("Exception")), not(containsString("weird"))))
                    .thenApply(message -> "INFO " + message)
        .when().isMatch(containsString("weird"))
                    .thenApply(message -> "WARN " + message)
        .when().isMatch(containsString("Exception"))
                    .thenApply(message -> "ERROR " + message)
        .match(log).get();

  }
}


Nice and clean ;)

Tuesday, 16 June 2015

Java 8 and how Optional removes the need for == null

I was confused initially when the Optional concept entered the Java world.
I was wondering how the hell can Optional remove the need to check for null? At some point I will need to use optional.isPresent() before using whatever is inside. So what's the point to replace == null with isPresent()?


The main concept to keep in mind is that Optional is a monad and as a monad contains map(), flatmap(), filter() and other methods that can be used directly against the optional instance.


Here, with the following simple code, I hope I will clarify a bit more the power of java.util.Optional.

In this example we have a list of logs and we want to apply 3 different operations based on the the type of log (INFO, ERROR, WARN).


package com.marco.optional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class TestOptional {

        public static void main(String[] args) {
                List<Optional<String>> logs = new ArrayList<Optional<String>>();
                logs.add(Optional.ofNullable("INFO:: some info here 1"));
                logs.add(Optional.ofNullable("INFO:: some info here 2"));
                logs.add(Optional.ofNullable("ERROR:: some error here 3"));
                logs.add(Optional.ofNullable("INFO:: some info here 4"));
                logs.add(Optional.ofNullable("WARN:: some info here 5"));
                logs.add(Optional.ofNullable(null));
                logs.add(Optional.ofNullable("INFO:: some info here 7"));
                logs.add(Optional.ofNullable("WARN:: some info here 8"));

                for (Optional<String> singleLog : logs) {
                        printErrors(singleLog);
                        printInfos(singleLog);
                        printWarnOnlyNumber(singleLog);
                }

        }

        public static void printErrors(Optional<String> singleLog) {
                singleLog.filter(entry -> entry.startsWith("ERROR")).ifPresent(System.out::println);
        }

        public static void printInfos(Optional<String> singleLog) {
                singleLog.filter(entry -> entry.startsWith("INFO")).ifPresent(System.out::println);
        }

        public static void printWarnOnlyNumber(Optional<String> singleLog) {
                singleLog.filter(entry -> entry.startsWith("WARN"))

                          .map(warn -> warn.substring(warn.length() - 1))

                          .ifPresent(System.out::println);
        }
}

Output :


INFO:: some info here 1
INFO:: some info here 2
ERROR:: some error here 3
INFO:: some info here 4
5
INFO:: some info here 7
8


No == null and no if

Optional takes care of it for you ;)

Friday, 12 June 2015

Java 8, easier with Cyclops : Try


Cyclops is another promising open source library from John McClean in AOL, that aims to extends and simplify Java 8 functionality.

One of its feature is Try that offers an alternative way to manage exception handling.

Imagine you have a method that load files from some location :

private List<File> loadFiles() { 
     return Lists.newArrayList(new File("somePath_one"), new File("somePath_two"));
} 

Many things could go wrong there, file does not exist, network is down, etc.
 
Traditionally, we could have manage exceptions surrounding the loadFiles() method with try and catch and handle each exception within a catch statement.

Cyclops Try made things easier and cleaner :

Try.withCatch(this::loadFiles, Exception.class)


    .onFail(FileNotFoundException.class, e -> System.err.println("Something specific to do here if file does not exists" + e))


    .onFail(IOException.class, e -> System.err.println("Maybe retry a couple of times before dropping the operation" + e))


    .forEach(System.out::println);

Based on the exception, different functions can be triggered.

http://media.giphy.com/media/U0uowJVj7ewO4/giphy.gif

Thursday, 11 June 2015

10 team building tips

1) Good Morning


http://media.giphy.com/media/RbVOveSAHkk2A/giphy.gif

When you enter in the office, before sitting on your desk, smile and say good morning to the team. Yes, E V E R Y day.

2) Listen when someone is talking to you.

http://media.giphy.com/media/kwNSxdqqutsEE/giphy.gif

When a team member is talking to you, look him in the eyes and show interest in what he is saying.

3) Give space, build trust


http://media.giphy.com/media/HdsLiowsPuoso/giphy.gif

Let team member fail sometimes and repair from their failures.
You may be always right, but who cares?! Other people need to learn to fail and take responsibilities.


4) Connect


http://media.giphy.com/media/LPAohuvTif0ek/giphy.gif

Go and take a coffee with each person in the team separately.

5) Congratulate


http://media.giphy.com/media/IAFlOwj4XsNlm/giphy.gif

When someone does something good, tell her/him!

6) Keep your personal problems out of work.


 http://media.giphy.com/media/dIDae8s93pave/giphy.gif

Don't shout at people because your last evening was bad.

7) Do pair programming


http://media.giphy.com/media/ggKMDmjkGZ5ZK/giphy.gif

Great way to share knowledge and build solid work relationships.

8)  Feedback


http://media.giphy.com/media/ql89wsWoAgTAI/giphy.gif

Do code reviews without sounding the king of the programming universe. Explain in a calm and friendly tone whatever you want to say.

9) Have lunch together


http://media.giphy.com/media/PvBnBEr7CUUDK/giphy.gif

If possible go regularly to lunch with as many team members as possible.


10) See you tomorrow


http://media.giphy.com/media/77ggDHDT372j6/giphy.gif

When you leave in the evening, if you are not the last person in the team left, say goodbye.


Thursday, 4 June 2015

Memoize functions in java 8

Memoization is not a grammar error,  memoization is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.

http://en.wikipedia.org/wiki/Memoization

I will explain it with a simple example.

Context :

Table PIZZA, columns ID, NAME

We have a java function called "hereThePizzaGiveMeTheId" where you pass a String representing a pizza name and it will return the correspondent id retrieved from the DB.

Function<String, Integer> hereThePizzaGiveMeTheId = name -> {

            int pizzaId = -1;


            System.out.println("Select ID from PIZZA where name = '" + name + "'");

            pizzaId = pizzaDao.get(name);


            return pizzaId;

        };

Now, if I call this function with the same pizza name I will hit the DB each time :

        System.out.println(hereThePizzaGiveMeTheId.apply("Margherita"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Margherita"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Margherita"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Margherita"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Four Season"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Four Season"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Four Season"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Four Season"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Gorgonzola and figs"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Gorgonzola and figs"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Gorgonzola and figs"));
        System.out.println(hereThePizzaGiveMeTheId.apply("Gorgonzola and figs"));


OUTPUT:


Select ID from PIZZA where name = 'Margherita'
1
Select ID from PIZZA where name = 'Margherita'
1
Select ID from PIZZA where name = 'Margherita'
1
Select ID from PIZZA where name = 'Margherita'
1
Select ID from PIZZA where name = 'Four Season'
2
Select ID from PIZZA where name = 'Four Season'
2
Select ID from PIZZA where name = 'Four Season'
2
Select ID from PIZZA where name = 'Four Season'
2
Select ID from PIZZA where name = 'Gorgonzola and figs'
3
Select ID from PIZZA where name = 'Gorgonzola and figs'
3
Select ID from PIZZA where name = 'Gorgonzola and figs'
3
Select ID from PIZZA where name = 'Gorgonzola and figs'
3



Fantastic, but I don't want to run that function every time, if I already know the result based on the pizza name.
So, lets memoize (cache) the result of that function.

First we create a generic method that wraps a function into another function that will behave the same as the input one, but will check if the result is already computed : 

public static <X, Y> Function<X, Y> memoise(Function<X, Y> fn) {

        Map<X, Y> pp = new ConcurrentHashMap<X, Y>();

        return (a) -> pp.computeIfAbsent(a, fn);

    }


 Then we wrap our "hereThePizzaGiveMeTheId"  function :

Function<String, Integer> memoziedHereThePizzaGiveMeTheId = memoise(hereThePizzaGiveMeTheId);
 
Lastly, we call again the same logic as before, but using the new memoziedHereThePizzaGiveMeTheId function :

      
        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Margherita"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Margherita"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Margherita"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Margherita"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Four Season"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Four Season"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Four Season"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Four Season"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Gorgonzola and figs"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Gorgonzola and figs"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Gorgonzola and figs"));

        System.out.println(memoziedHereThePizzaGiveMeTheId.apply("Gorgonzola and figs"));



OUTPUT:

Select ID from PIZZA where name = 'Margherita'
1
1
1
1
Select ID from PIZZA where name = 'Four Season'
2
2
2
2
Select ID from PIZZA where name = 'Gorgonzola and figs'
3
3
3
3







We will hit the DB only if the result of the function is not already present in the map.

That's it.

p.s.

Gorgonzola and figs is a fantastic pizza :















Thursday, 14 May 2015

Simple benchmarking : Immutable Collections VS Persistent Collections

Often you need to add new elements to a collection.
Because you are a good and careful developer you want to keep things immutable as much as possible. So adding a new element to an immutable collections will mean that you have to create a new immutable collection that contains all the elements of the original collections plus the new element.

You can create immutable collections using the guava library and also using the recent pCollection library.

In the following example, we will build 2 immutable lists, one immutable from guava and one persistent from pCollection.

They both will contain 10.000 integers initially.

We will create 20.000 immutable lists one for each type and we will measure the time taken.


package com.marco.pcollections;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.pcollections.PCollection;
import org.pcollections.TreePVector;
import com.google.common.collect.ImmutableList;

public class PcollectionVSImmutable {
 public static void main(String[] args) {
  
  List<Integer> bigList = new ArrayList<Integer>();
  for (int i = 0; i < 10000; i++) {
   bigList.add(new Integer(i));
  }
  
  Map<Integer, ImmutableList<Object>> allImmutable = new HashMap<Integer, ImmutableList<Object>>();
  Map<Integer, PCollection<Integer>> allPersistent = new HashMap<Integer, PCollection<Integer>>();
  
  
  
  PCollection<Integer> persistent = TreePVector.from(bigList);
  long start = System.currentTimeMillis();
  for (int i = 10000; i < 30000; i++) {
   allPersistent.put(new Integer(i), persistent.plus(new Integer(i)));
  }
  System.out.println("creating 20.000 pCollections takes : " + (System.currentTimeMillis() - start) + "ms");
  
  
  ImmutableList<Integer> immutable = ImmutableList.copyOf(bigList);
  start = System.currentTimeMillis();
  for (int i = 10000; i < 30000; i++) {
   allImmutable.put(new Integer(i), ImmutableList.builder().addAll(immutable).add(new Integer(i)).build());
  }
  System.out.println("creating 20.000 Guava ImmutableList takes : " + (System.currentTimeMillis() - start) + "ms");
  
  System.out.println("All immutable size : " + allImmutable.size() + " allPersistent size : " + allPersistent.size());
 }
}


Output :

creating 20.000 pCollections takes : 29ms
creating 20.000 Guava ImmutableList takes : 18347ms
All immutable size : 20000 allPersistent size : 20000