Interview Questions & Answers

java-8

  1. Facilitates functional programming – Lambda Expression facilitates functional programming and simplifies the development a lot.
  2. To provide the implementation of the Java 8 Functional Interface.
  3. Reduced Lines of Code – One of the clear benefits of using lambda expression is that the amount of code is reduced, we have already seen that how easily we can create instances of a functional interface using lambda expression rather than using an anonymous class.
  4. Passing Behaviors into methods – Lambda Expressions enable you to encapsulate a single unit of behavior and pass it to other code. For example, to other methods or constructors.

In Java 8,  the following new features were added:
  • Lambda Expressions − lambda expression is a function that can be referenced and passed around as an object
  • Method References − Method references are the references that use a function as a parameter to request a method.
  • Optional − This class is to provide a type-level solution for representing optional values instead of using null references.
  • Functional Interface – An Interface that contains exactly one abstract method and implementation can be provided using a Lambda Expression
  • Default methods − give us the ability to add full implementations in interfaces besides abstract methods
  • Stream API − Stream API provides a functional approach to processing collections of objects.
  • Date and Time API − an improved, immutable JodaTime-inspired Date API
  • Nashorn, JavaScript Engine − Java-based engine for executing and evaluating JavaScript code
Along with these new features, lots of feature enhancements are done under-the-hood, at both compiler and JVM levels.

The intermediate Stream operation returns another Stream, which means you can further call other methods of Stream class to compose a pipeline.
Intermediate Stream operations:
  • filter()
  • map()
  • flatMap()
  • distinct()
  • sorted()
  • peek()
  • limit()
  • skip()

For example, after calling filter() you can still call the map() method on Stream.

// Converting product List into Set
        Set < Float > productPriceList = productsList.stream().filter(product -> product.getPrice() < 30000)
        .map(product -> product.getPrice()).collect(Collectors.toSet());
Stream terminal operation produces a result other than Streams like a value or a Collection.
Terminal Stream operations:
  • anyMatch()
  • allMatch()
  • noneMatch()
  • collect()
  • count()
  • findAny()
  • findFirst()
  • forEach()
  • min()
  • max()
  • reduce()
  • toArray()

Once a terminal method like forEach() or collect() is called, you cannot call any other method of Stream or reuse the Stream.”

List<String> lines = Arrays.asList("java", "c", "python");

List<String> result = lines.stream()       // convert list to stream
.filter(line -> !"c".equals(line)) // we dont like c
.collect(Collectors.toList());     // collect the output and convert streams to a List

result.forEach(System.out::println);

The key difference between map() vs flatMap() in Java 8:

  • The function you pass to the map() operation returns a single value.
  • The function you pass to flatMap() operation returns a Stream of value.
  • flatMap() is a combination of map and flat operation.
  • map() is used for transformation only, but faltMap() is used for both transformation and flattening.

The Stream.flatMap() function, as the name suggests, is the combination of a map and a flat operation. This means you first apply the map function and then flatten the result.
To understand what flattening a stream consists in, consider a structure like [ [1,2,3],[4,5,6],[7,8,9] ] which has “two levels”. It’s basically a big List containing three more List. Flattening this means transforming it in a “one level” structure e.g. [ 1,2,3,4,5,6,7,8,9 ] i.e. just one list.
For example: In the below program, you can see that we have three lists that are merged into one by using a flatMap() function.
public class Main {
    public static void main(String[] args)
    {
        List<Integer> evens = Arrays.asList(2, 4, 6);
        List<Integer> odds = Arrays.asList(3, 5, 7);
        List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11);
        List<Integer> numbers = Stream.of(evens, odds, primes)
                .flatMap(list -> list.stream())
                .collect(Collectors.toList());
        System.out.println("flattend list: " + numbers);
    }
}

Output:
flattend list: [2, 4, 6, 3, 5, 7, 2, 3, 5, 7, 11]

The map() function is an intermediate function that is used to perform map functional operations in Java. This means it can transform one type of object to others by applying a function.
Use map() function to convert one object to another object.
For example, if you have a List of String and you want to convert that to a List of Integer, you can use map() to do so.

        import java.util.Arrays;
        import java.util.List;
        import java.util.stream.Collectors;

public class Main
{
    public static void main(String[] args)
    {
        List<String> listOfStrings = Arrays.asList("1", "2", "3", "4", "5");

        List<Integer> listOfIntegers = listOfStrings.stream()
                .map(Integer::valueOf)
                .collect(Collectors.toList());

        System.out.println(listOfIntegers);
    }
}

output:
java
python



1. Collections are used to store and group the data in a particular data structure like List, Set, or Map. Whereas Streams are used to perform complex data processing operations like filteringmatchingmapping, etc on stored data such as arrays, collections, or I/O resources. That means, collections are mainly about data and streams are mainly about operations on data.

2. You can add to or remove elements from collections. But, you can’t add to or remove elements from streams. Stream consumes a source, performs operations on it, and returns a result. They don’t modify even the source also.

In Streams, there are no such methods to add or remove elements.

3. The main specialty of Java 8 Streams is that you need not worry about iteration while using Streams. Streams perform iteration internally behind the scene for you (using the forEach() method). You just have to mention the operations to be performed on a source.

On the other hand, you have to do the iteration externally over collections using loops.

4. Streams are traversable only once. If you traverse the stream once, it is said to be consumed. To traverse it again, you have to get a new stream from the source again. But, collections can be traversed multiple times.