Java 8 Interview Questions : Part 1 | Code Factory


Donate : Link

Medium Blog : Link

Applications : Link

1. Java7 and Java8 Features

Java7 Features:

A. Try-with-resources statement

Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.

Using try-with-resources we can write try w/o catch block but we must have to handle exception using throws. So handle Exception using catch or throws.

this:

BufferedReader br = new BufferedReader(new FileReader(path));
try {
   return br.readLine();
} finally {
   br.close();
}

becomes:

try (BufferedReader br = new BufferedReader(new FileReader(path)) {
   return br.readLine();
}

You can declare more than one resource to close:

try (
   InputStream in = new FileInputStream(src);
   OutputStream out = new FileOutputStream(dest))
{
 // code
}

B. Underscores in numeric literals

int one_million = 1_000_000;

C. Strings in switch

String s = ...
switch(s) {
 case "quux":
    processQuux(s);
    // fall-through

  case "foo":
  case "bar":
    processFooOrBar(s);
    break;

  case "baz":
     processBaz(s);
    // fall-through

  default:
    processDefault(s);
    break;
}

D. Binary literals

int binary = 0b1001_1001;

E. Improved Type Inference for Generic Instance Creation

this:

Map<String, List<String>> anagrams = new HashMap<String, List<String>>();

becomes:

Map<String, List<String>> anagrams = new HashMap<>();

F. Multiple exception catching

this:

} catch (FirstException ex) {
     logger.error(ex);
     throw ex;
} catch (SecondException ex) {
     logger.error(ex);
     throw ex;
}

becomes:

} catch (FirstException | SecondException ex) {
     logger.error(ex);
    throw ex;
}

G. SafeVarargs

this:

@SuppressWarnings({"unchecked", "varargs"})
public static void printAll(List<String>... lists){
    for(List<String> list : lists){
        System.out.println(list);
    }
}

becomes:

@SafeVarargs
public static void printAll(List<String>... lists){
    for(List<String> list : lists){
        System.out.println(list);
    }
}

Java8 Features:

https://34codefactory.wordpress.com/2020/04/08/java8-tutorial/

  1. Lambda Expression
  2. Functional Interfaces
  3. Default methods in interfaces
  4. Static methods in interfaces
  5. Predicates
  6. Functions
  7. Consumer
  8. Method reference & Constructor reference by double colon (::) operator
  9. Stream API
  10. Date & Time API / Joda API (joda.org)

2. Stream and ParallelStream

  • Parallel streams divide the provided task into many and run them in different threads, utilizing multiple cores of the computer. On the other hand sequential streams work just like for-loop using a single core.
  • In parallel execution, if number of tasks are more than available cores at a given time, the remaining tasks are queued waiting for currently running task to finish.
public class SequentialParallelComparison {

	public static void main(String[] args) {
		String[] strings = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };

		System.out.println("-------\nRunning sequential\n-------");
		run(Arrays.stream(strings).sequential());
		System.out.println("-------\nRunning parallel\n-------");
		run(Arrays.stream(strings).parallel());
	}

	public static void run(Stream<String> stream) {
		stream.forEach(s -> {
			System.out.println(LocalTime.now() + " - value: " + s + " - thread: " + Thread.currentThread().getName());
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
	}

}

Output:

-------
Running sequential
-------
17:58:12.238 - value: 1 - thread: main
17:58:12.455 - value: 2 - thread: main
17:58:12.707 - value: 3 - thread: main
17:58:12.915 - value: 4 - thread: main
17:58:13.120 - value: 5 - thread: main
17:58:13.325 - value: 6 - thread: main
17:58:13.532 - value: 7 - thread: main
17:58:13.739 - value: 8 - thread: main
17:58:13.946 - value: 9 - thread: main
17:58:14.152 - value: 10 - thread: main
-------
Running parallel
-------
17:58:14.458 - value: 7 - thread: main
17:58:14.459 - value: 3 - thread: ForkJoinPool.commonPool-worker-1
17:58:14.459 - value: 9 - thread: ForkJoinPool.commonPool-worker-2
17:58:14.459 - value: 2 - thread: ForkJoinPool.commonPool-worker-3
17:58:14.659 - value: 6 - thread: main
17:58:14.674 - value: 5 - thread: ForkJoinPool.commonPool-worker-1
17:58:14.674 - value: 10 - thread: ForkJoinPool.commonPool-worker-2
17:58:14.674 - value: 1 - thread: ForkJoinPool.commonPool-worker-3
17:58:14.862 - value: 4 - thread: main
17:58:14.878 - value: 8 - thread: ForkJoinPool.commonPool-worker-1

3. Run javascript code in java.

  • Nashorn is a JavaScript engine. It is used to execute JavaScript code dynamically at JVM (Java Virtual Machine). Java provides a command-line tool jjs which is used to execute JavaScript code.
  • You can execute JavaScript code by using jjs command-line tool and by embedding into Java source code.

Executing by Using Terminal

hello.js

var hello = function(){  
    print("Hello Nashorn");  
};  
hello();

Open CMD

jjs hello.js

Output:

Hello Nashorn

Executing JavaScript file in Java Code

import javax.script.*;
import java.io.*;
public class NashornExample {
    public static void main(String[] args) throws Exception{
        // Creating script engine
        ScriptEngine ee = new ScriptEngineManager().getEngineByName("Nashorn");
        // Reading Nashorn file
        ee.eval(new FileReader("js/hello.js"));
    }
}

Output:

Hello Nashorn

Embedding JavaScript Code in Java Source File

import javax.script.*;  
public class NashornExample {  
    public static void main(String[] args) throws Exception{  
        // Creating script engine  
        ScriptEngine ee = new ScriptEngineManager().getEngineByName("Nashorn");  
        // Evaluating Nashorn code  
        ee.eval("print('Hello Nashorn');");  
    }  
} 

Output:

Hello Nashorn

4. Reduction

  • A reduction operation (also called a fold) takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation, such as finding the sum or maximum of a set of numbers, or accumulating elements into a list. The streams classes have multiple forms of general reduction operations, called reduce() and collect(), as well as multiple specialized reduction forms such as sum(), max(), or count().
  • Of course, such operations can be readily implemented as simple sequential loops, as in:
int sum = 0;
for (int x : numbers) {
   sum += x;
}
  • However, there are good reasons to prefer a reduce operation over a mutative accumulation such as the above. Not only is a reduction “more abstract” — it operates on the stream as a whole rather than individual elements — but a properly constructed reduce operation is inherently parallelizable, so long as the function(s) used to process the elements are associative and stateless. For example, given a stream of numbers for which we want to find the sum, we can write:
int sum = numbers.stream().reduce(0, (x,y) -> x+y);
   OR
int sum = numbers.stream().reduce(0, Integer::sum);
  • These reduction operations can run safely in parallel with almost no modification:
int sum = numbers.parallelStream().reduce(0, Integer::sum);

5. Functions

  • A function is a block of statements that performs a specific task. Functions accept data, process it, and return a result. Functions are written primarily to support the concept of re usability. Once a function is written, it can be called easily, without having to write the same code again and again.
  • Functional Programming revolves around first class functions, pure functions and high order functions.
    • A First Class Function is the one that uses first class entities like String, numbers which can be passed as arguments, can be returned or assigned to a variable.
    • A High Order Function is the one which can take a function as an argument and/or can return a function.
    • A Pure Function is the one which has no side effect while its execution.

6. High Order Functions

  • A function is considered as a High Order function if it fulfils any one of the following conditions.
    • It takes one or more parameters as functions.
    • It returns a function after its execution.
  • Java 8 Collections.sort() method is an ideal example of a high order function. It accepts a comparing method as an argument. See the example below −
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class FunctionTester {    
   public static void main(String[] args) {               
      List<Integer> numbers = Arrays.asList(3, 4, 6, 7, 9);

      //Passing a function as lambda expression
      Collections.sort(numbers, (a,b) ->{ return a.compareTo(b); });

      System.out.println(numbers);
      Comparator<Integer> comparator = (a,b) ->{ return a.compareTo(b); };
      Comparator<Integer> reverseComparator = comparator.reversed();
      
      //Passing a function
      Collections.sort(numbers, reverseComparator);
      System.out.println(numbers);
   } 
}

Output:

[3, 4, 6, 7, 9]
[9, 7, 6, 4, 3]

7. First Class Function

  • A function is called a first class function if it fulfills the following requirements.
    • It can be passed as a parameter to a function.
    • It can be returned from a function.
    • It can be assigned to a variable and then can be used later.
  • Java 8 supports functions as first class object using lambda expressions. A lambda expression is a function definition and can be assigned to a variable, can be passed as an argument and can be returned. See the example below −
@FunctionalInterface
interface Calculator<X, Y> {    
   public X compute(X a, Y b);
}

public class FunctionTester {    
   public static void main(String[] args) {               
      //Assign a function to a variable
      Calculator<Integer, Integer> calculator = (a,b) -> a * b;

      //call a function using function variable
      System.out.println(calculator.compute(2, 3));

      //Pass the function as a parameter
      printResult(calculator, 2, 3);

      //Get the function as a return result
      Calculator<Integer, Integer> calculator1 = getCalculator();
      System.out.println(calculator1.compute(2, 3));
   }

   //Function as a parameter
   static void printResult(Calculator<Integer, Integer> calculator, Integer a, Integer b){
      System.out.println(calculator.compute(a, b));
   }

   //Function as return value
   static Calculator<Integer, Integer> getCalculator(){
      Calculator<Integer, Integer> calculator = (a,b) -> a * b;
      return calculator;
   }
}

Output

6
6
6

8. Pure Function

  • A function is considered as Pure Function if it fulfils the following two conditions −
    • It always returns the same result for the given inputs and its results purely depends upon the inputs passed.
    • It has no side effects means it is not modifying any state of the caller entity.
  • Example- Pure Function
public class FunctionTester {    
   public static void main(String[] args) {
      int result = sum(2,3);
      System.out.println(result);
  
      result = sum(2,3);
      System.out.println(result);
   }
   static int sum(int a, int b){
      return a + b;
   }
}

Output
5
5
  • Here sum() is a pure function as it always return 5 when passed 2 and 3 as parameters at different times and has no side effects.
  • Example- Impure Function
public class FunctionTester {
   private static double valueUsed = 0.0; 
   public static void main(String[] args) {
      double result = randomSum(2.0,3.0);
      System.out.println(result);
      result = randomSum(2.0,3.0);
      System.out.println(result);
   }
   
   static double randomSum(double a, double b){
      valueUsed = Math.random();       
      return valueUsed + a + b;
   }
}

Output
5.919716721877799
5.4830887819586795
  • Here randomSum() is an impure function as it return different results when passed 2 and 3 as parameters at different times and modifies state of instance variable as well.

9. Eager vs Lazy Evaluation

  • Eager evaluation means expression is evaluated as soon as it is encountered where as lazy evaluation refers to evaluation of an expression when needed. See the following example to under the concept.
import java.util.function.Supplier;

public class FunctionTester {
   public static void main(String[] args) {
      String queryString = "password=test";
      System.out.println(checkInEagerWay(hasName(queryString)
         , hasPassword(queryString)));
      System.out.println(checkInLazyWay(() -> hasName(queryString)
         , () -> hasPassword(queryString)));
   }

   private static boolean hasName(String queryString){
      System.out.println("Checking name: ");
      return queryString.contains("name");
   }

   private static boolean hasPassword(String queryString){
      System.out.println("Checking password: ");
      return queryString.contains("password");
   } 

   private static String checkInEagerWay(boolean result1, boolean result2){
      return (result1 && result2) ? "all conditions passed": "failed.";
   }

   private static String checkInLazyWay(Supplier<Boolean> result1, Supplier<Boolean> result2){
      return (result1.get() && result2.get()) ? "all conditions passed": "failed.";
   }
}

Output

Checking name: 
Checking password: 
failed.
Checking name: 
failed.
  • Here checkInEagerWay() function first evaluated the parameters then executes its statement. Whereas checkInLazyWay() executes its statement and evaluates the parameter on need basis. As && is a short-circuit operator, checkInLazyWay only evaluated first parameter which comes as false and does not evaluate the second parameter at all.

10. Parallelism

  • Parallelism is a key concept of functional programming where a big task is accomplished by breaking in smaller independent tasks and then these small tasks are completed in a parallel fashion and later combined to give the complete result. With the advent of multi-core processors, this technique helps in faster code execution.
  • Java 8 onwards, stream have parallel method and collections has parallelStream() method to complete tasks in parallel fashion.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class FunctionTester {
   public static void main(String[] args) {

      Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 };
      List<Integer> listOfIntegers = new ArrayList<>(Arrays.asList(intArray));

      System.out.println("List using Serial Stream:");
      listOfIntegers
         .stream()
         .forEach(e -> System.out.print(e + " "));
      System.out.println("");

      System.out.println("List using Parallel Stream:");
      listOfIntegers
         .parallelStream()
         .forEach(e -> System.out.print(e + " "));
      System.out.println("");

      System.out.println("List using Another Parallel Stream:");
      listOfIntegers
         .stream()
         .parallel()
         .forEach(e -> System.out.print(e + " "));
      System.out.println("");

      System.out.println("List using Parallel Stream but Ordered:");
      listOfIntegers
         .parallelStream()
         .forEachOrdered(e -> System.out.print(e + " "));
         System.out.println(""); 
   } 
}

Output

List using Serial Stream:
1 2 3 4 5 6 7 8 
List using Parallel Stream:
6 5 8 7 3 4 2 1 
List using Another Parallel Stream:
6 2 1 7 4 3 8 5 
List using Parallel Stream but Ordered:
1 2 3 4 5 6 7 8

11. Infinite Streams

  • Collections are in-memory data structure which have all the elements present in the collection and we have external iteration to iterate through collection whereas Stream is a fixed data structure where elements are computed on demand and a Stream has inbuilt iteration to iterate through each element.
  • Example – Infinite Stream
import java.util.stream.Stream;

public class FunctionTester {    
   public static void main(String[] args) {
      //create a stream of numbers which are multiple of 3 
      Stream<Integer> numbers = Stream.iterate(0, n -> n + 3);

      numbers
         .limit(10)
         .forEach(System.out::println);
   }   
}

Output
0
3
6
9
12
15
18
21
24
27
  • In order to operate on infinite stream, we’ve used limit() method of Stream interface to restrict the iteration of numbers when their count become 10.

12. Fixed length Streams

  • There are multiple ways using which we can create fix length streams.
    • Using Stream.of() method
    • Using Collection.stream() method
    • Using Stream.builder() method
  • Example – Fix Length Stream
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class FunctionTester {    
   public static void main(String[] args) {

      System.out.println("Stream.of():");
      Stream<Integer> stream  = Stream.of(1, 2, 3, 4, 5);       
      stream.forEach(System.out::println);

      System.out.println("Collection.stream():");
      Integer[] numbers = {1, 2, 3, 4, 5};     
      List<Integer> list = Arrays.asList(numbers);
      list.stream().forEach(System.out::println);

      System.out.println("StreamBuilder.build():");
      Stream.Builder<Integer> streamBuilder = Stream.builder();
      streamBuilder.accept(1);
      streamBuilder.accept(2);
      streamBuilder.accept(3);
      streamBuilder.accept(4);
      streamBuilder.accept(5);
      streamBuilder.build().forEach(System.out::println);    
   }   
}

Output

Stream.of():
1
2
3
4
5
Collection.stream():
1
2
3
4
5
StreamBuilder.build():
1
2
3
4
5

40. Solving Real Time Queries Using Java 8 Features – Employee Management System

https://34codefactory.wordpress.com/2020/10/26/java-8-solving-real-time-queries-using-java-8-features-employee-management-system/

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s