Interview Questions & Answers

java-8

Collection API:-

  • It’s available since Java 1.2
  • It is used to store Data (A set of Objects).
  • We can use both spliterator and Iterator to iterate elements.
  • It is used to store an unlimited number of elements.
  • Typically, it uses the External Iteration concept to iterate Elements such as Iterator.
  • Collection Object is constructed Eagerly.
  • We add elements to the Collection object only after it is computed completely.

Stream API:-

  • It is introduced in Java SE 8
  • It is used to compute data (Computation on a set of Objects).
  • We can’t use Spliterator or Iterator to iterate elements. We can use forEach to perform an action for each element of this stream.
  • Stream API is used to process the elements of a Collection.
  • Stream API uses internal iteration to iterate Elements, using the forEach method.
  • Stream Object is constructed Lazily.
  • We can add elements to Stream Object without any prior computation. That means Stream objects are computed on-demand.

The stream represents a sequence of objects from a source such as a collection, which supports aggregate operations.
You can use Stream to filter, collect, print, and convert from one data structure to another, etc.

Stream does not store elements. It simply conveys elements from a source such as a data structure, an array, or an I/O channel, through a pipeline of computational operations.

Stream is functional in nature. Operations performed on a stream do not modify its source. For example, filtering a Stream obtained from a collection produces a new Stream without the filtered elements, rather than removing elements from the source collection.
Creating Empty String:
Stream<String> stream = Stream.empty();
stream.forEach(System.out::println);

  • Reference to a static method. For example:
ContainingClass::staticMethodName
  • Reference to an instance method of a particular object. For example:
containingObject::instanceMethodName
  • Reference to an instance method of an arbitrary object of a particular type. For example:
ContainingType::methodName
  • Reference to a constructor. for example:
ClassName::new

 

Method reference is used to refer method of the functional interface. It is a compact and easy form of a lambda expression. Each time when you are using a lambda expression to just referring a method, you can replace your lambda expression with a method reference.

Below are a few examples of method reference:

(o) -> o.toString();

can become:

Object::toString();

Static method reference:

String::valueOf;

Bound instance method reference:

str::toString;

Unbound instance method reference:

String::toString;

In Java 8, there are a lot of functional interfaces are introduced in the java.util.function package and the more common ones include but are not limited to:
  • Function – it takes one argument and returns a result
  • Consumer – it takes one argument and returns no result (represents a side effect)
  • Supplier – it takes no argument and returns a result
  • Predicate – it takes one argument and returns a boolean
  • BiFunction – it takes two arguments and returns a result
  • BiConsumer – it takes two (reference type) input arguments and returns no result
  • BinaryOperator – it is similar to a BiFunction, taking two arguments and returning a result. The two arguments and the result are all of the same types
  • UnaryOperator – it is similar to a Function, taking a single argument and returning a result of the same type
  • Runnable: use to execute the instances of a class over another thread with no arguments and no return value.
  • Callable: use to execute the instances of a class over another thread with no arguments and it either returns a value or throws an exception.
  • Comparator: use to sort different objects in a user-defined order
  • Comparable: use to sort objects in the natural sort order.

Yes, it is possible to define our own Functional Interfaces. We use Java 8 provides the @FunctionalInterface annotation to mark an interface as a Functional Interface.
We need to follow these rules to define a Functional Interface:
  • Define an interface with one and only one abstract method.
  • We cannot define more than one abstract method.
  • Use @FunctionalInterface annotation in the interface definition.
  • We can define any number of other methods like default methods, static methods.
The below example illustrates defining our own Functional Interface:
Let’s create a Sayable interface annotated with @FunctionalInterface annotation.
@FunctionalInterface
interface Sayable{
    void say(String msg);   // abstract method   
} 

Let's demonstrate a custom functional interface via the main() method.
public class FunctionalInterfacesExample {

    public static void main(String[] args) {

        Sayable sayable = (msg) -> {
            System.out.println(msg);
        };
        sayable.say("Say something ..");
    }
}

An Interface that contains exactly one abstract method is known as a functional interface. It can have any number of default, static methods but can contain only one abstract method. It can also declare the methods of the object class.
Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. A functional interface can extend another interface only when it does not have any abstract method.
Java 8 provides predefined functional interfaces to deal with functional programming by using lambda and method references.
Example:
interface Printable {
    void print(String msg);
}

public class JLEExampleSingleParameter {

    public static void main(String[] args) {
        // with lambda expression
        Printable withLambda = (msg) -> System.out.println(msg);
        withLambda.print(" Print message to console....");
    }
}

output:
Print message to console....
 

Java Lambda Expression Syntax:

(argument-list) -> {body}
Java lambda expression consists of three components.
  • Argument-list: It can be empty or non-empty as well.
  • Arrow-token: It is used to link arguments-list and body of expression.
  • Body: It contains expressions and statements for the lambda expression.

For example, Consider we have a functional interface:

interface Addable{
    int add(int a,int b);
} 
Let's implement the above Addable functional interface using a lambda expression:
Addable withLambdaD = (int a,int b) -> (a+b);  
    System.out.println(withLambdaD.add(100,200));