Core Java

Java Fundamentals 1

Java Fundamentals 2

Java Fundamentals 3

Java Swing

Java Applet

Java Memory & Performance

Core Java Fundamentals Interview Questions

Why do you get a ConcurrentModificationException when using an iterator?

Problem: The java.util.Collection classes are fail-fast, which means that if one thread changes a collection while another thread is traversing it through with an iterator the iterator.hasNext() or call will throw ConcurrentModificationException. Even the synchronized collection wrapper classes SynchronizedMap and SynchronizedList are only conditionally thread-safe, which means all individual operations are thread-safe but compound operations where flow of control depends on the results of previous operations may be subject to threading issues. Collection myCollection = new ArrayList(10);
for (Iterator it = myCollection.iterator(); it.hasNext();) {
String myObject = (String);
if (someConditionIsTrue) {
myCollection.remove(myObject); //can throw ConcurrentModificationException in single as
//well as multi-thread access situations.
  • You can convert your list to an array with list.toArray() and iterate on the array. This approach is not recommended if the list is large.
  • You can lock the entire list while iterating by wrapping your code within a synchronized block. This approach adversely affects scalability of your application if it is highly concurrent.
  • If you are using JDK 1.5 then you can use the ConcurrentHashMap and CopyOnWriteArrayList classes, which provide much better scalability and the iterator returned by ConcurrentHashMap.iterator() will not throw ConcurrentModificationException while preserving thread-safety.

What are the benefits of the Java Collections Framework? Collections framework provides flexibility, performance, and robustness.

  • Polymorphic algorithms sorting, shuffling, reversing, binary search etc.
  • Set algebra - such as finding subsets, intersections, and unions between objects.
  • Performance - collections have much better performance compared to the older Vector and Hashtable classes with the elimination of synchronization overheads.
  • Thread-safety - when synchronization is required, wrapper implementations are provided for temporarily synchronizing existing collection objects. For J2SE 5.0 use java.util.concurrent package.
  • Immutability - when immutability is required wrapper implementations are provided for making a collection immutable.
  • Extensibility - interfaces and abstract classes provide an excellent starting point for adding functionality and features to create specialized object collections.

What are static factory methods?

Some of the above mentioned features like searching, sorting, shuffling, immutability etc are achieved with java.util.Collections class and java.util.Arrays utility classes. The great majority of these implementations are provided via static factory methods in a single, non-instantiable (i.e. private constrctor) class. Speaking of static factory methods, they are an alternative to creating objects through constructors. Unlike constructors, static factory methods are not required to create a new object (i.e. a duplicate object) each time they are invoked (e.g. immutable instances can be cached) and also they have a more meaningful names like valueOf, instanceOf, asList etc.
For example:
Instead of:
String[] myArray = {"Java", "J2EE", "XML", "JNDI"};
for (int i = 0; i < myArray.length; i++) {

You can use:
String[] myArray = {"Java", "J2EE", "XML", "JNDI"};
System.out.println(Arrays.asList(myArray)); //factory method Arrays.asList(Ö)

For example: The following static factory method (an alternative to a constructor) example converts a boolean primitive
value to a Boolean wrapper object. public static Boolean valueOf(boolean b) {
return (b ? Boolean.TRUE : Boolean.FALSE)

What are some of the best practices relating to Java collection?

  • Use ArrayList, HashMap etc as opposed to Vector, Hashtable etc, where possible to avoid any synchronization overhead. Even better is to use just arrays where possible. If multiple threads concurrently access a collection and at least one of the threads either adds or deletes an entry into the collection, then the collection must be externally synchronized.
    This is achieved by:
    Map myMap = Collections.synchronizedMap (myMap); //conditional thread-safety
    List myList = Collections.synchronizedList (myList); //conditional thread-safety
  • Set the initial capacity of a collection appropriately (e.g. ArrayList, HashMap etc). This is because Collection classes like ArrayList, HashMap etc must grow periodically to accommodate new elements. But if you have a very large array, and you know the size in advance then you can speed things up by setting the initial size appropriately.
    For example: HashMaps/Hashtables need to be created with sufficiently large capacity to minimize rehashing (which happens every time the table grows). HashMap has two parameters initial capacity and load factor that affect its performance and space requirements. Higher load factor values (default load factor of 0.75 provides a good trade off between performance and space) will reduce the space cost but will increase the lookup cost of myMap.get("") and myMap.put("") methods. When the number of entries in the HashMap exceeds the current capacity * loadfactor then the capacity of the HasMap is roughly doubled by calling the rehash function. It is also very important not to set the initial capacity too high or load factor too low if iteration performance or reduction in space is important.
  • Program in terms of interface not implementation: For example you might decide a LinkedList is the best choice for some application, but then later decide ArrayList might be a better choice for performance reason.
    List list = new ArrayList(100); // program in terms of interface & set the initial capacity.
    Instead of:
    ArrayList list = new ArrayList();
  • Return zero length collections or arrays as opposed to returning null: CO Returning null instead of zero length collection (use Collections.EMPTY_SET, Collections.EMPTY_LIST, Collections.EMPTY_MAP) is more error prone, since the programmer writing the calling method might forget to handle a return value of null.
  • Immutable objects should be used as keys for the HashMap: CO Generally you use a java.lang.Integer or a java.lang.String class as the key, which are immutable Java objects. If you define your own key class then it is a best practice to make the key class an immutable object (i.e. do not provide any setXXX() methods etc). If a programmer wants to insert a new key then he/she will always have to instantiate a new object (i.e. cannot mutate the existing key because immutable key object class has no setter methods).
  • Encapsulate collections: CO In general collections are not immutable objects. So care should be taken not to unintentionally expose the collection fields to the caller.
  • Avoid storing unrelated or different types of objects into same collection: This is analogous to storing items in pigeonholes without any labeling. To store items use value objects or data objects (as opposed to storing every attribute in an ArrayList or HashMap). Provide wrapper classes around your collections API classes like ArrayList, HashMap etc as shown in better approach column. Also where applicable consider using composite design pattern, where an object may represent a single object or a collection of objects.

What is an intern() method in the String class?

A pool of Strings is maintained by the String class. When the intern() method is invoked equals() method is invoked to determine if the String already exist in the pool. If it does then the String from the pool is returned. Otherwise, this String object is added to the pool and a reference to this object is returned. For any two Strings s1 & s2, s1.intern() == s2.intern() only if s1.equals(s2) is true.

What are the non-final methods in Java Object class, which are meant primarily for extension?

The non-final methods are equals(), hashCode(), toString(), clone(), and finalize(). The other methods like wait(), notify(), notifyAll(), getClass() etc are final methods and therefore cannot be overridden. Let us look at these non-final methods, which are meant primarily for extension (i.e. inheritance).
Important: The equals() and hashCode() methods prove to be very important, when objects implementing these two methods are added to collections. If implemented incorrectly or not implemented at all then your objects stored in a collection like a Set, List or Map may behave strangely and also is hard to debug.

What are the primary considerations when implementing a user defined key?

  • If a class overrides equals(), it must override hashCode().
  • If 2 objects are equal, then their hashCode values must be equal as well.
  • If a field is not used in equals(), then it must not be used in hashCode().
  • If it is accessed often, hashCode() is a candidate for caching to enhance performance.
  • It is a best practice to implement the user defined key class as an immutable object.

What is an immutable object?

Immutable objects whose state (i.e. the objectís data) does not change once it is instantiated (i.e. it becomes a read-only object after instantiation). Immutable classes are ideal for representing numbers (e.g. java.lang.Integer, java.lang.Float, java.lang.BigDecimal etc are immutable objects), enumerated types, colors (e.g. java.awt.Color is an immutable object), short lived objects like events, messages etc.

What are the benefits of immutable objects?

  • Immutable classes can greatly simplify programming by freely allowing you to cache and share the references to the immutable objects without having to defensively copy them or without having to worry about their values becoming stale or corrupted.
  • Immutable classes are inherently thread-safe and you do not have to synchronize access to them to be used in a multi-threaded environment. So there is no chance of negative performance consequences.
  • Eliminates the possibility of data becoming inaccessible when used as keys in HashMaps or as elements in Sets. These types of errors are hard to debug and fix.

How will you write an immutable class?

Writing an immutable class is generally easy but there can be some tricky situations.
Follow the following guidelines:
  • A class is declared final (i.e. final classes cannot be extended).
    public final class MyImmutable {""}
  • All its fields are final (final fields cannot be mutated once assigned).
    private final int[] myArray; //do not declare as private final int[] myArray = null;
  • Do not provide any methods that can change the state of the immutable object in any way not just setXXX methods, but any methods which can change the state.
  • The this reference is not allowed to escape during construction from the immutable class and the immutable class should have exclusive access to fields that contain references to mutable objects like arrays, collections and mutable classes like Date etc by:
    Declaring the mutable references as private.
    Not returning or exposing the mutable references to the caller

What is the main difference between pass-by-reference and pass-by-value?

Other languages use pass-by-reference or pass-by-pointer. But in Java no matter what type of argument you pass the corresponding parameter (primitive variable or object reference) will get a copy of that data, which is exactly how pass-by-value (i.e. copy-by-value) works.
In Java, if a calling method passes a reference of an object as an argument to the called method then the passedin reference gets copied first and then passed to the called method. Both the original reference that was passed-in and the copied reference will be pointing to the same object. So no matter which reference you use, you will be always modifying the same original object, which is how the pass-by-reference works as well.

What is serialization? How would you exclude a field of a class from serialization or what is a transient variable? What is the common use? What is a serial version id?

Serialization is a process of reading or writing an object. It is a process of saving an objectís state to a sequence of bytes, as well as a process of rebuilding those bytes back into a live object at some future time. An object is marked serializable by implementing the interface, which is only a marker interface -- it simply allows the serialization mechanism to verify that the class can be persisted, typically to a file.
Transient variables cannot be serialized. The fields marked transient in a serializable object will not be transmitted in the byte stream. An example would be a file handle, a database connection, a system thread etc.Such objects are only meaningful locally. So they should be marked as transient in a serializable class.
Serialization can adversely affect performance since it:
  • Depends on reflection.
  • Has an incredibly verbose data format.
  • Is very easy to send surplus data.

    When to use serialization?

    Do not use serialization if you do not have to. A common use of serialization is to use it to send an object over the network or if the state of an object needs to be persisted to a flat file or a database. Deep cloning or copy can be achieved through serialization. This may be fast to code but will have performance implications.
    To serialize the above "Car" object to a file (sample for illustration purpose only, should use try {} catch {} block):
    Car car = new Car(); // The "Car" class implements a interface
    FileOutputStream fos = new FileOutputStream(filename);
    ObjectOutputStream out = new ObjectOutputStream(fos);
    out.writeObject(car); // serialization mechanism happens here

    The objects stored in an HTTP session should be serializable to support in-memory replication of sessions to achieve scalability. Objects are passed in RMI (Remote Method Invocation) across network using serialization.

    What is Java Serial Version ID?

    Say you create a 'Car' class, instantiate it, and write it out to an object stream. The flattened car object sits in the file system for some time. Meanwhile, if the 'Car' class is modified by adding a new field. Later on, when you try to read (i.e. deserialize) the flattened 'Car' object, you get the because all serializable classes are automatically given a unique identifier. This exception is thrown when the identifier of the class is not equal to the identifier of the flattened object. If you really think about it, the exception is thrown because of the addition of the new field. You can avoid this exception being thrown by controlling the versioning yourself by declaring an explicit serialVersionUID. There is also a small performance benefit in explicitly declaring your serialVersionUID (because does not have to be calculated). So, it is best practice to add your own serialVersionUID to your Serializable classes as soon as you create them as shown below:
    public class Car {
      static final long serialVersionUID = 1L; //assign a long value

    How does the new I/O (NIO) offer better scalability and better performance?

    Java has long been not suited for developing programs that perform a lot of I/O operations. Furthermore,commonly needed tasks such as file locking, non-blocking and asynchronous I/O operations and ability to map file to memory were not available. Non-blocking I/O operations were achieved through work around such as multithreading or using JNI. The New I/O API (aka NIO) in J2SE 1.4 has changed this situation.
    A serverís ability to handle several client requests effectively depends on how it uses I/O streams. When a server has to handle hundreds of clients simultaneously, it must be able to use I/O services concurrently. One way to cater for this scenario in Java is to use threads but having almost one-to-one ratio of threads (100 clients will have 100 threads) is prone to enormous thread overhead and can result in performance and scalability problems due to consumption of memory stacks (i.e. each thread has its own stack.) and CPU context switching (i.e. switching between threads as opposed to doing real computation.). To overcome this problem, a new set of non-blocking I/O classes have been introduced to the Java platform in java.nio package. The non-blocking I/O mechanism is built around Selectors and Channels. Channels, Buffers and Selectors are the core of the NIO.
    A Channel class represents a bi-directional communication channel (similar to InputStream and OutputStream) between datasources such as a socket, a file, or an application component, which is capable of performing one or more I/O operations such as reading or writing. Channels can be non-blocking, which means, no I/O operation will wait for data to be read or written to the network. The good thing about NIO channels is that they can be asynchronously interrupted and closed. So if a thread is blocked in an I/O operation on a channel, another thread can interrupt that blocked thread.
    A Selector class enables multiplexing (combining multiple streams into a single stream) and demultiplexing (separating a single stream into multiple streams) I/O events and makes it possible for a single thread to efficiently manage many I/O channels. A Selector monitors selectable channels, which are registered with it for I/O events like connect, accept, read and write. The keys (i.e. Key1, Key2 etc represented by the SelectionKey class) encapsulate the relationship between a specific selectable channel and a specific selector.
    Buffers hold data. Channels can fill and drain Buffers. Buffers replace the need for you to do your own buffer management using byte arrays. There are different types of Buffers like ByteBuffer, CharBuffer, DoubleBuffer, etc.
    Design pattern: NIO uses a reactor design pattern, which demultiplexes events (separating single stream into multiple streams) and dispatches them to registered object handlers. The reactor pattern is similar to an observer pattern (aka publisher and subscriber design pattern), but an observer pattern handles only a single source of events (i.e. a single publisher with multiple subscribers) where a reactor pattern handles multiple event sources (i.e. multiple publishers with multiple subscribers). The intent of an observer pattern is to define a one-to-many dependency so that when one object (i.e. the publisher) changes its state, all its dependents (i.e. all its subscribers) are notified and updated correspondingly.
    Another sought after functionality of NIO is its ability to map a file to memory. There is a specialized form of a Buffer known as MappedByteBuffer, which represents a buffer of bytes mapped to a file. To map a file to MappedByteBuffer, you must first get a channel for a file. Once you get a channel then you map it to a buffer and subsequently you can access it like any other ByteBuffer. Once you map an input file to a CharBuffer, you can do pattern matching on the file contents. This is similar to running grep on a UNIX file system.
    Another feature of NIO is its ability to lock and unlock files. Locks can be exclusive or shared and can be held on a contiguous portion of a file. But file locks are subject to the control of the underlying operating system.

    How can you improve Java I/O performance?

    Java applications that utilize Input/Output are excellent candidates for performance tuning. Profiling of Java applications that handle significant volumes of data will show significant time spent in I/O operations. This means substantial gains can be had from I/O performance tuning. Therefore, I/O efficiency should be a high priority for developers looking to optimally increase performance.
    The basic rules for speeding up I/O performance are
    • Minimize accessing the hard disk.
    • Minimize accessing the underlying operating system.
    • Minimize processing bytes and characters individually.
    • Use the NIO package, if you are using JDK 1.4 or later, which uses performance-enhancing features like buffers to hold data, memory mapping of files, non-blocking I/O operations etc.
    • I/O performance can be improved by minimizing the calls to the underlying operating systems. The Java runtime itself cannot know the length of a file, querying the file system for isDirectory(), isFile(), exists() etc must query the underlying operating system.
    • Where applicable caching can be used to improve performance by reading in all the lines of a file into a Java Collection class like an ArrayList or a HashMap and subsequently access the data from an in-memory collection instead of the disk.

    What is the main difference between shallow cloning and deep cloning of objects?

    The default behavior of an objectís clone() method automatically yields a shallow copy. So to achieve a deep copy the classes must be edited or adjusted.
    • Shallow copy: If a shallow copy is performed on obj-1 as shown in fig-2 then it is copied but its contained objects are not. The contained objects Obj-1 and Obj-2 are affected by changes to cloned Obj-2. Java supports shallow cloning of objects by default when a class implements the java.lang.Cloneable interface.
    • Deep copy: If a deep copy is performed on obj-1 as shown in fig-3 then not only obj-1 has been copied but the objects contained within it have been copied as well. Serialization can be used to achieve deep cloning. Deep cloning through serialization is faster to develop and easier to maintain but carries a performance overhead.

    Why would you prefer a short circuit "&&,||" operators over logical "&,|" operators?

    Firstly NullPointerException is by far the most common RuntimeException. If you use the logical operator you can get a NullPointerException. This can be avoided easily by using a short circuit "&&" operator as shown below. There are other ways to check for null but short circuit && operator can simplify your code by not having to declare separate if clauses.
    if((obj != null) & obj.equals(newObj)) { //can cause a NullPointerException if obj == null
      ... // because obj.equals(newObj) is always executed.

    Short-circuiting means that an operator only evaluates as far as it has to, not as far as it can. If the variable 'obj' equals null, it won't even try to evaluate the 'obj.equals(newObj)í clause as shown in the following example. This protects the potential NullPointerException.
    if((obj != null) && obj.equals(newObj)) { //cannot get a NullPointerException because
      ... //obj.equals(newObj) is executed only if obj != null

    Secondly, short-circuit "&&" and "||" operators can improve performance in certain situations.
    For example:
    if((number <= 7) || (doComputeIntensiveAnalysis(number) <= 13)) { //the CPU intensive
      .... //computational method in bold is executed only if number > 7

    Why would you prefer a short circuit "&&,||" operators over logical "&,|" operators?

    Firstly NullPointerException is by far the most common RuntimeException. If you use the logical operator you can get a NullPointerException. This can be avoided easily by using a short circuit "&&" operator as shown below.
    There are other ways to check for null but short circuit && operator can simplify your code by not having to declare separate if clauses.
    if((obj != null) & obj.equals(newObj)) { //can cause a NullPointerException if obj == null ... // because obj.equals(newObj) is always executed. }
    Short-circuiting means that an operator only evaluates as far as it has to, not as far as it can. If the variable 'obj' equals null, it won't even try to evaluate the 'obj.equals(newObj)í clause as shown in the following example. This protects the potential NullPointerException.
    if((obj != null) && obj.equals(newObj)) { //cannot get a NullPointerException because
      ... //obj.equals(newObj) is executed only if obj != null

    Secondly, short-circuit "&&" and "||" operators can improve performance in certain situations.
    For example:
    if((number <= 7) || (doComputeIntensiveAnalysis(number) <= 13)) { //the CPU intensive
      .... //computational method in bold is executed only if number > 7

    All Java methods are automatically re-entrant. It means that several threads can be executing the same method at once, each with its own copy of the local variables. A Java method may call itself without needing any special declarations. This is known as a recursive method call. Given enough stack space, recursive method calls are perfectly valid in Java though it is tough to debug. Recursive methods are useful in removing iterations from many sorts of algorithms. All recursive functions are re-entrant but not all re-entrant functions are recursive. Idempotent methods are methods, which are written in such a way that repeated calls to the same method with the same arguments yield same results. For example clustered EJBs, which are written with idempotent methods, can automatically recover from a server failure as long as it can reach another server (i.e. scalable).

    Explain Outer and Inner classes (or Nested classes) in Java? When will you use an Inner Class?

    In Java not all classes have to be defined separate from each other. You can put the definition of one class inside the definition of another class. The inside class is called an inner class and the enclosing class is called an outer class. So when you define an inner class, it is a member of the outer class in much the same way as other members like attributes, methods and constructors.

    Where should you use inner classes?

    Code without inner classes is more maintainable and readable. When you access private data members of the outer class, the JDK compiler creates package-access member functions in the outer class for the inner class to access the private members. This leaves a security hole. In general we should avoid using inner classes. Use inner class only when an inner class is only relevant in the context of the outer class and/or inner class can be made private so that only outer class can access it. Inner classes are used primarily to implement helper classes like Iterators, Comparators etc which are used in the context of an outer class.

    What is type casting? Explain up casting vs. down casting? When do you get ClassCastException?

    Type casting means treating a variable of one type as though it is another type.When up casting primitives as shown below from left to right, automatic conversion occurs. But if you go from right to left, down casting or explicit casting is required. Casting in Java is safer than in C or other languages that allow arbitrary casting. Java only lets casts occur when they make sense, such as a cast between a float and an int. However you can't cast between an int and a String (is an object in Java).
    byte >> short >> int >> long >> float >> double int i = 5;
    long j = i; //Right. Up casting or implicit casting
    byte b1 = i; //Wrong. Compile time error "Type Mismatch".
    byte b2 = (byte) i ; //Right. Down casting or explicit casting is required.

    When it comes to object references you can always cast from a subclass to a superclass because a subclass object is also a superclass object. You can cast an object implicitly to a super class type (i.e. upcasting). If this were not the case polymorphism wouldnít be possible.
    You can cast down the hierarchy as well but you must explicitly write the cast and the object must be a legitimate instance of the class you are casting to. The ClassCastException is thrown to indicate that code has attempted to cast an object to a subclass of which it is not an instance. If you are using J2SE 5.0 then generics will eliminate the need for casting (Refer Q55 in Java section) and otherwise you can deal with the problem of incorrect casting in two ways:

    Use the exception handling mechanism to catch ClassCastException.

      Object o = new Integer(1);
      System.out.println((String) o);
    catch(ClassCastException cce) {
      logger.log("Invalid casting, String is expected "Not an Integer");
      System.out.println(((Integer) o).toString());

    Use the instanceof statement to guard against incorrect casting.

    if(v2 instanceof Car) {
      Car c2 = (Car) v2;

    What do you know about the Java garbage collector? When does the garbage collection occur? Explain different types of references in Java?

    Each time an object is created in Java, it goes into the area of memory known as heap. The Java heap is called the garbage collectable heap. The garbage collection cannot be forced. The garbage collector runs in low memory situations. When it runs, it releases the memory allocated by an unreachable object. The garbage collector runs on a low priority daemon (i.e. background) thread. You can nicely ask the garbage collector to collect garbage by calling System.gc() but you canít force it.An objectís life has no meaning unless something has reference to it. If you canít reach it then you canít ask it to do anything. Then the object becomes unreachable and the garbage collector will figure it out. Java automatically collects all the unreachable objects periodically and releases the memory consumed by those unreachable objects to be used by the future reachable objects.

    Java Fundamentals 3 >>>

    Home Clouds