Showing posts with label performance. Show all posts
Showing posts with label performance. Show all posts

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

Friday, 12 September 2014

Friday-Benchmarking Functional Java

Lets image your product owner goes crazy one day and he asks you to do the following :

From a set of Strings as follows :

"marco_8", "john_33", "marco_1", "john_33", "thomas_5", "john_33", "marco_4", ....

give me back a comma separated String with only the marco's numbers and numbers need to be in order. 

 Example of expected result :

"1,4,8"


I will implement this logic in 4 distinct ways and I will micro benchmark each one of them. The ways I'm going to implement the logic are :

  • Traditional java with loops and all.
  • Functional with Guava 
  • Functional with java 8 stream
  • Functional with java 8 parallelStream

Code is below or in gist


package com.marco.brownbag.functional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Ordering;
public class MicroBenchMarkFunctional {

        private static final int totStrings = 200000;

        public static void main(String[] args) {

                Set<String> someNames = new HashSet<String>();

                init(someNames);

                for (int i = 1; i < totStrings; i++) {
                        someNames.add("marco_" + i);
                        someNames.add("someone_else_" + i);
                }

                System.out.println("start");

                run(someNames);

        }

        private static void run(Set<String> someNames) {
                System.out.println("========================");
                long start = System.nanoTime();
                int totalLoops = 20;
                for (int i = 1; i < totalLoops; i++) {
                        classic(someNames);
                }
                System.out.println("Classic         : " + ((System.nanoTime() - start)) / totalLoops);

                start = System.nanoTime();
                for (int i = 1; i < totalLoops; i++) {
                        guava(someNames);
                }
                System.out.println("Guava           : " + ((System.nanoTime() - start)) / totalLoops);

                start = System.nanoTime();
                for (int i = 1; i < totalLoops; i++) {
                        stream(someNames);
                }
                System.out.println("Stream          : " + ((System.nanoTime() - start)) / totalLoops);

                start = System.nanoTime();
                for (int i = 1; i < totalLoops; i++) {
                        parallelStream(someNames);
                }
                System.out.println("Parallel Stream : " + ((System.nanoTime() - start)) / totalLoops);

                System.out.println("========================");
        }

        private static void init(Set<String> someNames) {
                someNames.add("marco_1");
                classic(someNames);
                guava(someNames);
                stream(someNames);
                parallelStream(someNames);
                someNames.clear();
        }

        private static String stream(Set<String> someNames) {
                return someNames.stream().filter(element -> element.startsWith("m")).map(element -> element.replaceAll("marco_", "")).sorted()
                                .collect(Collectors.joining(","));
        }

        private static String parallelStream(Set<String> someNames) {
                return someNames.parallelStream().filter(element -> element.startsWith("m")).map(element -> element.replaceAll("marco_", "")).sorted()
                                .collect(Collectors.joining(","));
        }

        private static String guava(Set<String> someNames) {
                return Joiner.on(',').join(
                                Ordering.from(String.CASE_INSENSITIVE_ORDER).immutableSortedCopy(
                                                Collections2.transform(Collections2.filter(someNames, Predicates.containsPattern("marco")), REPLACE_MARCO)));

        }

        private static Function<String, String> REPLACE_MARCO = new Function<String, String>() {
                @Override
                public String apply(final String element) {
                        return element.replaceAll("marco_", "");
                }
        };

        private static String classic(Set<String> someNames) {

                List<String> namesWithM = new ArrayList<String>();

                for (String element : someNames) {
                        if (element.startsWith("m")) {
                                namesWithM.add(element.replaceAll("marco_", ""));
                        }
                }

                Collections.sort(namesWithM);

                StringBuilder commaSeparetedString = new StringBuilder();

                Iterator<String> namesWithMIterator = namesWithM.iterator();
                while (namesWithMIterator.hasNext()) {
                        commaSeparetedString.append(namesWithMIterator.next());
                        if (namesWithMIterator.hasNext()) {
                                commaSeparetedString.append(",");
                        }

                }

                return commaSeparetedString.toString();

        }
}


Two points before we dig into performance :

  1. Forget about the init() method, that one is just to initialize objects in the jvm otherwise numbers are just crazy.
  2. The java 8 functional style looks nicer and cleaner than guava and than developing in a traditional way :).

Performance:



Running that program on my mac with 4 cores, the result is the following :


========================
Classic              : 151941400
Guava               : 238798150
Stream              : 151853850
Parallel Stream : 55724700
========================

Parallel Stream is 3 times faster. This is because java will split the job in multiple tasks (total of tasks depends on your machine, cores, etc) and will run them in parallel, aggregating the result at the end.
Classic Java and java 8 stream have more or less the same performance.
Guava is the looser.


That is amazing, so someone could think:
"cool, I can just always use parallelStream and I will have big bonus at the end of the year". 
But life is never easy. Here is what happens when you reduce that Set of strings from 200.000 to 20

========================
Classic              : 36950
Guava               : 69650
Stream              : 29850
Parallel Stream : 143350
========================

Parallel Stream became damn slow. This because parallelStream has a big overhead in terms of initializing and managing multitasking and assembling back the results.
Java 8 stream looks now the winner compare to the other 2.

Ok, at this point, someone could say something like :
"for collections with lots of elements I use parallelStream, otherwise I use stream"
That would be nice and simple to get, but what happens when I reduce that Set again from 20 to 2?
This :

========================
Classic              : 8500
Guava               : 20050
Stream              : 24700
Parallel Stream : 67850
========================

Classic java loops are faster with very few elements.

So at this point I can go back to my crazy product owner and ask how many Strings he thinks to have in that input collection. 20? less? more? much more?


Like the Carpenter says :

Measure Twice, Cut Once!!

 

 







Friday, 22 August 2014

Java 8 : Functional VS Traditional

The business logic is the same :

Given a String expression composed of visits / time like : "1/24h,1..3/3h,5/*"
Then the result should be the following list of Strings 
"1/24h",
"1/3h","2/3h","3/3h",
"5/1h","5/2h","5/3h","5/4h","5/5h",until ,"24/1h"


So, 2 things need to be solved, the dots and the stars for the visits and for the time.

I will use Java 8 , but  I'll show you the difference between implementing this logic using Functional  and implementing it in a traditional way with loops and ifs.

package com.marco;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
public class ExpressionConverter {
        private static final String COMMA = ",";
        private static final String SEPARATOR = "/";

        private final ImmutableList<Function<String, List<String>>> visitFunctions;
        private final ImmutableList<Function<String, List<String>>> timeFunctions;

        public ExpressionConverter(DotsVisitFunction dotsVisitFunction, StarVisitFunction starVisitFunction, StandardFunction standardFunction,
                        StarTimeFunction starTimeFunction) {
                this.visitFunctions = ImmutableList.of(dotsVisitFunction, starVisitFunction, standardFunction);
                this.timeFunctions = ImmutableList.of(starTimeFunction, standardFunction);
        }

        public List<String> convertVisitTimeExpressionFunctional(String visitTimeExpression) {
                return Lists.newArrayList(visitTimeExpression.split(COMMA)).parallelStream().filter(it -> !it.isEmpty())
                                .map(it -> interpretSingleExpressionFunctional(it)).flatMap(it -> it.parallelStream()).collect(Collectors.toList());
        }

        public List<String> convertVisitTimeExpressionTraditional(String visitTimeExpression) {
                List<String> result = new ArrayList<String>();

                for (String singleVisitTime : visitTimeExpression.split(COMMA)) {
                        if (!singleVisitTime.isEmpty()) {
                                result.addAll(interpretSingleVisitTimeExpressionTraditional(singleVisitTime));
                        }
                }

                return result;

        }

        private List<String> interpretSingleExpressionFunctional(String singleExpression) {
                String visit = singleExpression.split(SEPARATOR)[0];
                String time = singleExpression.split(SEPARATOR)[1];
                List<String> result = Lists.newArrayList();

                visitFunctions.stream().map(it -> it.apply(visit)).flatMap(it -> it.stream()).forEach(visitIt -> {
                        timeFunctions.stream().map(it -> it.apply(time)).flatMap(it -> it.stream()).forEach(timeIt -> {
                                result.add(visitIt + SEPARATOR + timeIt);
                        });
                });
                return result;
        }

        private List<String> interpretSingleVisitTimeExpressionTraditional(String singleExpression) {

                String visit = singleExpression.split(SEPARATOR)[0];
                String time = singleExpression.split(SEPARATOR)[1];

                List<String> result = Lists.newArrayList();
                List<String> visists = Lists.newArrayList();
                List<String> times = Lists.newArrayList();

                for (Function<String, List<String>> visitFunction : visitFunctions) {
                        visists.addAll(visitFunction.apply(visit));
                }
                for (Function<String, List<String>> timeFunction : timeFunctions) {
                        times.addAll(timeFunction.apply(time));
                }
                for (String visitIt : visists) {
                        for (String timeIt : times) {
                                result.add(visitIt + SEPARATOR + timeIt);
                        }
                }
                return result;
        }
}


As you can see we have 2 public and 2 private methods, functional and traditional.

Here is a simple test focusing on the performance of the two styles :

package com.marco;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
public class ExpressionConverterTest {

        private static final String EXPRESSIONS = "6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,6/7400,9/65h,55..57/14400";

        private Cache cache;

        private ExpressionConverter expressionConverter;

        @Before
        public void init() {
                cache = mock(Cache.class);
                expressionConverter = new ExpressionConverter(new DotsVisitFunction(cache), new StarVisitFunction(cache), new StandardFunction(),
                                new StarTimeFunction(cache));

                Set<Integer> totVisists = Sets.newHashSet();
                for (int i = 1; i <= 100; i++) {
                        totVisists.add(i);
                }

                when(cache.getVisits(anyLong(), (BigDecimal) any(), anyInt())).thenReturn(ImmutableSet.copyOf(totVisists));
        }

        @Test
        public void testPerf() {

                long averageTraditional = 0l;
                long averageFuntional = 0l;

                for (int a = 0; a < 10; a++) {
                        long start = System.currentTimeMillis();

                        for (int i = 0; i < 1000; i++) {
                                expressionConverter.convertVisitTimeExpressionTraditional(EXPRESSIONS);

                        }
                        System.out.println("Traditional java " + (System.currentTimeMillis() - start) + " ms");
                        averageTraditional += (System.currentTimeMillis() - start);

                        long start2 = System.currentTimeMillis();
                        for (int i = 0; i < 1000; i++) {
                                expressionConverter.convertVisitTimeExpressionFunctional(EXPRESSIONS);
                        }
                        System.out.println("Functional java " + (System.currentTimeMillis() - start2) + " ms");
                        averageFuntional += (System.currentTimeMillis() - start2);
                }

                System.out.println("Average Traditional java : " + (averageTraditional / 10) + " ms");
                System.out.println("Average Functional java : " + (averageFuntional / 10) + " ms");

        }
}
 
 
And this is the output :
Traditional java 1274 ms
Functional java 773 ms
Traditional java 1054 ms
Functional java 531 ms
Traditional java 961 ms
Functional java 493 ms
Traditional java 948 ms
Functional java 492 ms
Traditional java 949 ms
Functional java 491 ms
Traditional java 958 ms
Functional java 481 ms
Traditional java 1004 ms
Functional java 474 ms
Traditional java 949 ms
Functional java 471 ms
Traditional java 947 ms
Functional java 475 ms
Traditional java 942 ms
Functional java 472 ms
Average Traditional java : 998 ms
Average Functional java : 515 ms


Functional is 2 times faster than Traditional. Why?

Because of this : parallelStream()
Parallel Stream will split the job in several tasks leveraging your multicore system.
So can you put parallelStream() everywhere and replace all the stream() methods with parallelStream() ??

No!
The parallelStream()can in fact cause a big degradation of performance if used in the wrong place.
There are loads of posts out there on this argument that should be read before using this feature, but just remember, if you want to use parallelStream() make sure to measure the performance before and after!!!!!!!!!!