1. What are Stream API?
Stream API is introduced in Java 8 that is used to process collections of objects. Basically A stream is a sequence of objects. It does not stores any values.
Stream API is introduced newly in Java 8 to process the Collection object.
Stream is not a data structure or it does not store any data, It just provides a convenient way to operate with data source and make its processing faster.
There are two methods to generate a Stream.
1). stream() − Returns a sequential stream considering collection as its source.
2). parallelStream() − Returns a parallel Stream considering collection as its source.
There are two types of operation performed on Stream
1). Intermediate operation : it contains methods like map(), filter() and Sorted().
2). Terminal Operation : It contains methods like contains(), forEach() and reduce().
Example of Stream API
import java.util.*;
import java.util.stream.Collectors;
class Student{
int id;
String name;
int roll;
public Student(int id, String name, int roll) {
this.id = id;
this.name = name;
this.roll = roll;
}
}
public class Main {
public static void main(String[] args) {
List<Student> studentsList = new ArrayList<Student>();
studentsList.add(new Student(1,"Mayank",2));
studentsList.add(new Student(2,"Nishant",1));
studentsList.add(new Student(3,"Subhesh",3));
List<Integer> studentsListOutput =studentsList.stream()
.filter(s -> s.roll >= 2)
.map(s->s.roll)
.collect(Collectors.toList());
System.out.println(studentsListOutput);
}
}
Output
[2, 3]
2. Use stream to print employee whose salary>10000.
import java.util.*;
import java.util.stream.Collectors;
class Employee {
private String name;
private int salary;
public void setName(String name) {
this.name = name;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getSalary() {
return this.salary;
}
public String getName() {
return this.name;
}
Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
}
class Main {
public static void main(String arr[])
{
List<Employee> emp = new ArrayList<>();
emp.add(new Employee("Ram", 20000));
emp.add(new Employee("Shayam", 30000));
emp.add(new Employee("Mohan", 10000));
emp.add(new Employee("Soham", 50000));
List<Employee> list = emp.stream().filter(s -> s.getSalary() > 10000).collect(Collectors.toList());
list.stream().forEach(s -> System.out.println(s.getName()));
}
}
Output
Ram
Shayam
Soham
3). Explain Fail Fast Iterator and Fail safe Iterator in Java.
Fail-Fast Iterator
- Iterator fails as soon as it realizes that the structure of the underlying data structure has been modified since the iteration has begun.
- Structural changes mean adding, removing any element from the collection, merely updating some value in the data structure does not count for the structural modifications.
- Fail-Fast Iterator is implemented by keeping a modification count and if iterating thread realizes the changes in modification count then it throws ConcurrentModificationException. Most collections in package util.* are fail-fast by Design.
Fail-Safe Iterator
- Fail-safe Iterator is “Weakly Consistent” and does not throw any exception if collection is modified structurally during the iteration.
- Such Iterator -may work on clone of collection instead of original collection such as in CopyOnWriteArrayList
- Most collections under util.concurrent offer fail-safe Iterators to its users and that’s by Design.
- Fail safe collections should be preferred while writing multi-threaded applications to avoid concurrency related issues.
- Fail Safe Iterator is guaranteed to list elements as they existed upon construction of Iterator, and may reflect any modifications subsequent to construction (without guarantee).
Fail Fast Example
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String element = itr.next();
if (element.equals("B")) {
list.add("BB");
}
}
System.out.println(list);
}
}
Output
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
at Main.main(Main.java:14)
Fail Safe Example
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
class Main {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String element = itr.next();
if (element.equals("A")) {
list.add("F");
}
}
System.out.println(list);
}
}
Output
[A, B, C, D, E, F]
4. Difference between List and Sets in Java.
- List implementation classes are LinkedList, ArrayList, Vector, Stack but Set implementation classes are TreeSet, HashSet and LinkedHashSet.
- List implementation allows duplicate elements but set implementation doesn’t allow duplicate elements.
- We can add any number of null value in list but Set allows only one null value.
- List maintain the insertion order but set doesn’t maintain the insertion order.
- List allow to access element by their position but set doesn’t have anything to access element from position.
5. Difference between wait() and sleep()
wait()
is non static method ofObject
andsleep()
is a static method ofThread
.- w
ait()
releases the lock whilesleep()
doesn’t release the lock. wait()
is used for inter-thread communication whereassleep()
pause the execution for given time.wait()
should call inside synchronise otherwise we will get anIllegalMonitorStateException
, whilesleep()
can be called anywhere.- While using
wait()
, we need to callnotify()
ornotifyAll()
indefinitely to start the thread again butsleep()
thread gets started after given time interval.
6. What is Inter-thread communication?
Inter-thread communication is a mechanism in which a thread releases the lock and enter into paused state and another thread acquires the lock and continue to executed.
It is implemented by following methods of Object class:
1. wait() :- wait() method release the lock from current thread for other thread and wait until another thread invokes the notify() or notifyAll() method for this object.
2. notify() : This method is used to wake up a single thread and releases the object lock.
3. notifyAll () : This method is used to wake up all threads that are in waiting state.
7. How many modifiers in Java?
There are total 12 modifiers in java that is divided into two categories:
- Access modifiers
- Non-access modifiers
Four Access Modifiers in Java are
- Private: private access modifier can access only in same class and not from outside the class.
- Default: default access modifier can be accessed within the same class and package but not from outside the package. If we don’t add any access modifier then it is consider as default access modifier.
- Protected: protected access modifier can be access in same package and also outside the package with the help of the child class.
- Public: public access modifier can be access from anywhere like within the class, outside the class, also within the package and outside the package.
8 non access modifiers are
For classes,
- final
- abstract
For attributes and methods
- final
- static
- abstract
- transient
- synchronized
- volatile
6). What is volatile, synchronized and transient?
Synchronized
The synchronized keyword used to indicate that a method can be accessed by only one thread at a time. It is a type of lock we can say to protect the method or resource from other thread. Suppose we have a single resource that can be used by multiple threads. So to protect from undesired result, we will enter one thread in synchronize area to access the resource by thread.
The Synchronized modifier can be applied with any of the four access level modifiers that is public, protected, private and default.
When a thread invokes a synchronized method, it automatically acquires the lock for that object and releases it when the thread completes its task.
Transient Modifier
Transient keyword is used with instance variable to exclude them from serialization process. When we use transient keyword with an variable, it ignores original value of the variable and save default value of that variable data type.
Default value for reference is null and zero for primitive type. Transient keyword cannot be used with static keyword.
Volatile Identifier
Volatile int a=10;
Volatile is used with variables only in multithreaded environment when multiple threads wanted to access single variable.
When we use volatile keywords, internally temp variable will be created for each thread with same value. And original value will be not affected until thread execution completed.
Suppose we have three threads then it will be look like
Volatile int a = 40;
t1 t2 t3
10 40 40
20 50
30 60
40
The volatile keyword does not cache the value of the variable and always read the variable from the main memory. The volatile keyword cannot be used with classes or methods. However, it is used with variables.
7. Difference between synchronization and volatile keyword.
Volatile keyword is not a substitute of synchronized keyword, but it can be used as an alternative in certain cases. There are the following differences are as follows:
- Synchronized keyword modifies blocks and methods whereas Volatile keyword is a field modifier.
- Synchronized block the Threads to access the resource means one thread can access block at a single time but Volatile cannot block the thread because it generate temp copy of resource.
- Synchronized degrade the thread performance but Volatile thread improves the performance.
- Synchronize optimize the compiler but Volatile field not optimize the compiler.
8. Difference between HashMap and ConcurrentHashMap?
- HashMap is not synchronized whereas ConcurrentHashMap is synchronized.
- HashMap is not thread-safe but ConcurrentHashMap is thread safe.
- HashMap is fail-fast and throws an exception during iteration by multiple threads but ConcurrentHashMap is fail-safe and performs iteration by multiple threads.
- Hashmap is faster whereas ConcurrentHashMap is slower.
- HashMap allows Null keys and Null values but ConcurrentHashMap never allows null value or Null key.
9. What is reduce() in Streams?
In Java Program sometime we have to perform operations to get single resultant value.
Single resultant value are like maximum, minimum, sum, product, etc. Reducing is the repeated process of combining all elements.
Java 8 Program to find the sum
import java.util.*;
class Main {
public static void main(String[] args)
{
List<Integer> array = Arrays.asList(1, 2, 3, 4, 5);
int sum = array.stream().reduce(0,(value1, value2) -> value1 + value2);
System.out.println("Sum = " + sum);
}
}
Output
Sum = 15
Java 8 Program to calculate the multiplication
import java.util.*;
import java.util.stream.IntStream;
class Main {
public static void main(String[] args)
{
int product = IntStream.range(2,5).reduce((num1, num2) -> num1 * num2).orElse(-1);
System.out.println("Product = " + product);
}
}
Output
Product = 24
10. Working of HashSet and HashMap
11. Where is ArrayList and LinkedList preferred?
As We know Accessing an element in ArrayList takes constant time [O(1)] and adding an element takes O(n) in the worst case. And in LinkedList inserting an element takes O(n) time and accessing also takes O(n) time but LinkedList needs some more memory than ArrayList.
Accessing elements in ArrayList is faster because it is index based. But Accessing elements in LinkedList is slower because we need to traverse each node. Insertion and deletion in Linked List are much faster because here we need to change the pointer of the node only. We need not shift the element as we do in ArrayList.
So here we are at the conclusion, if we need to perform more manipulation work on the element and memory is not a problem then we can prefer Linked List over ArrayList.
But When we require more searching of the element then we can choose ArrayList over LinkedList.
Time complexity with operations
For ArrayList<E>
- get(int index) takes O(1).
- add(E element) operation takes O(1) amortized, but in the worst case it will be O(n) since the array must be resized and copied.
- add(int index, E element) takes O(n) Complexity (with n/2 steps on average).
- remove(int index) operation takes O(n) (with n/2 steps on average).
- Iterator.remove() have O(n) Complexity (with n/2 steps on average).
- ListIterator.add(E element) operation takes O(n) (with n/2 steps on average)
For LinkedList<E>
- get(int index) operation takes O(n) , It will take O(1) when index = 0 or index = list.size() -1 .
- add(int index, E element) take O(n) and It will take O(1) when index = 0 or index = list.size() – 1
- remove(int index) takes O(n) and It will take O(1) when index = 0 or index = list.size() – 1.