Java 8 Features


Java 8 Important Features-


Functional Interface-

A Functional Interface is an interface, which contains one and only one abstract method.
@FunctionalInterface
public interface FuncInterface {
   
public void welcome(String name);
}

public class TestMain {

public static void main(String[] args) {
  FuncInterface funcInterface = (name) -> System.out.println("Welcome ! " + name);
  funcInterface.welcome("Manoj");
  }
}

BiConsumer Functional Interface
import java.util.function.BiConsumer;

public class TestMain {
   
public static void main(String[] args) {
        BiConsumer<String, String> consumer = (a, b) -> {
            System.
out.println(a + b);
        };
        consumer.accept(
"Welcome", " MK Study Journal");
    }
}

BiFunction Functional Interface
import java.util.function.BiFunction;

public class TestMain {
   
public static void main(String[] args) {
        BiFunction<String, String, String> biFunction = (a, b) -> {
           
return a + b;
        };
        System.
out.println(biFunction.apply("Welcome", " MK Study Journal"));
    }
}

BinaryOperator Functional Interface
import java.util.function.BinaryOperator;

public class TestMain {
   
public static void main(String[] args) {
        BinaryOperator<Integer> findMaxBinOperator = BinaryOperator
                        .maxBy( (a, b) -> (a > b) ?
1 : ((a == b) ? 0 : -1));
        System.
out.println(findMaxBinOperator.apply(21, 17));
    }
}

Predicate and Bipredicate functional interface-
import java.util.function.BiPredicate;
import java.util.function.Predicate;

public class TestMain {
   
public static void main(String[] args) {
        Predicate<Integer> pr = a -> (a >
10);  //will check given number is greater than 10
       
System.out.println(pr.test(9));   //false
       
System.out.println(pr.test(13));  //true

       
BiPredicate<Integer, Integer> biPr = (a , b) -> (a > b);
        System.
out.println(biPr.test(9, 13)); //false
       
System.out.println(biPr.test(13, 9)); //true
   
}
}

UnaryOperator and Suppiler functions-
import java.util.function.Supplier;
import java.util.function.UnaryOperator;

public class TestMain {
   
public static void main(String[] args) {
        UnaryOperator<Integer> unaryOperatorSquare = a -> (a*a);
        System.
out.println(unaryOperatorSquare.apply(10));

        Supplier<Long> randomValue = () -> System.nanoTime();
        System.
out.println(randomValue.get());
    }
}


Lambda Expression

Structure of Lambda Expressions

1)     A lambda expression can have zero, one or more the one parameters.
2)     The type of the parameters can be explicitly declared or it can be inferred from the context.
3)     Parameters are enclosed in parentheses and separated by commas
4)     Empty parentheses are used to represent an empty set of parameters. e.g. () -> 42
5)     When there is a single parameter, if its type is inferred, it is not mandatory to use parentheses. e.g. a -> return a*a
6)     The body of the lambda expressions can contain zero, one or more statements.
7)     If body of lambda expression has single statement curly brackets are not mandatory and the return type of the anonymous function is the same as that of the body expression.
8)     When there is more than one statement in body than these must be enclosed in curly brackets (a code block) and the return type of the anonymous function is the same as the type of the value returned within the code block, or void if nothing is returned.

Here’s the syntax:

(argtype arg...) -> {return some expression... probably using these arguments}
Code Snippet –
Runnable java8Runner = () -> {System.out.println("I am running");  };



Generic Type changes and improvements

The methods for instance using a generic collection need not specify genric types
Code Snippet –
In java 7 –
final List<Boolean> bools = Arrays.asList(true);
final List<Character> string = bools.stream().<Character>map(x -> x ? ’a’: 'b')
.collect(Collectors.<Character>toList());
In java 8 –
final List<Boolean> bools1 = Arrays.asList(true);
final List<Character> string1 = bools.stream().map(x -> x ? ’a’: 'b')
.collect (Collectors.toList());


forEach() method in Iterable interface-

This is an improved version of forEach loop, with this method of Iterable interface all the implementing class can iterate easily, refer below code snippet-
public class TestMain {

      public static void main(String[] args) {
            List<String> list = Arrays.asList("1","2","3");
            list.forEach(str -> System.out.println(str));
      }
}



Stream Collection Types (java.util.stream)

Stream can process data in a declarative way
Streams support Aggregate Operations like filter, map, reduce, find, match, sort etc.  These operations can be executed in series or in parallel.
Collection interface has been extended with stream() and parallelStream() default methods to get the Stream for sequential and parallel execution

Code Snippet –  
List<String> list =  Arrays.asList("a1""a2""a3""a4""a5");
list.stream().filter(s -> s.endsWith("5")) .map(String::toUpperCase) .sorted() .forEach(System.out::println);


Default and static method in interface-

public interface DefaultMethInterface {

   
public default void welcome(){
        System.
out.println("welcome");
    }
   
public static void welcomeStatic(){
        System.
out.println("static welcome");
    }
}


Optional class -

It is defined in java.util package.
It is used to represent optional values that is either exist or not exist. It contain either one value or zero value.
It is a bounded collection that is it contains at most one element only. It is an alternative to “null” value.


Date Time API

The existing classes such as java.util.Date and SimpleDateFormatter aren’t thread-safe.
Java 8 under the package java.time introduced a new date-time API,
1)     Local : Simplified date-time API with no complexity of timezone handling.
2)     Zoned : Specialized date-time API to deal with various timezones.
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;

public class TestMain {
   
public static void main(String[] args) {
        LocalDate date = LocalDate.now();
        System.
out.println(" Current date ::" + date);

        LocalDate nextMonday = date.with(TemporalAdjusters.next(DayOfWeek.
MONDAY));
        System.
out.println("Date on upcoming monday : " + nextMonday);

        Period period = Period.between(nextMonday, date);
        System.
out.println("Gap on next monday "+period);

        System.
out.println("Current time :: " + LocalTime.now());
        Duration fiveHours = Duration.ofHours(
2);

        LocalTime time = LocalTime.now().plus(fiveHours);
        System.
out.println("Time after 2 hours :: " + time);

        LocalDateTime current = LocalDateTime.now();
        System.
out.println("Current date-time : " +current);

        DateTimeFormatter format = DateTimeFormatter.ofPattern(
"dd-MM-yyyy HH:mm:ss");
        System.
out.println("Formatted Date " +current.format(format));
    }
}



Map vs FlatMap

map and flatMap are intermediate stream operations that receive a function and apply this function to all elements of a stream
The map() method wraps the underlying sequence in a Stream instance, whereas the flatMap() method allows avoiding nested Stream<Stream<R>> structure.
map() is used to transform a single stream of values while flatMap() is used to transform stream of stream values. Refer below code snippet-
import java.util.*;

import java.util.stream.Collectors;

public class TestMain {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("Hello", "Friends");
        List<String> list2 = Arrays.asList("Welcome", "in");
        List<String> list3 = Arrays.asList("MK", "Study", "Journal");
        //map will transform string in a list to uppercase.
        List<String> list1Upper = list1.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println(" map : " + list1Upper);
        List<List<String>> listOfLists = Arrays.asList(list1, list2, list3);
        System.out.println("Before : " + listOfLists);
        //flat map is used to transform the list of list
        List<String> flatList = listOfLists.stream()

                 .flatMap(list -> list.stream())

                .collect(Collectors.toList());
        System.out.println("After  : " + flatList);
    }
}

Output-
map : [HELLO, FRIENDS]
Before : [[Hello, Friends], [Welcome, in], [MK, Study, Journal]]
After  : [Hello, Friends, Welcome, in, MK, Study, Journal]


Improvement in Concurrent API-

New interface- CompletableFuture.AsynchronousCompletionTask
A marker interface identifying asynchronous tasks produced by async methods. This may be useful for monitoring, debugging, and tracking asynchronous activities.
Various aggregate operation are added base on stream and lambda expression like-
ConcurrentHashMap have several new methods like -forEach, forEachKey, forEachValue, ,forEachEntry etc


PermGen space is removed and Introduces Metaspace memory model-

PermGen space is completely removed in JAVA8, draw back of PermGen space-
Fixed size and it was difficult to tune.
Due to fix size it gives error - java.lang.OutOfMemoryError: PermGen error.
Benefits of Metaspace-
class metadata are allocated out of native memory.
Flag MaxMetaspaceSize is used to limit the amount of native memory used for class metadata. If you don’t specify this flag, the Metaspace will dynamically re-size depending of the application demand at runtime.

Refer our youtube channel for latest videos - https://www.youtube.com/watch?v=7yb1IBb-XlU&t=496s

4 comments: