Chong's

Chong's

Domaine en aide à la décision, machine learning et SAP technical architecture

Java 8 Lambda expression

Today, I’m going to show you a little bit of lambda expression in Java 8.

Well, the lambda expression has been added for replace the Anonymous function, sometimes, the anonymous function can be such fat..

an exemple:

new Thread(new Runnable() {
    @Override
    public void run() {
    System.out.println("this is an anonymous function");
    }
}).start();

with lambda expression:

new Thread(()->System.out.println("this is a lambda expression!")).start();

Lambda expression

the official Grammar is:

(parameters) -> expression
(parameters) ->{ statements; }

there is a couple of exemples

() -> something()
x -> something()
(x,y) -> something()
9 -> {something(); something()}

There is an exemple with Function,

mathematically f.andThen(g) is g(f(x)) or (g \circ f)(x), f.compose(g) is f(g(x)) of (f \circ g)(x)


		 /**
		 * Exemple 1
		 */
		System.out.println("Exemple1");
		//f(x) = 3x+6
		Function<Double,Double> f = x -> 3 * x + 6;
		//g(x) = 4x^2
		Function<Double,Double> g = x -> 4 * Math.pow(x, 2);
		
		//f2(x) = 4(3x+6)^2
		Function<Double,Double> f2 = f.andThen(g);
		//g2(g) = 3*(4x^2)+6
		Function<Double,Double> g2 = f.compose(g);
		
		// 3 * 2 + 6 = 12.0
		System.out.println(f.apply(2.0));
		// 4 * (2^2) = 16.0
		System.out.println(g.apply(2.0));
		// 4( 3 * 2 + 6 )^ 2 = 576.0
		System.out.println(f2.apply(2.0));
		// 3 * (4 * (2^2))+ 6 = 54.0
		System.out.println(g2.apply(2.0));
		
		//f3 = f2 = 4(3x+6)^2, 
		//please look here, the parameter is a function,
		Function<Double,Double> f3 = f.andThen(x -> 4 * Math.pow(x, 2));
		//576 the same as before f.andThen(g)
		System.out.println(f3.apply(2.0));
		
		

2nd Exemple with comparator

		/**
		 * Exemple 2
		 */
		System.out.println("Exemple2");
		//a list 
		List<Integer> list = Arrays.asList(1,4,7,2,5,8,3,6,9,0);
		
		
		//This is a comparator, 
		Comparator<Integer> S2B = new Comparator<Integer>(){
			@Override
			public int compare(Integer o1, Integer o2) {
				return o1 -o2;
			}};
			
		//of course you can use l.sort() or Collection.sort()
		//but as these methods are void, it will change the original order
		//so I use stream, it means I create a new list, 
		//and this list has the same elements as original list, but sorted.
		Function<List<Integer>,List<Integer>> sortS2B = l -> l.stream().sorted(S2B).collect(Collectors.toList());
		Function<List<Integer>, List<Integer>> sortB2S = l -> l.stream().sorted(S2B.reversed()).collect(Collectors.toList());
		
		
		//Showing you the list by order increase 
		System.out.println(sortS2B.apply(list));
		//showing you the list by order decrease
		System.out.println(sortB2S.apply(list));
		//original list:
		System.out.println(list);
		
		//or you can just call l.get(0), I'm using stream, because stream is a new part of java 8
		//and by using findFirst, it will return an Optional<T> which will showed as 
		//an Optional<Integer> in my exemple, Optional.orElse(x) means, if this value that in this
		//Optional is NOT null, then show you the value, if not, it will show you a "default value"
		//,so in my exemple the "default value" is -1
		//if you use l.get(0), it will be find in my exemple, but sometimes we have to check the value
		//so the statement has to be l -> {if(l.get(0)!= null) return l.get(0); else return -1;};
		Function<List<Integer>,Integer> first = l -> l.stream().findFirst().orElse(-1);
		
		//with a empty list, it will show you -1
		System.out.println(first.apply(new ArrayList<Integer>()));
		
		//I apply first on the original list 1,4,7,2,5,8,3,6,9,0, so it will show you 1
		System.out.println(first.apply(list));
		//I apply sortS2B ant then first on the list
		//it means sort the list, then find the first
		//so it will be 0
		System.out.println(sortS2B.andThen(first).apply(list));
		//it will find 9
		System.out.println(sortB2S.andThen(first).apply(list));
		

3rd exemple will show you how the sort works with lambda expression

		/*
		 * Exemple 3
		 */
		
		System.out.println("Exemple3");
		
		//Now I'll show you the lambda expression...
		Function<List<Integer>,List<Integer>> sortS2B2 = l -> l.stream().sorted((x,y) -> x-y).collect(Collectors.toList());
		Function<List<Integer>,List<Integer>> sortB2S2 = l -> l.stream().sorted((x,y) -> y-x).collect(Collectors.toList());
		//Look the sorted part, the method compare(int x, int y) becomes (x,y) -> x-y, 
		//compare is a function, so we can pass this function as parameter
		
		System.out.println(sortS2B2.apply(list));
		System.out.println(sortB2S2.apply(list));
		
		//sort the list and take the first element
		System.out.println(sortS2B2.andThen(l -> l.stream().findFirst().orElse(-1)).apply(list));
		System.out.println(sortB2S2.andThen(l -> l.stream().findFirst().orElse(-1)).apply(list));

4th, an ugly exemple

		 /*
		 * Exemple 4
		 */
		
		System.out.println("Exemple 4");
		//I made a list of integer 0 to 199
		//IntStream is a stream which makes int
		//iterate(0, i -> i+1), from 0 and each element +1
		//or you can use IntStream.range(0,200) without limit, I just show you methods as more as possible
		//limit(200) I will take only 200,
		//boxed() int to integer
		//collect() toList
		List<Integer> t2t = IntStream.iterate(0, i -> i+1).limit(200).boxed().collect(Collectors.toList());
		
		
		//look what I've got
		System.out.println(t2t);
		
		//Now I'm going to make an ugly function to show you a little bit more
		//I made a bifunction which needs two list<Integer> as parameters, and return a String
		BiFunction<List<Integer>,List<Integer>,String> int2Char =  
				//(x,y) means the parameters,
				(x,y) -> x.stream()
				//new I made a stream from x, the first list
						.map(i -> i + y.stream().mapToInt(Integer::intValue).sum())
				//each element, in the list x, I made it added the total sum of list y
						.map(i -> (char)i.intValue())
						//and I made it return the char of this int
						.collect(Collectors.toList())
						//catch all char in a list
						.stream().map(i -> i.toString())
						//a stream for chars, and each char become to String
						.reduce((acc, e) -> acc  + e).get();
						//get the string final
						
		//What an ugly exemple, I suppose that you will realize the same thing in you life
				//this one just an exemple, I've made it for fun
		
		//show you the final string												
		System.out.println(int2Char.apply(t2t, list));	

reduce

reduce is the most important method, I’d like to give you an exemple:

				/**
		 * Exemple 5
		 */
		//reduce is fold (also termed reduce, accumulate, aggregate, compress, or inject) refers to 
		//a family of higher-order functions that analyze a recursive data structure and through use 
		//of a given combining operation, recombine the results of recursively processing its constituent 
		//parts, building up a return value. 
		//via wiki

		//Actually, the methods as sum(), max(), min(), they are implementations by using reduce
		
		System.out.println("Exemple5");
		
		System.out.println(IntStream.rangeClosed(1, 10).sum());
		
		System.out.println(IntStream.rangeClosed(1, 10).count());
		
		System.out.println(IntStream.rangeClosed(1, 10).max().orElse(-1));
		
		System.out.println(IntStream.rangeClosed(1, 10).min().orElse(-1));
		
		
		//reduce has two overloads with IntStream, one is with only one parameter, anther one is with two,
		//reduce(operation) or reduce(initValue,operation)
		//the only different is the second one has an initial value, some time we have to have one
		//
		//there is 3rd overload, I'll show you later.
		

		//sum by reduce, if you remove 0, the default value, it will return an optional<Integer>
		System.out.println(IntStream.rangeClosed(1, 10).reduce(0, (x,y)-> x+y));
		//count by reduce
		System.out.println(IntStream.rangeClosed(1, 10).reduce(0, (x,y)-> {return y = ++x;}));
		//max by reduce, I set mini value as the default value 
		System.out.println(IntStream.rangeClosed(1, 10).reduce(Integer.MIN_VALUE, (x,y)-> {return x>y ? x:y;}));
		//min by reduce, I didn't set the default value, 
		System.out.println(IntStream.rangeClosed(1, 10).reduce( (x,y)-> {return x<y ? x:y;}).orElse(-1));
		
		
		
		
		//this is the reduce with 3 parameters,
		//this one is a little bit difficult, the other reduces can only return a value which has 
		//the same value as the input, but this one can return what you want
		//just make sure the second parameter and the 3rd have the same type as output
		//this exemple is the same functionality as collect(Collectors.toList()),
		//it just shows you how the reduce works,
		//the initial value is an ArrayList, an empty list of course as the first couple:(list, Integer)
		//second parameter is a function which will put the integer into the list, and return the list
		//for the next couple,
		//3rd parameter, is useless for us, it will work only we use .parallel() as stream().
		//so it's why I return an null
		//this exemple can be used with paralel(), because of ArrayList, it's not a thread safe collection
		System.out.println(IntStream.rangeClosed(1, 10).boxed()
			.reduce(new ArrayList<Integer>()
					, (List<Integer> x, Integer y) -> 
									{x.add(y); return x;}
					, (List<Integer> x, List<Integer> y) -> {return null;}));
		
		//the same as Above
		System.out.println(IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toCollection(ArrayList::new)));
		//if you don't care about of which list implementation,
		System.out.println(IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toList()));
		

Source code

Source code de Reduce