Learn logic and coding with the help of source code available here. Enhance your programming skills by practicing. You should try to code yourself, if you are stuck some where, then you should take help from others.
If you have any queries or suggestion please feel free to comment......
Thank You!
Primary purpose of java serialization is to write an object into a
stream, so that it can be transported through a network and that object
can be rebuilt again. When there are two different parties involved, you
need a protocol to rebuild the exact same object again. Java
serialization API just provides you that. Other ways you can leverage
the feature of serialization is, you can use it to perform a deep copy. Why I used ‘primary purpose’ in the above definition is, sometimes
people use java serialization as a replacement for database. Just a
placeholder where you can persist an object across sessions. This is not
the primary purpose of java serialization. Sometimes, when I interview
candidates for Java I hear them saying java serialization is used for
storing (to preserve the state) an object and retrieving it. They use it
synonymously with database. This is a wrong perception for
serialization.
How do you serialize?
When you want to serialize an object, that respective class should implement the marker interface
serializable. It just informs the compiler that this java class can be
serialized. You can tag properties that should not be serialized as
transient. You open a stream and write the object into it. Java API
takes care of the serialization protocol and persists the java object in
a file in conformance with the protocol. De-serialization is the
process of getting the object back from the file to its original form. Here protocol means, understanding between serializing person and
de-serializing person. What will be the contents of file containing the
serialized object? This serves as a guideline to de-serialize. Have a
look at the following sample and how its serialized file looks.
Look at following image. After serializing ‘SerializationBox’ in the
above sample code, I opened the output in a hex editor. You can use
Notepad++ and hex plugin to open the serialized file. Let us look at contents byte by byte and find out what they are. It
starts with “ac ed”. It is is called STREAM_MAGIC. It is a magic number
(java API guys says) that is written to the stream header. It denotes
that is start of serialzed content. Similarly every character has a meaning. Actually the serialized file
is more bulkier than you would expect, as it has a huge header the meta
information of the classes involved and finally the content. Object Serialization Stream Protocol have a look at chapter 6.4.2 Terminal Symbols and Constants. It gives you list of symbols and constants used in serialization.
Decrypting Serialized Java Object
In the image, I have underline a unit of information in a separate color for you to easily identify. ac ed – STREAM_MAGIC – denotes start of serialzed content
00 05 – STREAM_VERSION – serialization version
73 – TC_OBJECT – new Object
72 – TC_CLASSDESC – new Class Descriptor
00 26 – length of the class name
63 6f 6d 2e 6a 61 76 61 70 61 70 65 72 73 2e 73 61 6d 70 6c 65 2e 53 65 72 69 61 6c 69 7a 61 74 69 6f 6e 42 6f 78 – class name
57 fc 83 ca 02 85 f0 18 – SerialVersionUID
02 – this object is serializable
00 01 – count of properties in the serialzed class – one property in our example
42 00 10 – private byte
73 65 72 69 61 6c 69 7a 61 62 6c 65 50 72 6f 70 78 70 – property name – serializableProp in our example
0a – 10 the value – This is the persisted value of the property in our sample Q2. What is the use of seriaversionUID while implementing the Serializable interface? private static final long serialVersionUID = 1L; Ans:
How serialVersionUID is generated?
serialVersionUID is a 64-bit hash of the class name, interface class
names, methods and fields. Serialization runtime generates a
serialVersionUID if you do not add one in source. Refer this link for the algorithm to generate serialVersionUID. It is advised to have serialVersionUID as unique as possible. Thats
why the java runtime chose to have such a complex algorithm to generate
it. If you want help in generating it, jdk tools provides a tool named serialver. Use serialver -show to start the gui version of the tool as shown below.
How serialVersionUID works?
When an object is serialized, the serialVersionUID is serialized along with the other contents. Later when that is deserialized, the serialVersionUID from the
deserialized object is extracted and compared with the serialVersionUID
of the loaded class. If the numbers do not match then, InvalidClassException is thrown. If the loaded class is not having a serialVersionUID declared, then
it is automatically generated using the same algorithm as before.
Strongly recommended to declare serialVersionUID
Javadocs says,
“the default serialVersionUID computation is highly
sensitive to class details that may vary depending on compiler
implementations, and can thus result in unexpected
InvalidClassExceptions during deserialization”
Now you know why we should declare a serialVersionUID. Not only declaring a serialVersionUID is sufficient. You must do the
following two things carefully. Otherwise it defeats the purpose of
having the serialVersionUID. serialVersionUID should be maintained. As and when you change anything in the class, you should upgrade the serailVersionUID.
Try your best to declare a unique serialVersionUID.
Demonstrate serialVersionUID
Initial class to be serialized has a serialVersionUID as 1L.
Comment the “serialize” block (4 lines of code) in SerialVersionUIDTest. Now run it and you will get the following exception.
Serialized Lion with serialVersionUID with 1L.
Changed serialVersionUID to 2L and compiled and loaded the class.
Deserialize the already serialized object and load it with the latest class.
We get exception as serialVersionUID is not matching.
Exception in thread "main" java.io.InvalidClassException:Lion;
local class incompatible:stream classdesc serialVersionUID =1,
local class serialVersionUID =2
at java.io.ObjectStreamClass.initNonProxy(UnknownSource)
at java.io.ObjectInputStream.readNonProxyDesc(UnknownSource)
at java.io.ObjectInputStream.readClassDesc(UnknownSource)
at java.io.ObjectInputStream.readOrdinaryObject(UnknownSource)
at java.io.ObjectInputStream.readObject0(UnknownSource)
at java.io.ObjectInputStream.readObject(UnknownSource)
at SerialVersionUIDTest.main(SerialVersionUIDTest.java:21)
Points to remember 1. If a parent class has implemented Serializable interface then child
class doesn’t need to implement it but vice-versa is not true. 2. Only non-static data members are saved via Serialization process. 3. Static data members and transient data members are not saved via
Serialization process.So, if you don’t want to save value of a
non-static data member then make it transient. 4. Constructor of object is never called when an object is deserialized. 5. Associated objects must be implementing Serializable interface. In case of transient variables:- A variable defined with
transient keyword is not serialized during serialization process.This
variable will be initialized with default value during deserialization.
(e.g: for objects it is null, for int it is 0). In case of static Variables:- A variable defined with static
keyword is not serialized during serialization process.This variable
will be loaded with current value defined in the class during
deserialization. Q3. Difference between shallow copy and deep copy. Ans:
Shallow Copy Vs Deep Copy In Java :
Below is the list of differences between shallow copy and deep copy in java.
Shallow Copy
Deep Copy
Cloned Object and original object are not 100% disjoint.
Cloned Object and original object are 100% disjoint.
Any changes made to cloned object will be reflected in original object or vice versa.
Any changes made to cloned object will not be reflected in original object or vice versa.
Default version of clone method creates the shallow copy of an object.
To create the deep copy of an object, you have to override clone method.
Shallow copy is preferred if an object has only primitive fields.
Deep copy is preferred if an object has references to other objects as fields.
Shallow copy is fast and also less expensive.
Deep copy is slow and very expensive.
Q4. What are the ways of creating an instance of a singleton class?
What is the purpose of Singleton?
The
purpose of the Singleton class is to control object creation, limiting
the number of objects to only one. The singleton allows only one entry
point to create the new instance of the class.
Since
there is only one Singleton instance, any instance fields of a
Singleton will occur only once per class, just like static fields.
Singletons are often useful where you have to control the resources,
such as database connections or sockets.
It
seems to be a simple design pattern but when it comes to
implementation, it comes with a lot of implementation concerns. The
implementation of Singleton pattern has always been a controversial
topic among developers. Here, you are going to discuss how to create a
Singleton class that fulfills its purpose :
Restrict the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine.
Let’s create Singleton class in java and test it in different conditions.
Create Singleton class
To
implement the Singleton class, the simplest way is to make the
constructor of the class as private. There are two approaches for the
initialization.
1. Eager initialization:
In
eager initialization, the instance of Singleton Class is created at the
time of class loading, this is the easiest method to create a Singleton
class.
By making the constructor
as private you are not allowing other class to create a new instance of
the class you want to create the Singleton. Instead, you are creating
one public static method (commonly name as for getInstance()) to provide the single entry point to create the new instance of the class.
This
approach has one drawback. Here instance is created even though client
application might not be using it. This might be a considerable issue if
your Singleton class in creating a database connection or creating a
socket. This may cause the memory leak problem. The solution is to
create the new instance of the class, when needed. This can be achieved
by Lazy Initialization method.
2. Lazy initialization:
Opposite to Eager initialization, here you are going to initialize new instance of the class in getInstance() method it self.This method will check if there is any instance of that class is already created? If yes, then our method (getInstance())
will return that old instance and if not then it creates a new instance
of the singleton class in JVM and returns that instance. This approach
is called as Lazy initialization.
public class SingletonClass {
private static SingletonClass sSoleInstance;
private SingletonClass(){} //private constructor.
public static SingletonClass getInstance(){
if (sSoleInstance == null){ //if there is no instance available... create new one
sSoleInstance = new SingletonClass();
}
return sSoleInstance;
}
}
We
all know that in Java if the two objects are same then, their hash key
have to be equal. Let’s test that. If the above Singleton is correctly
implemented than below code should return the same hash key.
Below is the output log with the hash code of both the instances.
Both have the same hash.
You
can see that both the instances are having the same hash code. So, that
means above code will make the perfect Singleton. Right???? No.
Make Singleton reflection proof
In above Singleton class, by using reflection you can create more than one instance. If you don’t know what is the Java Reflection API is, Java Reflection is a process of examining or modifying the run-time behavior of a class at run time.
You
can make the new instance of the Singleton class by changing the
constructor visibility as public in run-time and create new instance
using that constructor. Run the below code and see it our Singleton
class survives?
public class SingletonTester {
public static void main(String[] args) {
//Create the 1st instance
SingletonClass instance1 = SingletonClass.getInstance();
//Create 2nd instance using Java Reflection API.
SingletonClass instance2 = null;
try {
Class<SingletonClass> clazz = SingletonClass.class;
Constructor<SingletonClass> cons = clazz.getDeclaredConstructor();
cons.setAccessible(true);
instance2 = cons.newInstance();
} catch (NoSuchMethodException | InvocationTargetException
Here is the output of hash codes of both instances.
Testing reflection
Both the instances have a different hash code. That clearly indicates that Singleton class failed this test.
Solution:
To
prevent Singleton failure while due to reflection you have to throw a
run-time exception in constructor, if the constructor is already
initialized and some class to initialize it again. Let’s update SingletonClass.java.
public class SingletonClass {
private static SingletonClass sSoleInstance;
//private constructor.
private SingletonClass(){
//Prevent form the reflection api.
if (sSoleInstance != null){
throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
}
}
public static SingletonClass getInstance(){
if (sSoleInstance == null){ //if there is no instance available... create new one
sSoleInstance = new SingletonClass();
}
return sSoleInstance;
}
}
Make Singleton thread safe
If
two threads try to initialize the Singleton class at almost the same
time, what happens? Let’s test below code in which two threads are
created almost simultaneously and they are calling getInstance().
public class SingletonTester {
public static void main(String[] args) {
//Thread 1
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
SingletonClass instance1 = SingletonClass.getInstance();
System.out.println("Instance 1 hash:" + instance1.hashCode());
}
});
//Thread 2
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
SingletonClass instance2 = SingletonClass.getInstance();
System.out.println("Instance 2 hash:" + instance2.hashCode());
}
});
//start both the threads
t1.start();
t2.start();
}
}
If you run this code many times, you will see sometimes both the threads creates different instances.
That means your Singleton class is not Thread safe. Both the threads calls out getInstance() method at the same time, the sSoleInstance == null
condition will return for both the thread. So, two different instances
of the same class will be created. That will break the singleton
principle.
Solution:
1. Make getInstance() synchronized:
Let’s make getInstance() method synchronized.
public class SingletonClass {
private static SingletonClass sSoleInstance;
//private constructor.
private SingletonClass(){
//Prevent form the reflection api.
if (sSoleInstance != null){
throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
}
}
public synchronized static SingletonClass getInstance(){
if (sSoleInstance == null){ //if there is no instance available... create new one
sSoleInstance = new SingletonClass();
}
return sSoleInstance;
}
}
As you made your getInstance() class synchronized the second thread will have to wait until the getInstance() method is completed for the first thread. This way we can achieve thread safety.
But, there are some cons of using this approach:
Slow performance because of locking overhead.
Unnecessary synchronization that is not required once the instance variable is initialized.
2. Double check locking method:
You can overcome this issue if you use Double check locking method to create the Singleton.
In
this, you will make the Singleton class in the synchronized block if
the instance is null. So, the synchronized block will be executed only
when the sSoleInstance is null and prevent unnecessary synchronization once the instance variable is initialized.
public class SingletonClass {
private static SingletonClass sSoleInstance;
//private constructor.
private SingletonClass(){
//Prevent form the reflection api.
if (sSoleInstance != null){
throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
}
}
public static SingletonClass getInstance() {
//Double check locking pattern
if (sSoleInstance == null) { //Check for the first time
synchronized (SingletonClass.class) { //Check for the second time.
//if there is no instance available... create new one
if (sSoleInstance == null) sSoleInstance = new SingletonClass();
}
}
return sSoleInstance;
}
}
3. Use volatile keyword:
On
the surface, this method looks perfect, as you only need to pay price
for synchronized block one time, but it still was broken, until you make
sSoleInstance variable volatile.
Without volatile modifier, it’s possible for another thread in Java to see half initialized state of sSoleInstance variable, but with volatile variable guaranteeing happens-before relationship, all the write will happen on volatile sSoleInstance before any read of sSoleInstance variable.
public class SingletonClass {
private static volatile SingletonClass sSoleInstance;
//private constructor.
private SingletonClass(){
//Prevent form the reflection api.
if (sSoleInstance != null){
throw new RuntimeException("Use getInstance()
method to get the single instance of this class.");
}
}
public static SingletonClass getInstance() {
//Double check locking pattern
if (sSoleInstance == null) { //Check for the first time
synchronized (SingletonClass.class) { //Check for the second time.
//if there is no instance available... create new one
if (sSoleInstance == null) sSoleInstance = new SingletonClass();
}
}
return sSoleInstance;
}
}
Now,
above Singleton class is thread safe. Making Singleton thread safe is
especially required in multi-threaded application environment like in
Android Applications.
Make Singleton safe from Serialization
Sometimes in distributed systems, you need to implement Serializableinterface in Singleton class. By doing that you can store its state in the file system and retrieve it at later point of time.
Let’s test singleton class whether it maintains single instance after serializable and deserializable operations?
public class SingletonTester {
public static void main(String[] args) {
try {
SingletonClass instance1 = SingletonClass.getInstance();
ObjectOutput out = null;
out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(instance1);
out.close();
//deserialize from file to object
ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
SingletonClass instance2 = (SingletonClass) in.readObject();
in.close();
System.out.println("instance1 hashCode=" + instance1.hashCode());
System.out.println("instance2 hashCode=" + instance2.hashCode());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
You
can see that the hash code of both the instances are different. That is
clearly violates singleton principle. The problem with above serialized
singleton class is that whenever we deserialize it, it will create a
new instance of the class.
To prevent creation of another instance you have to provide the implementation of readResolve() method. readResolve()
replaces the object read from the stream. This ensures that nobody can
create another instance by serializing and deserializing the singleton.
public class SingletonClass implements Serializable {
private static volatile SingletonClass sSoleInstance;
//private constructor.
private SingletonClass(){
//Prevent form the reflection api.
if (sSoleInstance != null){
throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
}
}
public static SingletonClass getInstance() {
if (sSoleInstance == null) { //if there is no instance available... create new one
synchronized (SingletonClass.class) {
if (sSoleInstance == null) sSoleInstance = new SingletonClass();
}
}
return sSoleInstance;
}
//Make singleton from serialize and deserialize operation.
protected SingletonClass readResolve() {
return getInstance();
}
}
At
end of the article, you can make your class a Singleton class that is
thread, reflection and serialization safe. This Singleton is still not
the perfect Singleton. You can violate the Singleton principle by
creating more than one instance of the Singleton class by using cloning
or using multiple class loaders. But for the most of the applications,
above implementation of Singleton will work perfectly.
Q4. What is the difference between map and flat map in java stream API? Ans:
In Java, Stream interface has >map() and flatMap() methods and both are intermediate stream operations and return another stream as method output. The primary difference between map() vs flatMap() is the return type of both methods.
map() is used for transformation only, but flatMap() is used for both transformation and flattening. flatMap() = map() + Flattening
1. Difference between map() and flatMap()
The map() method produces one output value for each input value in the stream. So if there are n elements in the stream, map() operation will produce a stream of n output elements.
We can use map() operation when we have a stream of objects, and we need to get some unique value for each element in the stream. There is one-to-one mapping between input and output element. For example, we can write a program to find the date of birth of all employees in a stream of employees. In case of flatMap(), a one-to-many
mapping is created where for each input element/stream, we first get a
multiple values and then we flatten the values from all such input
streams into a single output stream. For example, we may write program
to find all district words from all lines in a text file.
Q5. What are the built-in interfaces included in the java.util.function package such as Predicate, Consumer, Function, and Supplier?
Functional interfaces provide target types for lambda expressions and
method references. Each functional interface has a single abstract
method, called functional method for that functional interface, to which the lambda expression's parameter and return types are matched or adapted.
Predicate
A predicate is a statement that may be true or false depending on the
values of its variables. It can be thought of as a function that
returns a value that is either true or false.
In Java 8, a Predicate is a functional interface that can be
used anywhere you need to evaluate a boolean condition. Since it's a
functional interface, you can pass a lambda expression wherever a Predicate is expected.
See the API to know the methods of this interface.
Here's an example. First, we see how the interface with an anonymous class:
Predicate<String> isALongWord = new Predicate<String>() {
@Overridepublicbooleantest(String t){
return t.length() > 10;
}
};
String s = "successfully"boolean result = isALongWord.test(s);
And now with a lambda expression:
Predicate<String> isALongWord = t -> t.length() > 10;
String s = "successfully"boolean result = isALongWord.test(s);
Predicates are also used to filter collections, for example:
publicclassTest{
publicstaticvoidmain(String[] args){
List<String> l = new ArrayList<>();
l.add("successfully");
l.add("easy");
l.add("fortune");
List<String> filtered = l.stream().filter( s -> s.length() > 5 ).collect(Collectors.<String>toList());
System.out.println(filtered);
}
}
Here, the filter method expects a Predicate, so we can pass a lambda expression to simplify things, so the output of the example is:
["successfully", "fortune"]
Consumer
This functional interface represents an operation that accepts a
single input argument and returns no result.The real outcome is the
side-effects it produces. Since it's a functional interface, you can
pass a lambda expression wherever a Consumer is expected.
See the API to know the methods of this interface.
Here's an example:
Basically, what Consumer does is executing the assigned
lambda expression. The side-effect here, it's the updating of the
product's price, so the output is:
5.9
Function
This functional interface represents a function that accepts one
argument and produces a result. One use, for example, it's to convert
or transform from one object to another. Since it's a functional
interface, you can pass a lambda expression wherever a Function is expected.
See the API to know the methods of this interface.
Here's an example:
publicclassTest{
publicstaticvoidmain(String[] args){
int n = 5;
modifyTheValue(n, val-> val + 10);
modifyTheValue(n, val-> val * 100);
}
staticvoidmodifyValue(int v, Function<Integer, Integer> function){
int result = function.apply(v);
System.out.println(newValue);
}
}
The input parameter type and the return type of the method can either
be same or different. In this case, they are the same type and the
program just execute the functions represented by the lambda expression,
an addition and a multiplication, so the output is:
15
500
Supplier
This functional interface does the opposite of the Consumer,
it takes no arguments but it returns some value. It may return
different values when it is being called more than once. Since it's a
functional interface, you can pass a lambda expression wherever a Supplier is expected.
See the API to know the one method of this interface.
Here's an example:
publicclassProgram{
publicstaticvoidmain(String[] args){
int n = 3;
display(() -> n + 10);
display(() -> n + 100);
}
staticvoiddisplay(Supplier<Integer> arg){
System.out.println(arg.get());
}
}
Basically, a Supplier just provides values. The output of the example is:
13
103
Develop code that uses primitive versions of functional interfaces
Due to the way generics are implemented, parameters of the functional interfaces (for example, Predicate<T>) can be bound only to reference types (like String, objects, etc).
If you want to use primitive types with these functional interfaces,
Java uses a mechanism called autoboxing to automatically convert a
primitive to its corresponding wrapper type (for example, int to Integer) and vice versa.
But since boxed values use more memory, this comes with a performance
cost. For this reason, Java provides specialized versions of the
functional interfaces to avoid autoboxing operations when the inputs or
outputs are primitives.
For example, instead of using
Predicate<Integer> p = i -> i > 10;
You can use
IntPredicate p = i -> i > 10;
In general, the names of functional interfaces that have a primitive
version for the input parameter are preceded by the primitive type, like
IntPredicate.
The Function interface also has variants for the output parameter like ToIntFunction<T>.
Here's a summary of the primitive version of functional interfaces with a link to their javadoc: Predicate<T> IntPredicate. Predicate of one int-valued argument. LongPredicate. Predicate of one long-valued argument. DoublePredicate. Predicate of one double-valued argument. Consumer<T> IntConsumer. Operation that accepts a single int-valued argument and returns no result. LongConsumer. Operation that accepts a single long-valued argument and returns no result. DoubleConsumer. Operation that accepts a single double-valued argument and returns no result. Function<T, R> IntFunction<R>. Function that accepts an int-valued argument and produces a result. IntToDoubleFunction. Function that accepts an int-valued argument and produces a double-valued result. IntToLongFunction. Function that accepts an int-valued argument and produces a long-valued result. LongFunction<R>. Function that accepts a long-valued argument and produces a result. LongToDoubleFunction. Function that accepts a long-valued argument and produces a double-valued result. LongToIntFunction. Function that accepts a long-valued argument and produces an int-valued result. DoubleFunction<R>. Function that accepts a double-valued argument and produces a result. ToIntFunction<T>. Function that produces an int-valued result. ToDoubleFunction<T>. Function that produces a double-valued result. ToLongFunction<T>. Function that produces a long-valued result. Supplier<T> BooleanSupplier. Supplier of boolean-valued results. IntSupplier. Supplier of int-valued results. LongSupplier. Supplier of long-valued results. DoubleSupplier. Supplier of double-valued results. UnaryOperator<T> IntUnaryOperator. Function operation on a single int-valued operand that produces an int-valued result. LongUnaryOperator. Function operation on a single long-valued operand that produces a long-valued result. DoubleUnaryOperator. Function operation on a single double-valued operand that produces a double-valued result.
Develop code that uses binary versions of functional interfaces
The following functional interfaces:
Predicate<T>
Consumer<T>
Function<T,R>
UnaryOperator<T>
Represent an operation that takes one argument. But there are
versions of these interfaces that take two arguments called. These are
the binary versions. They have the same semantics, the only difference
is the number of arguments. Note there is no binary version of Supplier. This is because a Supplier takes no arguments.
Here's a summary of the binary versions of the functional interfaces
along with their primitive versions and a link to their javadoc: BiPredicate<L, R>
(No primitive versions) BiConsumer<T, U> ObjIntConsumer<T>. Operation that accepts an Object-valued and an int-valued argument and returns no result. ObjLongConsumer<T>. Operation that accepts an Object-valued and a long-valued argument and returns no result. ObjDoubleConsumer<T>. Operation that accepts an Object-valued and a double-valued argument and returns no result. BiFunction<T, U, R> ToIntBiFunction<T, U>. Function that accepts two arguments and produces an int-valued result. ToLongBiFunction<T, U>. Function that accepts two arguments and produces a long-valued result. ToDoubleBiFunction<T, U>. Function that accepts two arguments and produces a double-valued result. BinaryOperator<T> IntBinaryOperator. Function operation upon two int-valued operands and producing an int-valued result. LongBinaryOperator. Function operation upon two long-valued operands and producing a long-valued result. DoubleBinaryOperator. Function operation upon two double-valued operands and producing a double-valued result.
Develop code that uses the UnaryOperator interface
UnaryOperator is a functional interface that receives a
value of a certain type and returns a value of the same type. This is a
specialization of the Function interface for the case where the operand and result are of the same type (in fact UnaryOperator extends from Function).
Here's the javadoc.
And here's an example:
publicclassTest{
publicstaticvoidmain(String[] args){
UnaryOperator<Integer> unary = v -> v * 10;
// This means the same as the UnaryOperator above.
Function<Integer, Integer> function = v -> v * 10;
System.out.println(unary.apply(10));
System.out.println(function.apply(10));
}
}
The output:
100
100
The UnaryOperator can also be applied to a collection like this:
publicclassProgram{
publicstaticvoidmain(String[] args){
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.replaceAll(i -> i * 10);
// ... Display the results.
System.out.println(list);
}
}
The output:
[10, 20, 30]
Note:
BiConsumer, BiFunction and BiPredicate Interface.
BiConsumer, BiFunction and BiPredicate Interface All these Interfaces are similar to above mentioned interface the only difference is these interface accept two input parameters and returns a
result.
Q5. Given the structure of class Student and Subject. You have a list of students with their corresponding subject and marks return top marks of each subject from studentList.class Student{ private String name; private UUId id; List<Subject> subjectList; } class Subject{ private String subjectName; private Double Marks; }
Solution:
1. First below code will flatten subject object in one list.
Q6. What is functional interface and how to create functional interface ? Solution:
An interface with exactly one abstract method is called Functional Interface. @FunctionalInterface annotation is added so that we can mark an interface as functional interface.
It is not mandatory to use it, but it’s best practice to use it with functional interfaces to avoid addition of extra methods accidentally. If the interface is annotated with @FunctionalInterface annotation and we try to have more than one abstract method, it throws compiler error.
The major benefit of java 8 functional interfaces is that we can use lambda expressions to instantiate them and avoid using bulky anonymous class implementation.
Here is a Java functional interface example:
public interface MyFunctionalInterface {
public void execute();
}
The above counts as a functional interface in Java because it only contains a single method, and that method has no implementation. Normally a Java interface does not contain implementations of the methods it declares, but it can contain implementations in default methods, or in static methods. Below is another example of a Java functional interface, with implementations of some of the methods:
public interface MyFunctionalInterface2{
public void execute();
public default void print(String text) {
System.out.println(text);
}
public static void print(String text, PrintWriter writer) throws IOException {
writer.write(text);
}
}
The above interface still counts as a functional interface in Java, since it only contains a single non-implemented method.
Functional Interfaces Can Be Implemented by a Lambda Expression
A Java functional interface can be implemented by a Java Lambda Expression. Here is an example that implements the functional interface MyFunctionalInterface defined in the beginning of this Java functional interface tutorial:
A Java lambda expression implements a single method from a Java interface. In order to know what method the lambda expression implements, the interface can only contain a single unimplemented method. In other words, the interface must be a Java functional interface.
CompletableFuture is used for asynchronous programming in Java. Asynchronous programming is a means of writing non-blocking
code by running a task on a separate thread than the main application
thread and notifying the main thread about its progress, completion or
failure.
This way, your main thread does not block/wait for the completion of the task and it can execute other tasks in parallel.
Having this kind of parallelism greatly improves the performance of your programs.
Future vs CompletableFuture
CompletableFuture is an extension to Java’s Future API which was introduced in Java 5.
A Future is used as a reference to the result of an asynchronous computation. It provides an isDone() method to check whether the computation is done or not, and a get() method to retrieve the result of the computation when it is done.
You can learn more about Future from Callable and Future Tutorial.
Future API was a good step towards asynchronous programming in Java but it lacked some important and useful features -
Limitations of Future
It cannot be manually completed :
Let’s say that you’ve written a function to fetch the latest price of
an e-commerce product from a remote API. Since this API call is
time-consuming, you’re running it in a separate thread and returning a
Future from your function.
Now, let’s say that If the remote API service is down, then you want
to complete the Future manually by the last cached price of the product.
Can you do this with Future? No!
You cannot perform further action on a Future’s result without blocking:
Future does not notify you of its completion. It provides a get() method which blocks until the result is available.
You don’t have the ability to attach a callback function to the
Future and have it get called automatically when the Future’s result is
available.
Multiple Futures cannot be chained together :
Sometimes you need to execute a long-running computation and when the
computation is done, you need to send its result to another
long-running computation, and so on.
You can not create such asynchronous workflow with Futures.
You can not combine multiple Futures together :
Let’s say that you have 10 different Futures that you want to run in
parallel and then run some function after all of them completes. You
can’t do this as well with Future.
No Exception Handling :
Future API does not have any exception handling construct.
Whoa! So many limitations right? Well, That’s why we have
CompletableFuture. You can achieve all of the above with
CompletableFuture.
CompletableFuture implements Future and CompletionStage
interfaces and provides a huge set of convenience methods for creating,
chaining and combining multiple Futures. It also has a very
comprehensive exception handling support.
Q3. What are the implementations class of ExecutorService?
Q4. What is the difference between dequeBlocking and queueBlocking?
Q5. Difference between completable future and future?
Q6. What is the difference between sleep(), wait() and yield()?