-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLambdaExamples.java
339 lines (268 loc) · 10.9 KB
/
LambdaExamples.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
package com.umang.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.TooManyListenersException;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static java.util.stream.Collectors.*;
public class LambdaExamples {
public static boolean isGreaterThan3(int number){
return number>3;
}
public boolean isEven(int number){
return number%2==0;
}
public static int compute(int number){
return number*2;
}
public void streamExample(){
List<Integer> numbers=Arrays.asList(1,2,34,56,7);
numbers.stream()
.filter(e -> e % 2==0) //take only even number
.mapToInt(LambdaExamples:: compute)//double the numbers
.sum();//sum it
//if u want to parallelize it use parallel stream
//this code will take less time to execute.
//When to use parallel stream
//when it make sense means problem is actually parallelizable
// when u willing to spend more resource to get faster result.
//when data size is big enough that u will get performance benefit
//when task comutation is big enough that u will get performance benefit
numbers.parallelStream()
.filter(e -> e % 2==0) //take only even number
.mapToInt(LambdaExamples:: compute)//double the numbers
.sum();//sum it
//stream is abstraction not data, data does not exist in stream its like non mutating pipeline.
numbers.stream()
.filter(e-> e%2==0)
.map(e -> e*2.0)
.reduce(0.0, (carry,num) ->carry+num);
//------- filter------
//no of elements in output is less than no of elements in input
//parameter: Stream<T> filter takes Filter<T> as input
//------map--------
//map transorms value
//no of output is equal to no of input.
//no guarantee of type of o/p with respect to type of input
//parameter: Stream<T> map takes Function<T,R> to return Stream<R>
//both filter and map stay within their swimlanes.
/* Filter map reduce
0.0
x1 | \
--------------------------- \
x2 -> x2' -> +
--------------------------- \
x3 | \
----------------------------- \
x4 -> x4' -> +
*/
//reduce cut across the swimlanes
//reduce convert stream to a single concrete value.
//reduce on Stream<T> takes 2 parameters
//first parameter is of type T
//second parameter is of type BiFunction<R,T,R> to produce a result of R.
//sum : a special reduce function
numbers.stream()
.filter(e-> e%2==0)
.mapToDouble(e -> e*2.0)
.sum();
//collect: special reduce function
//case: double the even values and put that into a list
List<Integer> doubleList=new ArrayList<>();
//wrong way to do this
numbers.stream()
.filter(e -> e%2==0)
.map(e->e*2)
.forEach(e -> doubleList.add(e));//dont do this as its shred mutability.
//mutability is ok, sharing is nice but shred mutability is devil
//good way is
numbers.stream()
.filter(e -> e%2==0)
.map(e->e*2)
.collect(toList());//same is toSet()
//and toMap(key,value)
numbers.stream()
.filter(e -> e%2==0)
.map(e->e*2)
.collect(toMap(
e -> e,
e-> e*2
));
//streams are lazily evaluated so it computes the intermediate operation only when termination operation is executed.
//streams are efficient the computational complexity is same as old style code.
//streams create pipelines of all intermediate functions and execute the whole pipleline one by one on each element of stream when a termination operation is triggered.
//characteristics of stream sized,ordered,distinct,sorted these can be controlled by the parent collection or can be done by calling various functions on stream.
//infinite streams.
//start with 100 create a series 100, 101, 102, 103...
Stream.iterate(100,e ->e+1);
}
public void infiniteStreamExample(){
//given a number k and a count n, find the total of double of
//n even numbers starting with k , where sqrt of each number is >20
int k=121;
int n=51;
compute(k,n);
}
public static int compute(int k, int n){
/* old style of code
int result=0;
int index=k;
int count=0;
while(count>n){
if(index %2==0 && Math.sqrt(index)>20){
result+=index*2;
count++;
}
index++;
}
return result;*/
//code using lambda and streams
return Stream.iterate(k, e -> e+1) //unbounded ,lazy
.filter(e -> e%2 == 0) //unbounded ,lazy
.filter(e -> Math.sqrt(e) > 20) //unbounded ,lazy
.mapToInt(e -> e*2) //unbounded ,lazy
.limit(n) //bounded ,lazy
.sum(); // it controls all above operations all above operation will execute when sum is called.
}
public void lambdaExample2(){
//single abstract method interface can be changed to lambda
Thread myThread=new Thread(() -> {
System.out.println("This is another thrrad");
});
//before lambda in java 8 complier will create a .class file for each annonymous inner classes
//so generated several inner class .class files like $1.class $2.class which increases the memory footprint of your application.
//with lambda these inner classes class files not generated so they use concept invokedynamic : attach and detach function dynamically at run time using function pointer.
}
//lambdas should be glue code , it should be short, 2 lines are too many.
public static void main(String[] args) {
List<Integer> items=Arrays.asList(1,2,34,56,7);
//type inference in lambda.
items.forEach((item)->{
item=item++;
});
//invoking function as we are just doing pass through so use method reference when we are just simply doing pass through.
//=========When to use method reference===========
//we can not use if we are manuplating data or if ambiguity of function like Integr.toString
//-----case 1 -----
items.forEach(e-> System.out.println(e));
//in above code parameter becomes argument to a instance method so used method reference.
//this example a method reference to instance method
items.forEach(System.out::println);
//-------case 2------
items.forEach(e -> String.valueOf(e));
//in above code parameter becomes argument to a static method so used method reference.
items.forEach(String::valueOf);
///-----case 3-------
items.forEach(e -> e.toString());
//in above code your method parameter becomes target so used method reference.
items.forEach(Integer :: toBinaryString);
//----case 4------
//two parameters as argument.
items.stream().reduce(0,(total,num) -> Integer.sum(total, num));
//here 2 parameter are used as simple pass through from parameter to argument to sum method total and num so this can be changed to method reference.
items.stream().reduce(0,Integer::sum);
//-----case 5----------
//one parameter becomes target and other becomes argument
items.stream().map(String:: valueOf).reduce("",(carry, str) -> carry.concat(str));
//here carry becomes target and str becomes argument
items.stream().map(String::valueOf).reduce("",String::concat);
List<Integer> values=Arrays.asList(1,2,3,5,6,78,9,4);
//find the double of first even number greater than 3
/*
* Optional<Integer> desiredValue=values.stream().filter(e->e > 3)
.filter(e-> e % 2==0)
.map(e -> e*2)
.findFirst();
*/
//here method reference is used.
//Higher order functions : passing functions into a function.
//lazy (here filter function is lazy) and composition
Optional<Integer> desiredValue=values.stream().filter(LambdaExamples::isGreaterThan3)
.filter(new LambdaExamples():: isEven )
.map(e -> e*2)
.findFirst();
System.out.println(desiredValue.get());
//these intermediate functions will not execute until we call a terminal operation like findFirst or collect or reduce.
Stream<Integer> temp=values.stream().filter(LambdaExamples::isGreaterThan3)
.filter(e-> e % 2==0)
.map(e -> e*2);
//now it will execute all intermediate functions.
int executedNowValue=temp.findFirst().get();
//replacing lambdas with Predicates.
Predicate<Integer> iseven=num -> num %2 ==0;
values.stream().filter(LambdaExamples::isGreaterThan3)
.filter(iseven)
.map(e -> e*2);
//function returning predicates.
Function<Integer, Predicate<Integer>> isGreaterThan=pivot -> numvalue -> numvalue > pivot;
values.stream().filter(LambdaExamples::isGreaterThan3)
.filter(isGreaterThan.apply(4))//so this work as number gt than 4, its a eager evaluation
.map(e -> e*2);
//Dependency Injection with Lambdas
//so in above example we are injecting dependency in filter by injecting the various function strategy like gt than any number.
//so filter uses it to filter the values.
//initial conventional style
totalValues(values);
//now we want to total it based on some conditions(strategy)
//still conventional style
totalValuesOnCondition(values, new EvenSelector());
//calling it using declaratively
totalValuesOnCondition(values, e -> e % 2==0);//passing evenSelector using lambda so here only passing essence.
//calling functional style code
totalValuesOnPredicate(values, e -> e % 2==0);//passing evenSelector using lambda so here only passing essence.
//so how easy to change strategy now, here is strategy for summing number devisible by 3
//so here we mixing object composition (Predicate) with function composition(creating functions for strategy while calling.)
totalValuesOnPredicate(values, e -> e % 3==0);
totalValuesOnPredicate(values, e -> true); //total all numbers
}
//imperative style of coding
public static int totalValues(List<Integer> numbers){
int result=0;
for(int value:numbers){
result+=value;
}
}
//total based on various strategy in conventional style
public static int totalValuesOnCondition(List<Integer> numbers,Selector strategy){
int result=0;
for(int value:numbers){
if(strategy.pick(value)){
result+=value;
}
}
}
//total based on various strategy in declarative(functional) style
public static int totalValuesOnPredicate(List<Integer> numbers,Predicate<Integer> strategy){
/*int result=0;
for(int value:numbers){
if(strategy.test(value)){
result+=value;
}
}
return result;
*/
//all above code is the ceremonial code changing it to lambda style
return numbers.stream()
.filter(strategy)
.reduce(0,Math::addExact);
}
//its a strategy
interface Selector{
public boolean pick(int value);
}
class EvenSelector implements Selector{
@Override
public boolean pick(int value) {
return value %2==0; //this is the essence of this class rest other code is ceremony so in lambda we only focus on essence.
}
}
public static boolean isPrime(int number){
Predicate<Integer> isDevisible=index -> number%index==0;
//return number>1 && IntStream.range(0, number).noneMatch(index -> number%index==0);
return number>1 && IntStream.range(0, number).noneMatch(index -> isDevisible(index));
}
}