Java, Programming

Java interview questions

The Toptal Engineering Blog has published a great post called
8 Essential Java Interview Questions” on there you can submit your Java interview questions, answers and hire freelancers,
and they were happy to share with us these questions. If you would like to like them on Facebook click on the link Toptal on Facebook
8 Essential Java Interview Questions
Click on the question to see the answer

The main distinction between fail-fast and fail-safe
iterators is whether or not the collection can be modified while it is being iterated.
Fail-safe iterators allow this; fail-fast iterators do not.


Of the three, LinkedList is generally going to give you the best performance. Here’s why:

ArrayList and
Vector each use an array to store the elements of the list.
As a result, when an element is inserted into (or removed from) the middle of the list, the elements that follow must all be shifted accordingly.
Vector is synchronized, so if a thread-safe implementation is
not needed, it is recommended to use ArrayList rather than Vector.


In Java, Strings are immutable
and are stored in the String pool. What this means is that, once a String is created, it stays in the pool in memory until being garbage collected.
Therefore, even after you’re done processing the string value (e.g., the password), it remains available in memory for an indeterminate period of time thereafter
(again, until being garbage collected) which you have no real control over. Therefore, anyone having access to a memory dump can potentially extract the sensitive data and exploit it.


A single ThreadLocal
instance can store different values for each thread independently. Each thread that accesses the get() or set() method of a
ThreadLocal instance is accessing its own, independently initialized copy of the variable. ThreadLocal i
nstances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or transaction ID).
The example below, from the ThreadLocal Javadoc,
generates unique identifiers local to each thread. A thread’s id is assigned the first time it invokes ThreadId.get() and remains unchanged on subsequent calls.

public class ThreadId {
			// Next thread ID to be assigned
			private static final AtomicInteger nextId = new AtomicInteger(0);
				// Thread local variable containing each thread's ID
			private static final ThreadLocal<Integer> threadId =
				new ThreadLocal<Integer>() {
					@Override protected Integer initialValue() {
						return nextId.getAndIncrement();
				}
			};

			// Returns the current thread's unique ID, assigning it if necessary
			public static int get() {
				return threadId.get();
			}
		}
		


In Java, each thread has its own stack, including its own copy of variables it can access.
When the thread is created, it copies the value of all accessible variables into its own stack. The volatile
keyword basically says to the JVM “Warning, this variable may be modified in another Thread”.

In all versions of Java, the volatile keyword guarantees global ordering on reads and writes
to a variable. This implies that every thread accessing a volatile field will read the variable’s current value instead of (potentially) using a cached value.

In Java 5 or later, volatile reads and writes establish a happens-before
relationship, much like acquiring and releasing a mutex.

Using volatile may be faster than a lock, but
it will not work in some situations. The range of situations in which volatile is
effective was expanded in Java 5; in particular, double-checked locking now works correctly.

One common example for using volatile is for a flag to terminate a thread. If you’ve started a thread, and you want to be able to safely interrupt it from a different thread, you can have the thread periodically check a flag (i.e., to stop it, set the flag to true). By making the flag volatile, you can ensure that the thread that is checking its value will see that it has been set to true without even having to use a synchronized block. For example:

public class Foo extends Thread {
		private volatile boolean close = false;
		public void run() {
			while(!close) {
				// do work
			}
		}
		public void close() {
			close = true;
			// interrupt here if needed
		}
	}
	


sleep() is a blocking operation that keeps a hold on the monitor / lock of the shared object for the specified number of milliseconds.

wait(), on the other hand, simply pauses the thread until either (a) the specified number of milliseconds have elapsed or
(b) it receives a desired notification from another thread (whichever is first), without keeping a hold on the monitor/lock of the shared object.

sleep() is most commonly used for polling, or to check for certain results, at a regular interval. wait() is generally used in
multithreaded applications, in conjunction with notify() / notifyAll(), to achieve synchronization and avoid race conditions.


Here is an example of a typical recursive function, computing the arithmetic series 1, 2, 3…N. Notice how the addition is performed after
the function call. For each recursive step, we add another frame to the stack.

public int sumFromOneToN(int n) {
	  if (n < 1) {
		return n;
	  }

	  return n + sumFromOneToN(n - 1);
	}
	

Tail recursion occurs when the recursive call is in the tail position within its enclosing context –
after the function calls itself, it performs no additional work. That is, once the base case is complete,
the solution is apparent. For example:

public int sumFromOneToN(int n, int a) {
	  if (n < 1) {
		return a;
	  }

	  return sumFromOneToN(n - 1, a + n);
	}
	

Here you can see that a plays the role of the accumulator – instead of computing the sum on
the way down the stack, we compute it on the way up, effectively making the return trip unnecessary,
since it stores no additional state and performs no further computation. Once we hit the base case, the work is done – below is that same function, “unrolled”.

public int sumFromOneToN(int n) {
	  int a = 0;

	  while(n > 0) {
		a += n--;
	  }
	  
	  return a;
	}
	

Many functional languages natively support tail call optimization, however the JVM does not. In order
to implement recursive functions in Java, we need to be aware of this limitation to avoid
StackOverflowErrors. In Java, iteration is almost universally preferred to recursion.


This can be done using Thread.UncaughtExceptionHandler.

Here’s a simple example:

// create our uncaught exception handler
	Thread.UncaughtExceptionHandler handler = new Thread.UncaughtExceptionHandler() {
		public void uncaughtException(Thread th, Throwable ex) {
			System.out.println("Uncaught exception: " + ex);
		}
	};

	// create another thread
	Thread otherThread = new Thread() {
		public void run() {
			System.out.println("Sleeping ...");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				System.out.println("Interrupted.");
			}
			System.out.println("Throwing exception ...");
			throw new RuntimeException();
		}
	};

	// set our uncaught exception handler as the one to be used when the new thread
	// throws an uncaught exception
	otherThread.setUncaughtExceptionHandler(handler);

	// start the other thread - our uncaught exception handler will be invoked when
	// the other thread throws an uncaught exception
	otherThread.start();
	

How did you like it?

Leave a Reply