Wednesday, 14 October 2020

Java 8 Functions, Lambda, Streams

 

Most commonly used functions in Java 8 with examples

Predicate: takes one argument and returns true/false

@Test
public void testPredicate() {
//using the test method of Predicate
Predicate<String> stringLen = (s)-> s.length() < 10;
Assert.assertTrue(stringLen.test("Apples"));
Assert.assertFalse(stringLen.test("Applesssdnvonwoe"));
}

Consumer: accepts one argument, returns no value

//Consumer example uses accept method
Consumer<String> consumerStr = (s) -> System.out.println(s.toLowerCase());
consumerStr.accept("ABCD");

Function: accepts one argument, returns result of execution of a different type

//Function example        
Function<Integer,String> converter = (num)-> Integer.toString(num);
System.out.println("length of 26: " + converter.apply(26).length());

Unary Operator: is almost same as function except that the return value has to be of same type as the input argument

//Unary Operator example
UnaryOperator<String> str = (msg)-> msg.toUpperCase();
System.out.println(str.apply("This is my message in upper case"));

Supplier: Does not accept any argument, returns result of execution

//Supplier example
Supplier<String> s = ()-> "Java is fun";
System.out.println(s.get());

Binary Operator: accepts two arguments, returns result of execution, all of same type

//Binary Operator example
BinaryOperator<Integer> add = (a, b) -> a + b;
System.out.println("add 10 + 25: " + add.apply(10, 25));


Compute and Merge functions in Map:

If we are not using Java 8, then for creating a map with frequency of the data in a list, we would do the following:

@Test
public void testListToMapNoJava8() {

List<String> dataList = new ArrayList<>();
dataList.add("v1");
dataList.add("v1");
dataList.add("v2");
dataList.add("v3");
dataList.add("v3");
dataList.add("v3");
Map<String, Integer> dataCountMap = new HashMap<>();
for (String data : dataList) {
if (dataCountMap.containsKey(data)) {
dataCountMap.put(data, dataCountMap.get(data) + 1);
} else {
dataCountMap.put(data, 1);
}
}
Assert.assertEquals(2, dataCountMap.get("v1").intValue());
Assert.assertEquals(3, dataCountMap.get("v3").intValue());
}

In java 8, there are few functions for Map that makes this task simpler.

Using Compute function:

@Test
public void testMapCompute() {

List<String> dataList = new ArrayList<>();
dataList.add("v1");
dataList.add("v1");
dataList.add("v2");
dataList.add("v3");
dataList.add("v3");
dataList.add("v3");
Map<String, Integer> dataCountMap = new HashMap<>();
for (String data : dataList) {
dataCountMap.compute(data, (key, count) -> count == null? 1 : count + 1);
}
System.out.println(dataCountMap);
Assert.assertEquals(2, dataCountMap.get("v1").intValue());
Assert.assertEquals(3, dataCountMap.get("v3").intValue());
}

Using Merge function:

@Test
public void testMapMerge() {

List<String> dataList = new ArrayList<>();
dataList.add("v1");
dataList.add("v1");
dataList.add("v2");
dataList.add("v3");
dataList.add("v3");
dataList.add("v3");
Map<String, Integer> dataCountMap = new HashMap<>();
for (String data : dataList) {
dataCountMap.merge(data, 1, (value, replacement) -> value + 1);
}
System.out.println(dataCountMap);
Assert.assertEquals(2, dataCountMap.get("v1").intValue());
Assert.assertEquals(3, dataCountMap.get("v3").intValue());
}

Using Streams, Collectors.toMap with Merge function:

@Test
public void testStreamsToMap() {

List<String> dataList = new ArrayList<>();
dataList.add("v1");
dataList.add("v1");
dataList.add("v2");
dataList.add("v3");
dataList.add("v3");
dataList.add("v3");
Map<String, Integer> dataCountMap = dataList.stream()
.collect(Collectors.toMap(Function.identity(), value -> 1, (value, replacement) -> value + 1));
Assert.assertEquals(2, dataCountMap.get("v1").intValue());
Assert.assertEquals(3, dataCountMap.get("v3").intValue());
}



No comments:

Post a Comment