June 01, 2016

#Java8 : Java 8 Interview Questions and Answers..

What are new features introduced with Java 8 ?
Lambda Expressions, Interface Default and Static Methods, Method Reference, Parameters Name, Optional, Streams, Concurrency.
  • Lambda Expressions : a new language feature allowing treating actions as objects
  • Method References : enable defining Lambda Expressions by referring to methods directly using their names
  • Optional : special wrapper class used for expressing optionality
  • Functional Interface – an interface with maximum one abstract method, implementation can be provided using a Lambda Expression
  • Default methods : give us the ability to add full implementations in interfaces besides abstract methods
  • Nashorn, JavaScript Engine : Java-based engine for executing and evaluating JavaScript code
  • Stream API : a special iterator class that allows processing collections of objects in a functional manner
  • Date API : an improved, immutable JodaTime-inspired Date API

What is a Lambda Expression?
Lambda expressions are introduced in Java 8 and are touted to be the biggest feature of Java 8. Its an anonymous method without any declaration. Lambda Expression are useful to write shorthand code and hence saves the effort of writing lengthy Code. It promotes developer productivity, better readable and reliable code.

A lambda expression is characterized by the following syntax :
parameter -> expression body

In very simple terms, a lambda expression is a function that can be referenced and passed around as an object.

Important characteristics of a lambda expression
  • A lambda expression can have zero, one or more parameters.
  • The type of the parameters can be explicitly declared or it can be inferred from the context. e.g. (int a) is same as just (a)
  • Parameters are enclosed in parentheses and separated by commas. e.g. (a, b) or (int a, int b) or (String a, int b, float c)
  • Empty parentheses are used to represent an empty set of parameters. e.g. () -> 42
  • When there is a single parameter, if its type is inferred, it is not mandatory to use parentheses. e.g. a -> return a*a
  • The body of the lambda expressions can contain zero, one or more statements.
  • 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.
  • 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.
Lambda expression eliminates the need of anonymous class and gives a very simple yet powerful functional programming capability to Java.

Lambda expressions are used primarily to define inline implementation of a functional interface, i.e., an interface with a single method only.

Following are some examples of Lambda expressions:
  • (int a, int b) -> {  return a + b; }
  • () -> System.out.println("Hello World");
  • (String s) -> { System.out.println(s); }
  • () -> 42
  • () -> { return 3.1415 };

In the below example, we've used various types of lambda expressions to define the operation method of DoMathOperation interface.

Example:
package com.test;
public class LambdaTest {
    interface DoMathOperation {
        int doOperation(int a, int b);
    }
    private int callDoOperation(int a, int b, DoMathOperation doMathOperation) {
        return doMathOperation.doOperation(a, b);
    }

    public static void main(String args[]){
        LambdaTest lamdaTest=new LambdaTest();
      
        // with type declaration
        DoMathOperation addition = (int a, int b) -> a + b;
        System.out.println("addition: "+ lamdaTest.callDoOperation(10, 5, addition));
      
        // with out type declaration
        DoMathOperation subtraction = (a, b) -> a - b;
        System.out.println("subtraction: "+ lamdaTest.callDoOperation(10, 5, subtraction));
      
        // with return statement along with curly braces
        DoMathOperation multiplication = (int a, int b) -> {return a * b;};
        System.out.println("multiplication: "+ lamdaTest.callDoOperation(10, 5, multiplication));
      
        // without return statement and without curly braces
        DoMathOperation division = (int a, int b) -> a / b;
        System.out.println("division: "+ lamdaTest.callDoOperation(10, 5, division));      
    }
}

Output:
addition: 15
subtraction: 5
multiplication: 50
division: 2

Let us take a simple example to sort a list of strings. In prior versions of Java, sorting is done:

List names = Arrays.asList("thomas", "andreas", "michael", "mattrias");
Collections.sort(names, new Comparator() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
    }
});


In above example, the static utility method Collections.sort accepts a list and a comparator object in order to sort the elements of the given list. We usually create anonymous comparators and pass them to the sort() method, like we did in above example.

In Java 8 we can do the similar thing with a much shorter syntax by using lambda expressions.

Collections.sort(names, (String a, String b) -> {
    return b.compareTo(a);
});


If you want, you  you skip both the braces {} and the return keyword from the above code. Here is even more shorter way:

Collections.sort(names, (String a, String b) -> b.compareTo(a));

We can also skip the parameter types, as the java compiler is aware of the parameter types. Another way to write the above code:

Collections.sort(names, (a, b) -> b.compareTo(a));

Difference between Lambda Expression and Anonymous class?
Lambda expressions are very powerful and can replace many usage of anonymous class but not all. An anonymous class can be used to create a subclass of an abstract class, a concrete class and can be used to implement an interface in Java. It can even add state fields.

An instance of anonymous class can also be refereed by using 'this' keyword inside its methods, which means you can call other methods and state can be changed.

Since the most common use of Anonymous class is to provide throwaway, stateless implementation of abstract class and interface with single function, those can be replaced by lambda expressions, but when you have a state field or implementing more than one interface, you cannot use lambdas to replace anonymous class.

For anonymous class ‘this’ keyword resolves to anonymous class, whereas for lambda expression ‘this’ keyword resolves to enclosing class where lambda is written.

Another difference between lambda expression and anonymous class is in the way these two are compiled. Java compiler compiles lambda expressions and convert them into private method of the class. It uses invokedynamic instruction that was added in Java 7 to bind this method dynamically.

Difference between Predicate, Supplier and Consumer?
  • Predicate represents an anonymous function that accepts one argument and produces a result.
  • Supplier represents an anonymous function that accepts no argument and produces a result.
  • Consumer represents an anonymous function that accepts an argument and produces no result. 
How you can Default Methods for Interfaces?
Java 8 enables us to add non-abstract method implementations to interfaces by utilizing the default keyword. This feature is also known as Extension Methods. For example:

package com.defaultmethods;
public interface Formula {
    double doubleIt(int a);

    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}


In the above example, apart from an abstract method doubleIt(), one more method sqrt() is also defined. sqrt() is the default method, which can be used out of the box.

When a class implements Formula interface, that class need to only implement the abstract method doubleIt().

package com.defaultmethods;
public class TestFormula {
    public static void main(String[] args) {
        //anonymous inner class
        Formula formula=new Formula() {           
            @Override
            public double doubleIt(int a) {
                return (double)a;
            }
        };
        System.out.println(formula.doubleIt(10));
        System.out.println(formula.sqrt(16));  
    }
}


Output is:
10.0
4.0

What are Functional interfaces in Java8?
All the Java developer's must have used at least one of the following interfaces, while developing Java based projects: java.lang.Runnable, java.awt.event.ActionListener, java.util.Comparator or java.util.concurrent.Callable.

All these interfaces have one thing in common, they all have only one method declared in their interface definition. There are lot more such interfaces in JDK and also lot more created by Java developers. These interfaces are also called Single Abstract Method interfaces (SAM Interfaces).

To use such interfaces, the developer's create Anonymous Inner classes, e.g :

public class TestAnonymousInnerClass {
  public static void main(String[] args) {
    new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.println("Inside run method..");
      }
    }).start();
  }
}

With Java 8, we can recreate the same concept of SAM interfaces by using @FunctionalInterface annotation. These can be represented using Lambda expressions, Method reference and constructor references.

@FunctionalInterface
public interface TestFunctionalInterface {
  public void testIt();
}


If required, you can also declare the abstract methods from the java.lang.Object class in Functional Interface, e.g:

@FunctionalInterface
public interface TestFunctionalInterface {
  public void testIt();
  public String toString();
  public boolean equals(Object o);
}


If you try to add a second abstract method declaration in the FunctionalInterface, the compiler will throw an error. You can declare any number of default methods in the FunctionalInterface.

You can use the lambda expression as against anonymous inner class for implementing functional interfaces:

public class FunctionalInterfaceExample {
    public static void doTesting(TestFunctionalInterface tfi) {
        tfi.testIt();
    }

    public static void main(String[] args) {
        doTesting(new TestFunctionalInterface() {
            @Override
            public void testIt() {
                System.out.println("testIt() with anonymous inner class");

            }
        });
        doTesting(() -> System.out.println("testIt() with lambda expression"));
    }

}
Output of above program is :
testIt() with anonymous inner class
testIt() with lambda expression


Another Example:
@FunctionalInterface
interface Converter {
    T convert(F from);
}


/*in another class*/
Converter converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("619");
System.out.println(converted);



Java 8 has defined a lot of functional interfaces to be used extensively in lambda expressions. Here is the list of functional interfaces defined in java.util.Function package of Java8:
1. BiConsumer : Represents an operation that accepts two input arguments, and returns no result.
2. BiFunction : Represents a function that accepts two arguments and produces a result.
3. BinaryOperator : Represents an operation upon two operands of the same type, producing a result of the same type as the operands.
4. BiPredicate : Represents a predicate (Boolean-valued function) of two arguments.
5. BooleanSupplier : Represents a supplier of Boolean-valued results.
6. Consumer : Represents an operation that accepts a single input argument and returns no result.
7. DoubleBinaryOperator : Represents an operation upon two double-valued operands and producing a double-valued result.
8. DoubleConsumer : Represents an operation that accepts a single double-valued argument and returns no result.
9. DoubleFunction : Represents a function that accepts a double-valued argument and produces a result.
10. DoublePredicate : Represents a predicate (Boolean-valued function) of one double-valued argument.
11. DoubleSupplier : Represents a supplier of double-valued results.
12. DoubleToIntFunction : Represents a function that accepts a double-valued argument and produces an int-valued result.
13. DoubleToLongFunction : Represents a function that accepts a double-valued argument and produces a long-valued result.
14. DoubleUnaryOperator : Represents an operation on a single double-valued operand that produces a double-valued result.
15. Function : Represents a function that accepts one argument and produces a result.
16. IntBinaryOperator : Represents an operation upon two int-valued operands and produces an int-valued result.
17. IntConsumer : Represents an operation that accepts a single int-valued argument and returns no result.
18. IntFunction : Represents a function that accepts an int-valued argument and produces a result.
19. IntPredicate : Represents a predicate (Boolean-valued function) of one int-valued argument.
20. IntSupplier : Represents a supplier of int-valued results.
21. IntToDoubleFunction : Represents a function that accepts an int-valued argument and produces a double-valued result.
22. IntToLongFunction : Represents a function that accepts an int-valued argument and produces a long-valued result.
23. IntUnaryOperator : Represents an operation on a single int-valued operand that produces an int-valued result.
24. LongBinaryOperator : Represents an operation upon two long-valued operands and produces a long-valued result.
25. LongConsumer : Represents an operation that accepts a single long-valued argument and returns no result.
26. LongFunction : Represents a function that accepts a long-valued argument and produces a result.
27. LongPredicate : Represents a predicate (Boolean-valued function) of one long-valued argument.
28. LongSupplier : Represents a supplier of long-valued results.
29. LongToDoubleFunction : Represents a function that accepts a long-valued argument and produces a double-valued result.
30. LongToIntFunction : Represents a function that accepts a long-valued argument and produces an int-valued result.
31. LongUnaryOperator : Represents an operation on a single long-valued operand that produces a long-valued result.
32. ObjDoubleConsumer : Represents an operation that accepts an object-valued and a double-valued argument, and returns no result.
33. ObjIntConsumer : Represents an operation that accepts an object-valued and an int-valued argument, and returns no result.
34. ObjLongConsumer : Represents an operation that accepts an object-valued and a long-valued argument, and returns no result.
35. Predicate : Represents a predicate (Boolean-valued function) of one argument.
36. Supplier : Represents a supplier of results.
37. ToDoubleBiFunction : Represents a function that accepts two arguments and produces a double-valued result.
38. ToDoubleFunction : Represents a function that produces a double-valued result.
39. ToIntBiFunction : Represents a function that accepts two arguments and produces an int-valued result.
40. ToIntFunction : Represents a function that produces an int-valued result.
41. ToLongBiFunction : Represents a function that accepts two arguments and produces a long-valued result.
42. ToLongFunction : Represents a function that produces a long-valued result.
43. UnaryOperator : Represents an operation on a single operand that produces a result of the same type as its operand. :  :  :
 

What is Method references in Java8?
We can use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it's often clearer to refer to the existing method by name. Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.

It allows us to reference constructors or methods without executing them. Method references and Lambda are similar in that they both require a target type that consist of a compatible functional interface (similar to lambda expressions, a method reference when evaluated creates an instance of the functional interface)

A method reference is described using :: (double colon) symbol. A method reference can be used to point the following types of methods :
  • Static methods
  • Instance methods
  • Constructors using new operator (TreeSet::new)
In the first two types, the method reference is equivalent to a lambda expression on which parameters of a method will be supplied. In the 3rd type, the 1st parameter of a method becomes the target of the method and second parameter becomes argument to the method just like s1.equals(s2); .

The above example from 'Functional interfaces' to convert string to Integer can be further simplified by utilizing static method references:

Converter converter = Integer::valueOf;
Integer converted = converter.convert("619");
System.out.println(converted);

 

Example:
package com.test;
import java.util.ArrayList;
import java.util.List;

public class MethodReferenceExample {
    public static void main(String[] args) {
        List employeeNames = new ArrayList();
        employeeNames.add("Martin");
        employeeNames.add("Thomas");
        employeeNames.add("Ulrich");
        employeeNames.add("Stephan");
        employeeNames.add("Andreas");
        employeeNames.forEach(System.out::println);
    }
}

Output of the above program:
Martin
Thomas
Ulrich
Stephan
Andreas

What is Internal Iteration in Java SE 8?
Internal Iteration means “Iterating an Aggregated Object elements one by one internally by Java API”. Instead of Java Application do iteration externally, We ask Java API to do this job internally.

What is the differences between External Iteration and Internal Iteration?
External Iteration, iterate elements by using for-each loop and Iterators like Enumeration, Iterator, ListIterator. Where as, Internal Iteration iterate elements by using Java API like “forEach” method.
Iterating elements in Sequential and In-Order only in External Iteration. Where as, in Internal Iteration it is not required to iterate elements in Sequential order.

What is Multiple Inheritance? How Java 8 supports Multiple Inheritance?
Multiple Inheritance means a class can inherit or extend characteristics and features from more than one parent class.

In Java 7 or Earlier, Multiple Inheritance is not possible because Java follows “A class should extend one and only one class or abstract class” Rule. However, it’s possible to provide Multiple Implementation Inheritance using Interface because Java follows “A class can extend any number of Interfaces” Rule.

However, Java 8 supports “Implementing Methods in Interfaces” by introducing new features: Default methods in Interface. Because of this feature, Java 8 supports Multiple Inheritance with some limitations.

What is Diamond Problem in Inheritance? How Java 8 Solves this problem?

A Diamond Problem is a Multiple Inheritance problem. In Java, It occurs when a Class extends more than one Interface which have same method implementation (Default method).

Suppose interface A has a default method printIt(), now interface B1 and B2 extends interface A and override default method.printIt(). If you declare a Test class which implements both B1 and B2, then you will get a compilation error 'Duplicate default methods named printIt with the parameters () and () are inherited from the types B1 and B2'

Can a class implement two Interfaces having default method with same name and signature?
No. Compiler gives error saying "Duplicate Default Methods"

What if we make the method as abstract in another Interface?
Even then the Compiler will give error saying that there is a conflict.

What if we override the conflicting method in the Class?
There won't be any error and upon execution the overriding class method will be executed.

Difference between final and effectively final? Why is effectively final even required?

Final variable means a variable that has been declared final and hence cannot be changed after initialization. Effective final means a variable that has not been declared final but haven't been reassigned the value after initialization.

First is the regulation that restricts the reassignment and will raise a compilation error if we try to do so. Second is the outcome without the restriction.

Effective Final is the eventual treatment of the variable that is required for many features. For eq - Java 8 requires that

local variables referenced from a lambda expression must be final or effectively final

It means all local referenced from lambda expressions must be such that their value shouldn't be changed after initialization whether declared final or not.

Write a program that calculates the sum of all even numbers between 10-100 using Java 8?
int sum = IntStream.rangeClosed(10, 100)  
    .filter(i - > i % 2 == 0)
    .sum();
}

  • IntStream.rangeClosed(10, 100) supplies all the integers between 10 and 100 inclusive as a stream
  • filter(i - > i % 2 == 0) creates a new stream, containing only the even numbers ( where number mod 2 equals zero)
  • sum() handle adds up all the integers in this new stream and returns an int

-K Himaanshu Shuklaa..

No comments:

Post a Comment