Apart from the security aspect, what are the reasons behind
making strings immutable in Java?
A String is made immutable due to the following reasons:
String Pool: Designers of Java were aware of the fact that String data
type is going to be majorly used by the programmers and developers.
Thus, they wanted optimization from the beginning. They came up with
the notion of using the String pool (a storage area in Java heap) to
store the String literals. They intended to decrease the temporary
String object with the help of sharing. An immutable class is needed to
facilitate sharing. The sharing of the mutable structures between two
unknown parties is not possible. Thus, immutable Java String helps in
executing the concept of String Pool.
Multithreading: The safety of threads regarding the String objects is
an important aspect in Java. No external synchronization is required if
the String objects are immutable. Thus, a cleaner code can be written
for sharing the String objects across different threads. The complex
process of concurrency is facilitated by this method.
Collections: In the case of Hashtables and HashMaps, keys are String
objects. If the String objects are not immutable, then it can get
modified during the period when it resides in the HashMaps.
Consequently, the retrieval of the desired data is not possible. Such
changing states pose a lot of risks. Therefore, it is quite safe to make
the string immutable.
Explain the differences between
the synchronized keyword, Lock,
and Semaphore for managing thread
synchronization.
Answer:
Synchronized is a keyword in Java that controls access to an object to
prevent data inconsistencies due to concurrent access. It provides an implicit
lock and release mechanism but no explicit methods to lock or unlock, giving
the programmer less control.
The Lock interface in the [Link] package provides more
extensive operations than the implicit locking mechanism. It allows more
flexible structuring and can be non-blocking, making it more resilient to
deadlock situations.
What are the benefits and
drawbacks of using Java’s Executor
Framework over directly creating
threads?
Answer:
The Executor Framework simplifies managing and controlling threads. It
comes with several benefits. It provides thread pooling, which helps to
reduce the overhead of thread creation and destruction. It also offers
convenient scheduling capabilities and lets you more finely control how tasks
are executed.
However, there are some drawbacks. The Executor Framework introduces an
additional layer of abstraction, which can make it more complex. Also, a
thread pool can cause resource exhaustion if not correctly configured.
How do you handle concurrent
modifications to a collection using
the ConcurrentHashMap and CopyOnWr
iteArrayList?
Answer:
Both ConcurrentHashMap and CopyOnWriteArrayList are designed for
multithreaded environments and are part of the [Link]
package.
ConcurrentHashMap allows high concurrency for updates (via segment
locking) and retrieval operations. Iterators of this class reflect the state of
the map at the time they were created, so they don’t
throw ConcurrentModificationException. It’s particularly useful when you
need a thread-safe map where reads are more common than writes.
CopyOnWriteArrayList uses a different approach. Any modification operation
(add, set, remove, etc.) on this list results in a new copy of the underlying
array, while read operations work on the existing copy. This approach
eliminates the need for locking for reads,
making CopyOnWriteArrayList excellent when iteration is a more common
operation than modification.
6. What are CompletableFutures in
Java, and how do they enable
asynchronous programming?
Answer:
CompletableFuture is a Future that may be explicitly completed by setting
its value and status. It’s part of the [Link] package and
supports asynchronous programming in Java.
CompletableFuture offers a variety of methods to handle the results of
asynchronous computations. You can chain together multiple asynchronous
operations, handle exceptions, combine results, or run additional tasks when
the computation completes.
By allowing you to write non-blocking code, CompletableFuture makes it
possible to maximize the usage of computational resources. It makes it
possible to perform other tasks instead of waiting for a long-running
operation to complete.
How can you achieve high-
performance serialization and
deserialization in Java, considering
various formats (JSON, XML,
Protocol Buffers)?
Answer:
To achieve high-performance serialization and deserialization in Java, you
can use various libraries and techniques depending on the data format.
For JSON, popular libraries include Jackson and Gson. These provide
comprehensive APIs to convert objects to JSON and vice versa. Jackson is
generally faster and has a smaller memory footprint than Gson.
For XML, JAXB is a standard Java API for object/XML mapping and provides
mechanisms for efficient serialization and deserialization.
Protocol Buffers (protobuf), a binary protocol developed by Google, allows
faster serialization/deserialization than JSON and XML. It also results in
smaller payloads. For Java, protobuf provides an API to generate Java classes
from a .proto file, which you can use for serialization and deserialization.
In all cases, custom serializers and deserializers can improve performance,
as you can optimize them according to the specific application’s needs.
Can You Catch an Exception Thrown in a Static
Block?
Question:
What happens if an exception is thrown in a static block?
Explanation:
Exceptions thrown in a static block can only be caught within
a static initializer block using a try-catch. Otherwise, the
program will fail to load the class.