Java 8 Interview Questions
Java 8 Interview Questions
Java 8 Interview Questions
Pipelines and streams enrich the Java collections framework. Sequence of aggregate
operations is a pipeline. Stream is used to propagate elements from a source through a
pipeline. It is a sequence of elements. Pipeline and streams will make our task easier in
accessing the elements from collections and applying operations on it.
Pre Java 8, date and time related operations are little bit cumbersome. JSR 310: Date and
Time API give us a brand new package java.time package. This is a well thought
package. It contains a best list of utility methods used for regular operations. This will
help in handling date and time operations in an easier way.
4. Default Methods
Default methods gives the ability to add default implementation for methods in an
interface. This is a rocking feature of Java 8. When we implement an interface, if we did
not provide implementation for a method, then the default method will be used in that
place. This will help in maintaining backward compatibility in applications, we can add a
method to an interface without breaking its implementations.
5. Type Annotations
Before Java 8 Java annotations can be applied to type declarations. From this Java 8
release onwards, annotations can be applied to type use. Annotations can be applied
wherever a type is used like in new instance creates, exception throws clause etc. This
will help to enforce stronger type checks and using this feature we can come up with a
type checking framework itself.
Nashorn is a brand new JavaScript engine provided along with the Java 8 release. Using
this we can develop standalone JavaScript applications in Java. Pre Java 8, we got JDK
with a JavaScript engine based on Rhino. It is a developed from scratch. It will provide
better compatibility with ECMA normalized JavaScript specification and better
performance than Rhino. Already we have seen a tutorial to run Javascript in Java using
the ScriptEngineManager.
7. Concurrent Accumulators
8. Parallel operations
Iterating over a collection can be done in parallel using the aggregate operations easily.
Pre Java 8 Iterators are used to parse the elements of a collection one by on explicitly.
Now that can be done in parallel internally with the use of streams and aggregate
operations. We can create multiple substreams and those substreams can be processed
internally in parallel and then the results be combined. For this to be effective, we need to
have multiple cores and data volume.
The PermGen space is removed from Java 8 and instead we have MetaSpace introduced.
One of the most dreaded error, “java.lang.OutOfMemoryError: PermGen error” will no
longer be seen from Java 8. Nice thing is that the MetaSpace default is unlimited and that
the system memory itself becomes the memory.
Server Name Indentification (SNI) is an extension of the TLS protocol used for
identifying the certificate to serve based on the hostname specified by the client. This
enables a server to have virtual host over HTTPS. The same IP address can be used for
multiple hosts and their respective different security certificates.
The above list of Java 8 features is just a highlight. I will be writing detailed tutorials about each
of them in the coming days.
Parameter List
“->” is known as Lambda Arrow operator. It separates parameters list and body.
The type of “Journal Dev” is java.lang.String. The type of “true” is Boolean. In the same
way, what is the type of a Lambda Expression?
The Type of a Lambda Expression is a Functional Interface.
This Lambda Expression does not have parameters and does return any results. So it’s type is
“java.lang.Runnable” Functional Interface.
This Lambda Expression does not have parameters and does return any results. So it’s type is
“java.lang.Runnable” Functional Interface.
7. What is the meaning of following lambda expression?
Recently, we can observe drastic changes in Hardware. Now-a-days, all systems are
using Multi-Core CPUs (2,4,8,16-Core etc.) to deploy and run their Applications. We
need new Programming Constructs in Java to utilize these Multi-Core Processors
efficiently to develop Highly Concurrently and Highly Scalable applications.
To Utilize FP Features
One of the benefits of using lambda expression is the reduced amount of code. See the example
below.
We know that in Java lambda can be used only with functional interfaces. In the above
example, Runnable is a functional interface, so we can easily apply lambda expression
here
In this case, we are not passing any parameter in lambda expression because the run()
method of the functional interface (Runnable) takes no argument.
Also, the syntax of the lambda expression says that we can omit curly braces ({}) in case
of a single statement in the method body. In case of multiple statements, we should use
curly braces as done in the above example.
Prior to Java 8, processing the elements of any collection could be done by obtaining an iterator
from the collection and then iterating over the elements and then processing each element. If the
requirement is to process the elements in parallel, it would be done by the client code. With the
introduction of Stream API in Java 8, functions can be passed to collection methods and now it is
the responsibility of collection to process the elements either in a sequential or parallel manner.
Using Stream API’s and lambda expression we can achieve higher efficiency (parallel execution)
in case of bulk operations on collections. Also, the lambda expressions can help in achieving
internal iteration of collections rather than external iteration as shown in the above example. As
nowadays we have CPUs with multicores, we can take advantage of these multicore CPU’s by
parallel processing of collections using lambda.
Lambda expressions can be used anywhere in Java 8 where we have a target type. In Java, we
have target type in the following contexts
With lambda expressions, the goal is to minimize as many of the drawbacks to using a single
class or anonymous inner class when implementing a functional interface, while at the same time
maximizing the benefits. If you look at the Comparator example implemented using a lambda
expression in Java, there’s no debating the fact that the code is much more concise and compact.
This simple example of lambda expressions is only sufficient to demonstrate a few of the
benefits of lambda expressions in Java as compared to other approaches. As you explore lambda
expressions at a more advanced level, you will discover how they also make iterative processing
easier using the new, functional forEach method. And because lambda expressions can be
assigned to a variable, they provide an opportunity for reuse that simply isn’t possible with
anonymous inner classes.
It took a long time for lambda expression to finally make it into the Java language, but given the
benefits of using lambda expressions in Java code, it’s no wonder that developers are excited
when their target deployment platform gets upgraded to a newer version of the JDK.
When we want perform Database like Operations. For instance, we want perform groupby
operation, orderby operation etc.
When want to Perform operations Lazily.
When we want to write Functional Style programming.
When we want to perform Parallel Operations.
When want to use Internal Iteration
When we want to perform Pipelining operations.
When we want to achieve better performance.
3. Intermediate Operations are evaluated Lazily. Terminal Operations are evaluated Eagerly.
We can chain any number of Stream We can NOT chain Stream Terminal
4.
Intermediate Operations. Operations.
We can use any number of Stream We can use only one Stream Terminal
5.
Intermediate Operations per Statement. Operation per Statement.
It uses Internal Iteration concept to iterate It uses External Iteration concept to iterate
4.
Streams. Collections.
We can use Spliterator to iterate Streams in We can use Iterator to iterate Collections
5.
Parallel and Sequential order. only in Sequential order.
We can get Spliterator by calling spliterator() We can get Iterator by calling iterator()
6.
method on Stream Object. method on Collection Object.
Here we have assigned some String values at right side, but not defined it’s type. Java
Compiler automatically infers it’s type and creates a String of Array.
Java 7:-
Oracle Corporation has introduced “Diamond Operator” new feature in Java SE 7 to avoid
unnecessary Type definition in Generics.
Map<String,List<Customer>> customerInfoByCity = new HashMap<>();
Here we have not defined Type information at right side, simply defined Java SE 7’s
Diamond Operator “”.
Java SE 8:-
Oracle Corporation has enhanced this Type Inference concept a lot in Java SE 8. We use this
concept to define Lambda Expressions, Functions, Method References etc.
Here Java Compiler observes the type definition available at left-side and determines the type
of Lambda Expression parameters a and b as Integers.
Lets see how simple it is to say print all elements in an ArrayList in Java 8 using an example of
internal iterator based forEach loop –
import java.util.*;
public class InternalIterator {
public static void main(String args[]){
List<String> namesList=Arrays.asList("Tom", "Dick", "Harry");
namesList.forEach(name -> System.out.println(name));//Internal Iteration
}
}
In the above code, we are just telling the forEach method what to do(i.e. print) with each String in the
namesList list using a lambda expression( In case you are not familiar with lambda expressions you
can read the tutorial here).
All the work of iterating over the list of names one by one and printing them is taken care of
internally by the runtime, leaving us with just declaratively defining only what is to be done i.e.
print the names.
The forEach method comes under the category of terminal operations when working with streams i.e.
it ends the chain of pipelined operations to produce a result.
Note – You can also use internal iterators with parallelStream() method instead of a stream to
improve on the performance.
23. What are the main differences between Internal and External
Iterator?
Iterating elements in Sequential and In-Order Not required to iterate elements in Sequential
4.
only. order.
If we want to perform some check or operation for a particular index then external iterators are
preferred over internal ones.
Default Methods
Static Methods
31. What are the core ideas behind the Date/Time API of Java 8?
Java’s OLD Java Date API means Date API available before Java SE 8 that is Date,
Calendar, SimpleDateFormat etc.
Java’s Old Date API has the following Issues or Drawbacks compare to Java 8’s Date and
Time API and Joda Time API.
33. What are the main differences between legacy Date/Time API
in Java and Date/Time API of Java 8?
S.No. Java’s OLD Java Date API Java 8’s Date and Time API
It defines months values from 0 to 11, that is It defines months values from 1 to 12, that is
8.
January = 0. January = 1.
34. How can we get duration between two dates or time in Java
8?
If you want logical calendar days, use DAYS.between() method from
java.time.temporal.ChronoUnit:
LocalDate dateBefore;
LocalDate dateAfter;
long daysBetween = DAYS.between(dateBefore, dateAfter);
If you want literal 24 hour days, (a duration), you can use the Duration class instead:
This parallel set of methods provides parallel processing of Arrays that can run Java code very
fast on a multi core machine.
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.
This above diagram shows Diamond Problem. To avoid this problem, Java 7 and Earlier versions
does not support methods implementation in interface and also doesn’t support Multiple
Inheritance. Java 8 has introduced new feature: Default methods to support Multiple Inheritance
with some limitations.
public interface A{
default void display() { //code goes here }
}
public interface B extends A{ }
public interface C extends A{ }
public class D implements B,C{ }
In the above code snippet, class D gives compiltime errors because Java Compiler will get bit
confusion about which display() has to provide in class D. Class D inherits display() method
from both interfaces B and C. To solve this problem, Java SE 8 has given the following remedy:
public interface A{
default void display() { //code goes here }
}
public interface B extends A{ }
public interface C extends A{ }
public class D implements B,C{
void display() {
B.super.display();
}
}
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.
39. Is it possible to have default method definition in an interface
without marking it with default keyword?
No, Compiler complains that its an abstract method and hence shouldn't
have the body.
42. How can you get the name of Parameter in Java by using
reflection?
Java Optional Class : Every Java Programmer is familiar with NullPointerException. It can
crash your code. And it is very hard to avoid it without using too many null checks.
Java 8 has introduced a new class Optional in java.util package. It can help in writing a neat
code without using too many null checks. By using Optional, we can specify alternate values
to return or alternate code to run. This makes the code more readable because the facts which
were hidden are now visible to the developer.
// Java program without Optional Class
public class OptionalDemo{
public static void main(String[] args) {
String[] words = new String[10];
String word = words[5].toLowerCase();
System.out.print(word);
}
}
Output :
To avoid abnormal termination, we use the Optional class. In the following example, we are
using Optional. So, our program can execute without crashing.
Optional is a container object which may or may not contain a non-null value. You must import
java.util package to use this class. If a value is present, isPresent() will return true and get() will
return the value. Additional methods that depend on the presence or absence of a contained value
are provided, such as orElse() which returns a default value if value not present and ifPresent()
which executes a block of code if the value is present. This is a value-based class, i.e their
instances are :
Following table shows the list of Static Methods provided by Optional Class :
Following table shows the list of Instance Methods provided by Optional Class :
package com.javainuse.model;
}
Consider the class ItemProcessor which returns an instance of Item class-
package com.javainuse;
import com.javainuse.model.Item;
}
}
When we call the getItem(), the item instance is returned. We first have to check for null else this
may cause NullPointerException.
Now lets consider the use of Optional. Instead of item instance we return optional.
package com.javainuse;
import java.util.Optional;
import com.javainuse.model.Item;
}
}
Here first check if the optional element is present and only then process it. No null checks are
required.
One of the most common performance-related practices is to initialize the heap memory as per
the application requirements.
That's why we should specify minimal and maximal heap size. Below parameters can be used for
achieving it:
1-Xms<heap size>[unit]
2-Xmx<heap size>[unit]
Here, unit denotes the unit in which the memory (indicated by heap size) is to be initialized.
Units can be marked as ‘g' for GB, ‘m' for MB and ‘k' for KB.
1-Xms2G -Xmx5G
Starting with Java 8, the size of Metaspace is not defined. Once it reaches the global limit, JVM
automatically increases it, However, to overcome any unnecessary instability, we can set
Metaspace size with:
1-XX:MaxMetaspaceSize=<metaspace size>[unit]
Here, metaspace size denotes the amount of memory we want to assign to Metaspace.
As per Oracle guidelines, after total available memory, the second most influential factor is the
proportion of the heap reserved for the Young Generation. By default, the minimum size of the
YG is 1310 MB, and maximum size is unlimited.
1-XX:NewSize=<young size>[unit]
2-XX:MaxNewSize=<young size>[unit]
3. Garbage Collection
For better stability of the application, choosing of right Garbage Collection algorithm is critical.
1-XX:+UseSerialGC
2-XX:+UseParallelGC
3-XX:+USeParNewGC
4-XX:+UseG1GC
4. GC Logging
To strictly monitor the application health, we should always check the JVM's Garbage
Collection performance. The easiest way to do this is to log the GC activity in human readable
format.
1-XX:+UseGCLogFileRotation
2-XX:NumberOfGCLogFiles=< number of log files >
UseGCLogFileRotation specifies the log file rolling policy, much like log4j, s4lj, etc.
NumberOfGCLogFiles denotes the max number of log files that can be written for a single
application life cycle. GCLogFileSize specifies the max size of the file. Finally, loggc denotes its
location.
Point to note here is that, there are two more JVM parameters available (-
XX:+PrintGCTimeStamps and -XX:+PrintGCDateStamps) which can be used to print date-wise
timestamp in the GC log.
For example, if we want to assign a maximum of 100 GC log files, each having a maximum size
of 50 MB and want to store them in ‘/home/user/log/' location, we can use below syntax:
1-XX:+UseGCLogFileRotation
2-XX:NumberOfGCLogFiles=10
3-XX:GCLogFileSize=50M
4-Xloggc:/home/user/log/gc.log
However, the problem is that one additional daemon thread is always used for monitoring system
time in the background. This behavior may create some performance bottleneck; that's why it's
always better not to play with this parameter in production.
It's very common for a large application to face out of memory error which, in turn, results in the
application crash. It's a very critical scenario and very hard to replicate to troubleshoot the issue.
That's why JVM comes with some parameters which dump heap memory into a physical file
which can be used later for finding out leaks:
1-XX:+HeapDumpOnOutOfMemoryError
2-XX:HeapDumpPath=./java_pid<pid>.hprof
4-XX:+UseGCOverheadLimit
A couple of points to note here:
HeapDumpOnOutOfMemoryError instructs the JVM to dump heap into physical file in case of
OutOfMemoryError
HeapDumpPath denotes the path where the file is to be written; any filename can be given;
however, if JVM finds a <pid> tag in the name, the process id of the current process causing the
out of memory error will be appended to the file name with .hprof format
OnOutOfMemoryError is used to issue emergency commands to be executed in case of out of
memory error; proper command should be used in the space of cmd args. For example, if we
want to restart the server as soon as out of memory occur, we can set the parameter:
1-XX:OnOutOfMemoryError="shutdown -r"
UseGCOverheadLimit is a policy that limits the proportion of the VM's time that is spent in GC
before an OutOfMemory error is thrown
6. 32/64 Bit
In the OS environment where both 32 and 64-bit packages are installed, the JVM automatically
chooses 32-bit environmental packages.
If we want to set the environment to 64 bit manually, we can do so using below parameter:
1-d<OS bit>
OS bit can be either 32 or 64. More information about this can be found here.
7. Misc
-server: enables “Server Hotspot VM”; this parameter is used by default in 64 bit JVM
-XX:+UseStringDeduplication: Java 8u20 has introduced this JVM parameter for reducing the
unnecessary use of memory by creating too many instances of the same String; this optimizes
the heap memory by reducing duplicate String values to a single global char[] array
-XX:+UseLWPSynchronization: sets LWP (Light Weight Process) – based synchronization policy
instead of thread-based synchronization
-XX:LargePageSizeInBytes: sets the large page size used for the Java heap; it takes the argument
in GB/MB/KB; with larger page sizes we can make better use of virtual memory hardware
resources; however, this may cause larger space sizes for the PermGen, which in turn can force
to reduce the size of Java heap space
-XX:MaxHeapFreeRatio: sets the maximum percentage of heap free after GC to avoid shrinking.
-XX:MinHeapFreeRatio: sets the minimum percentage of heap free after GC to avoid expansion;
to monitor the heap usage you can use VisualVM shipped with JDK.
-XX:SurvivorRatio: Ratio of eden/survivor space size – for example, -XX:SurvivorRatio=6 sets the
ratio between each survivor space and eden space to be 1:6,
-XX:+UseLargePages: use large page memory if it is supported by the system; please note that
OpenJDK 7 tends to crash if using this JVM parameter
-XX:+UseStringCache: enables caching of commonly allocated strings available in the String pool
-XX:+UseCompressedStrings: use a byte[] type for String objects which can be represented in
pure ASCII format
-XX:+OptimizeStringConcat: it optimizes String concatenation operations where possible
Java 8 has included two new features repeating and type annotations in its prior annotations
topic. In early Java versions, you can apply annotations only to declarations. After releasing
of Java SE 8 , annotations can be applied to any type use. It means that annotations can be
used anywhere you use a type. For example, if you want to avoid NullPointerException in
your code, you can declare a string variable like this:
1. @NonNull List<String>
Note - Java created type annotations to support improved analysis of Java programs. It
supports way of ensuring stronger type checking.
In Java 8 release, Java allows you to repeating annotations in your source code. It is
helpful when you want to reuse annotation for the same class. You can repeat an
annotation anywhere that you would use a standard annotation.
For compatibility reasons, repeating annotations are stored in a container annotation that
is automatically generated by the Java compiler. In order for the compiler to do this, two
declarations are required in your code.
Declaring of repeatable annotation type must be marked with the @Repeatable meta-
annotation. In the following example, we have defined a custom @Game repeatable
annotation type.
1. @Repeatable(Games.class)
2. @interfaceGame{
3. String name();
4. String day();
5. }
Containing annotation type must have a value element with an array type. The component
type of the array type must be the repeatable annotation type. In the following example,
we are declaring Games containing annotation type:
1. @interfaceGames{
2. Game[] value();
3. }
Note - Compiler will throw a compile-time error, if you apply the same annotation to a
declaration without first declaring it as repeatable.
Simply put, it can be used for joining Strings making use of a delimiter, prefix, and suffix.
@Test
public void whenAddingElements_thenJoinedElements() {
StringJoiner joiner = new StringJoiner(",", PREFIX, SUFFIX);
joiner.add("Red")
.add("Green")
.add("Blue");
assertEquals(joiner.toString(), "[Red,Green,Blue]");
}
If we want to join all elements of a list, we'll have to loop through the list. Unfortunately, there's no easy
way to do it using StringJoiner:
@Test
public void whenAddingListElements_thenJoinedListElements() {
List<String> rgbList = new ArrayList<>();
rgbList.add("Red");
rgbList.add("Green");
rgbList.add("Blue");
assertEquals(rgbJoiner.toString(), "[Red,Green,Blue]");
}
Abstract class can define constructor. They are more structured and can have a state associated
with them. While in contrast, default method can be implemented only in the terms of invoking
other interface methods, with no reference to a particular implementation's state. Hence, both use
for different purposes and choosing between two really depends on the scenario context.
Default methods in Java interface enables interface evolution. Given an existing interface, if you
wish to add a method to it without breaking the binary compatibility with older versions of the
interface, you have two options at hands: add a default or a static method. Indeed, any abstract
method added to the interface would have to be implemented by the classes or interfaces
implementing this interface.
A static method is unique to a class. A default method is unique to an instance of the class. If you
add a default method to an existing interface, classes and interfaces which implement this
interface do not need to implement it.
54. https://www.javainuse.com/java/java8_intvw
55. https://www.wisdomjobs.com/e-university/java-8-interview-questions.html
56.
Investment banks
https://www.codementor.io/savingfunda/20-java-interview-questions-and-answers-from-
investment-banks-98ghl6frw
https://dzone.com/articles/technical-job-interview