1. What are Java Streams and how do you use them?
Java Streams are a part of the Java Collections Framework
introduced in Java 8. They allow for functional-style operations on sequences
of elements such as map, filter, and reduce. Streams can be created from
collections, arrays, or I/O resources and are used to process data in a
declarative way.
Example:
```java
List<String> names = Arrays.asList("Alice",
"Bob", "Charlie");
List<String> filteredNames = names.stream()
.filter(name
-> name.startsWith("A"))
.collect(Collectors.toList());
System.out.println(filteredNames); // Output: [Alice]
```
Tip: Use streams for efficient and
readable data processing, especially with large datasets.
2. Explain the concept of CompletableFuture in
Java.
`CompletableFuture` is a class introduced in Java 8 for
asynchronous programming. It represents a future result of an asynchronous
computation. `CompletableFuture` can be used to build complex asynchronous
pipelines, handle exceptions, and combine multiple async operations.
Example:
```java
CompletableFuture<Integer> future =
CompletableFuture.supplyAsync(() -> {
return 50 + 20;
});
future.thenAccept(result ->
System.out.println("Result: " + result));
```
Tip: Use `CompletableFuture` for non-blocking, asynchronous tasks to improve performance in concurrent applications.
3. What are the differences between HashMap and ConcurrentHashMap?
- HashMap: It is not thread-safe and cannot be
shared between threads without proper synchronization. Operations on a
`HashMap` are faster in single-threaded environments.
- ConcurrentHashMap: It is thread-safe and allows
concurrent read and write operations. It achieves thread safety through a
technique called lock stripping, which divides the map into segments.
Example:
```java
Map<String, Integer> map = new
ConcurrentHashMap<>();
map.put("one", 1);
map.put("two", 2);
System.out.println(map.get("one"));
```
Tip: Use `ConcurrentHashMap` for
thread-safe operations when multiple threads are accessing the map
concurrently.
4. How does the Java Memory Model handle
concurrency?
The Java Memory Model (JMM) defines how threads interact
through memory and what behaviors are allowed in concurrent execution. It
specifies rules for:
- Visibility: Ensuring changes made by one thread to
shared variables are visible to other threads.
- Atomicity: Ensuring that certain operations are
performed as a single unit of execution.
- Ordering: Preventing unexpected reordering of code
instructions.
Example of `volatile` for visibility:
```java
public class VolatileExample {
private volatile
boolean flag = true;
public void
stop() {
flag = false;
}
public void run()
{
while (flag)
{
// Do
something
}
}
}
```
Tip:. Use `volatile` for variables
that are accessed by multiple threads but not modified in a synchronized block.
5. What are the different types of class
loaders in Java?
Java has several
class loaders, each responsible for loading classes into the JVM:
- Bootstrap ClassLoader: Loads core Java classes
(e.g., `java.lang.*`).
- Extension ClassLoader: Loads classes from the Java
extensions directory (`jre/lib/ext`).
- System/Application ClassLoader: Loads classes from
the classpath (`-cp` or `CLASSPATH` environment variable).
- Custom ClassLoader: User-defined class loaders to
load classes in a customized way.
Example of a custom class loader:
```java
public class MyClassLoader extends ClassLoader {
@Override
public
Class<?> findClass(String name) throws ClassNotFoundException {
byte[] b =
loadClassFromFile(name);
return
defineClass(name, b, 0, b.length);
}
private byte[]
loadClassFromFile(String fileName) {
// Load the
class file into a byte array
}
}
```
Tip: Use custom class loaders for
dynamic class loading and to implement specific security policies.
6. What
is the difference between Callable and Runnable?
Runnable: Represents a task that
can be executed by a thread. It does not return a result and cannot throw
checked exceptions.
- Callable: Similar to `Runnable` but can return a
result and throw checked exceptions.
Example:
```java
// Runnable example
Runnable task = () -> System.out.println("Task
executed");
new Thread(task).start();
// Callable example
Callable<Integer> task = () -> {
return 123;
};
Future<Integer> future =
Executors.newSingleThreadExecutor().submit(task);
System.out.println(future.get());
```
Tip: Use `Callable` when you need
a task to return a result or throw an exception.
7.
Explain the Fork/Join Framework in Java.
The Fork/Join framework is designed for parallel processing
and is part of the `java.util.concurrent` package. It helps in breaking a large
task into smaller subtasks and then combining the results. It uses a
work-stealing algorithm to optimize the performance.
Example:
```java
public class FibonacciTask extends
RecursiveTask<Integer> {
private final int
n;
public
FibonacciTask(int n) {
this.n = n;
}
@Override
protected Integer
compute() {
if (n <=
1) return n;
FibonacciTask
f1 = new FibonacciTask(n - 1);
FibonacciTask
f2 = new FibonacciTask(n - 2);
f1.fork();
return
f2.compute() + f1.join();
}
public static
void main(String[] args) {
ForkJoinPool
pool = new ForkJoinPool();
FibonacciTask
task = new FibonacciTask(10);
System.out.println(pool.invoke(task));
}
}
```
Tip: Use the Fork/Join framework
for tasks that can be recursively divided into smaller subtasks.
8. What
is Java's try-with-resources statement?
The try-with-resources statement ensures that each resource
is closed at the end of the statement. It is used for managing resources such
as files, sockets, and database connections that need to be closed after being
used.
Example:
```java
try (BufferedReader br = new BufferedReader(new
FileReader("test.txt"))) {
String line;
while ((line =
br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
```
Tip: Use try-with-resources to
automatically close resources and reduce boilerplate code.
9.
Explain the difference between `synchronized` and `ReentrantLock`.
synchronized: A keyword that
provides a simple way to lock a method or a block of code. It is intrinsic and
cannot be interrupted.
ReentrantLock: A
class from `java.util.concurrent.locks` that provides more flexible locking
mechanisms. It supports lock polling, timed lock waits, and interruptible lock
waits.
Example:
```java
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
// critical
section
} finally {
lock.unlock();
}
```
Tip: Use `ReentrantLock` for
advanced locking features like fairness, tryLock, and interruptibility.
10. What
are Phantom References in Java?
Phantom references
are one of the types of references in Java, represented by the
`PhantomReference` class. They are used to determine when an object is no
longer reachable and is about to be collected by the garbage collector. Unlike
soft or weak references, they do not prevent their referents from being
collected.
Example:
```java
ReferenceQueue<Object> refQueue = new
ReferenceQueue<>();
PhantomReference<Object> phantomRef = new
PhantomReference<>(new Object(), refQueue);
// Check if the object is about to be collected
System.gc();
Reference<?> ref = refQueue.poll();
if (ref != null) {
System.out.println("Object is about to be collected");
}
```
Tip: Use phantom references for
scheduling pre-mortem cleanup actions before the object is collected by the GC.