Publicis Sapient

Publicis Sapient | Hiring Assessment | 1st Round | Interview | JAVA Full Stack Developer

Section: Fundamentals

In OOAD, what is a weak ‘has-a’ relationship (where the contained object’s lifecycle does not depend on the container object’s lifecycle) termed as?

Welcome to your javainterface


  1. Encapsulation
  2. Inheritance
  3. Aggregation
  4. Composition

Answer: Aggregation

Explanation: In object-oriented analysis and design (OOAD), a weak ‘has-a’ relationship is called “aggregation”. This relationship implies that while the contained object (the ‘part’) can be associated with the container object (the ‘whole’), it can exist independently of the container.

For example, a classroom contains students; this is an aggregation because students can exist without being associated with a particular classroom. Conversely, “composition” is a strong ‘has-a’ relationship where the contained object’s lifecycle is strictly bound to the lifecycle of the container object. An example of composition would be the relationship between an engine and a car; an engine is an integral part of the car, which usually doesn’t exist independently outside of a car. ​

Question 2: Assume the following method is properly synchronized and called from a thread A on an object B: wait(2000); After calling this method, when will the thread A become a candidate to get another turn at the CPU?


  1. After thread A is notified, or after two seconds.
  2. After the lock on B is released, or after two seconds.
  3. Two seconds after thread A is notified.
  4. Two seconds after lock B is released.


  1. After thread A is notified, or after two seconds.


This is because when wait(2000) is called, thread A will wait for up to two seconds to be notified. If it receives a notification (via notify() or notifyAll() on object B) before two seconds have elapsed, it will resume sooner. If not, it will resume once the two-second wait time has expired. However, it’s important to note that “becoming a candidate for CPU time” does not mean it will immediately run; it will first need to re-acquire the lock on object B.

Question 3: Which of the following statements regarding ‘break’ and ‘continue’ are true?


  1. Break without a label can occur only in a switch, while, do, or for statement.
  2. Continue without a label can occur only in a switch, while, do, or for statement.
  3. Break can never occur without a label.
  4. Continue can never occur WITH a label.

Explanation: The break statement, when used without a label, can be utilized within loops (for, while, do-while) and switch statements to terminate the loop or switch block. The continue statement, also when used without a label, can only be used within loops to skip to the next iteration of the loop.

The continue statement with a label is used to skip the current iteration of an outer loop marked with the given label. Therefore, the statement about continue without a label is the correct one as per the Java language specification.

In Java, “label” is a term for a construct that can precede a statement block, creating a labeled block. This is primarily used in conjunction with break and continue statements in loops to control the flow of the program more precisely, particularly when nested loops are involved.

Without Label

When break and continue are used without a label, they apply to the nearest inner loop in which they are called.

  • A break statement without a label will terminate the nearest enclosing while, do-while, for, or switch statement.
  • A continue statement without a label will skip to the next iteration of the nearest enclosing while, do-while, or for loop.

With Label

When used with a label, break and continue affect the flow of the program at the labeled (outer) loop.

  • A break with a label will exit the labeled loop, not just the innermost loop.
  • A continue with a label will skip to the next iteration of the labeled (outer) loop.

Here is an example to demonstrate the use of labeled break and continue:

public class LabelExample {
    public static void main(String[] args) {
        outerLoop: // This is a label
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                // If j is 2, continue with the outer loop labeled as outerLoop
                if (j == 2)
                    continue outerLoop;
                // If i is 2, break the outer loop labeled as outerLoop
                if (i == 2)
                    break outerLoop;
                System.out.println("i: " + i + ", j: " + j);

In this code, when i is 2, the break outerLoop; statement will exit the entire outerLoop, not just the inner loop where j runs. Similarly, when j is 2, continue outerLoop; will skip the rest of the inner loop’s current iteration and proceed with the next iteration of outerLoop.

Without the labels, a break would only exit the inner j loop, and continue would only skip to the next iteration of the inner j loop. The use of labels allows for controlling the flow of nested loops in a more granular way.

Question 4: How can you declare a method someMethod() such that an instance of the class is not needed to access it and all the members of the same package have access to it?


  1. static void someMethod()
  2. void someMethod()
  3. protected void someMethod()
  4. public abstract static void someMethod()

Correct Answer:

  1. static void someMethod()

Explanation: The method needs to be declared as static to be called without an instance of the class. By default, without any access modifier, the method has package-private access, which means it is accessible to all classes within the same package. The static the keyword indicates that the method is associated with the class rather than any particular instance of the class, allowing it to be accessed without creating an object of the class.

Option 2, void someMethod(), would require an instance of the class to be accessed. Option 3, protected void someMethod(), while it does allow access by subclasses and package members, is more restrictive than the default package-private level when considering access by non-subclass code within the same package. Option 4, public abstract static void someMethod(), is incorrect because abstract methods cannot be static; abstract methods require an implementation in a subclass, whereas static methods cannot be overridden and belong to the class.

Therefore, the correct way to declare someMethod() so that it does not need an instance and is accessible within its package is to declare it with the static keyword and without any access modifier (making it package-private by default).

Question 5:
Is it possible to have an abstract class without abstract methods?


  1. TRUE
  2. FALSE

Correct Answer:

  1. TRUE

An abstract class in Java does not need to have abstract methods. The abstract class can provide implementations of all its methods and still be declared abstract. This might be useful if the class should not be instantiated on its own, meaning the designer wants the class to be extended before it is used. Here’s an example to illustrate:

abstract class AbstractWithoutMethods {
    void concreteMethod() {
        System.out.println("This is a concrete method in an abstract class.");
// This abstract class does not contain any abstract methods.

Even though AbstractWithoutMethods does not have any abstract methods, it is declared abstract and thus cannot be instantiated. Classes that extend AbstractWithoutMethods will inherit the concreteMethod, and they can also be instantiated if they are not abstract themselves.Sec

Section: Collection

Question 1:
The advantage of …………… is that they solve the problem of sequential storage representation. But the disadvantage
that is they are sequential lists.


  1. Lists
  2. Linked Lists
  3. Trees
  4. Queues

Correct Answer:

  1. Linked Lists

Linked lists are data structures that store elements in nodes; these nodes are linked using pointers or references. Unlike arrays (a type of sequential list with a fixed size where elements are stored contiguously), linked lists do not require a contiguous block of memory, and their size can be altered during runtime. The advantage of linked lists is that they can overcome the limitations of a sequential storage representation by allowing dynamic memory allocation and efficient insertion and deletion operations. However, the disadvantage of linked lists is that access time to individual elements is sequential (O(n)), as opposed to the constant time (O(1)) access provided by arrays. This means that to access the nth element, you must traverse all the previous elements.

Question 2: Is ArrayList fail-fast?


  1. true
  2. false

Correct Answer:

  1. true

Explanation: In Java, ArrayList is considered a fail-fast collection. This term refers to the immediate failure behavior (throwing a ConcurrentModificationException) when a collection is structurally modified while it is being iterated over by a thread, other than through the iterator’s own remove or add methods. This is typically the result of modifying the collection directly while it is being iterated over, which the ArrayList class’s iterator does not support.

The fail-fast behavior helps prevent unpredictable results and potential bugs that could arise from concurrent modification.

Keep in mind that fail-fast behavior is not the same as thread-safe. It merely alerts the programmer quickly if there is a concurrent modification, rather than ensuring consistent behavior in a multi-threaded environment. For thread-safe operations on lists, you would need to use other data structures like Vector or synchronized versions of the list created using Collections.synchronizedList.

Question 3: How does a Set in Java ensure that there are no duplicates?


  1. It compares the objects by examining only equals() method.
  2. It compares the objects by examining only hashCode() method.
  3. Given two objects a and b, if a.hashCode() == b.hashCode() evaluates to true, then it is further evaluated to see if a.equals(b) also results to true.
  4. If any of the a.hashCode() == b.hashCode() or a.equals(b) evaluation results in true, then it is assumed that the objects are duplicate.

Correct Answer:

  1. Given two objects a and b, if a.hashCode() == b.hashCode() evaluates to true, then it is further evaluated to see if a.equals(b) also results to true.

In Java, Set implementations, such as HashSet, use both the hashCode() and equals() methods to ensure that no duplicates are present. When an object is inserted into a Set:

  • First, the hashCode() method is called to determine which “bucket” the object should go into. If no other objects are in that bucket, the object is added without any need to call equals().
  • If there are already objects in the bucket (which means their hash codes are the same), the equals() method is called to check if any of the objects in the bucket is equal to the current object. If equals() returns true for any comparison, the current object is not added, maintaining the no-duplicate property of the set.

This approach ensures that objects are not considered duplicates based solely on hash code because different objects can have the same hash code (hash collisions). The equals() method is the final check to confirm uniqueness.

Option 4 is incorrect because if only the hash codes match (but equals() returns false), the objects are not considered duplicates, and both can exist in the set.

In the code snippet provided, what is the outcome?

1. List ints = Arrays.asList(1,2);
2. List nums = ints;
3. nums.add(3.14);

A. No compilation error
B. Compilation error at line 2
C. Compilation error at line 3
D. Runtime error at line 2

Correct Answer:
D. Runtime error at line 3

The code is attempting to add a new element to a list created by Arrays.asList(). The Arrays.asList() method returns a fixed-size list backed by the specified array. This means that the list does not support any structural modifications such as adding or removing elements. Attempts to modify the returned list, whether directly or via its iterator, result in an UnsupportedOperationException.

However, this is a runtime exception, not a compilation error. Therefore, the correct answer should be:

package collections.list;
import java.util.Arrays;
import java.util.List;
public class ListTest {
    public static void main(String[] args) {
     try {
            // This list is backed by an array and cannot be structurally modified
            List<Integer> ints = Arrays.asList(1, 2);
            List nums = ints; // This assignment is fine
            nums.add(3.14); // This will throw a runtime exception
        } catch (UnsupportedOperationException e) {
            System.out.println("Caught an UnsupportedOperationException: You cannot add elements to the list");

Certainly! Below is a Java program with the main method (public static void main(String[] args)) that will demonstrate what happens when you try to run the code from your image:

javaCopy code

import java.util.Arrays; import java.util.List; public class ListTest { public static void main(String[] args) { try { // This list is backed by an array and cannot be structurally modified List<Integer> ints = Arrays.asList(1, 2); List nums = ints; // This assignment is fine nums.add(3.14); // This will throw a runtime exception } catch (UnsupportedOperationException e) { System.out.println("Caught an UnsupportedOperationException: You cannot add elements to the list"); } } }

When you run this code, it will catch the UnsupportedOperationException thrown when attempting to add a new element to the list returned by Arrays.asList(). The list cannot be structurally modified, meaning that you cannot add or remove elements from it.

The output will be:

Caught an UnsupportedOperationException: You cannot add elements to the list

Question 5:
All collection classes are available in the __________ package.


  2. java.lang
  3. java.awt
  4. java.util

Correct Answer:

  1. java.util

The java.util package contains all the classes and interfaces for the collection framework. The collections framework provides various data structures and algorithms for handling collections of objects, such as lists, sets, queues, and maps. The package is for input and output operations, java.lang contains fundamental classes, and java.awt is for Abstract Window Toolkit, which provides a set of APIs for creating and managing the user interface for Java programs.

Section: Multithreading

Question 1: Select the correct statement(s) regarding the wait() method in Java.


  1. wait() can be called from a synchronized block.
  2. wait() can be called from a non-synchronized block.
  3. wait() can’t be called from a synchronized block.
  4. wait() can’t be called from a non-synchronized block.

Correct Answer: a) wait() can be called from a synchronized block. d) wait() can’t be called from a non-synchronized block.

Explanation: The wait() method in Java is used to put the current thread into a waiting state. It must be called from within a synchronized context, which means it can only be called from within a synchronized block or method. If you attempt to call wait() without holding the appropriate lock (i.e., outside of a synchronized block), it will throw an IllegalMonitorStateException.

So, the statements a) and d) are correct. Statement b) is incorrect because calling wait() outside a synchronized block will result in an exception, and statement c) is incorrect because it is the antithesis of the correct usage of wait(). ​​

Question 2:
Which two of the following methods are defined in class Thread?

  1. start()
  2. wait()
  3. notify()
  4. run()
  5. terminate()


  • 1 and 4
  • 2 and 3
  • 3 and 4
  • 2 and 4

Correct Answer:
1 and 4

In Java, the Thread class has two key methods related to the lifecycle of a thread:

  1. start(): This method is used to start a newly created thread; it causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
  2. run(): This method is meant to contain the code that constitutes the new thread’s task.

The methods wait(), notify(), and notifyAll() are methods of the Object class, not the Thread class. They are used for inter-thread communication and must be called from within a synchronized context.

The method terminate() is not a standard method in the Thread class or any standard Java class; Java threads are stopped by simply returning from their run method, or by being interrupted.

Section: Java Memory Management

Question 1:
Below method of Runtime class forcibly terminates the currently running Java Virtual Machine and should be used with extreme caution?

A. public void halt()
B. public void exit(int status)
C. public void halt(int status)
D. public boolean removeShutdownHook()

Correct Answer:
C. public void halt(int status)

The halt(int status) method of the Java Runtime class can be used to forcibly terminate the currently running Java virtual machine🥵. This method does not perform any cleanup or run shutdown 😒 hooks before terminating, unlike the exit(int status) method which initiates a shutdown sequence and can run shutdown hooks or perform finalization before the JVM exits.

The halt method should be used with caution because it does not give the JVM a chance to clean up and may leave resources in an inconsistent state.

Question 2:
Which of the below class loaders loads JDK internal classes?

A. Bootstrap
B. Extensions
C. System
D. None of the Above

Correct Answer:
A. Bootstrap

In Java, the Bootstrap ClassLoader is the root of the class loader hierarchy and is part of the core JVM. It loads the core Java libraries located in the <JAVA_HOME>/jre/lib directory, such as rt.jar and other core libraries which contain JDK internal classes.

The Extension ClassLoader loads classes that are an extension of the standard core Java classes. The System (or Application) ClassLoader loads classes from the system classpath, which by default is set to the current directory.

If the question refers to the class loader responsible for loading the JDK internal classes, then the Bootstrap ClassLoader is the correct answer.

The removeShutdownHook() method is used to de-register a previously registered virtual machine shutdown hook. It’s not related to terminating the JVM but rather to the cleanup process during a normal shutdown sequence.

It seems we’ve encountered an internal error while processing the images. Despite this, let’s tackle the content based on the visible parts of your screenshot and typical Java knowledge:

Question 3:
Below are the valid differences between Stack Memory and Heap Space.


  • Objects stored in heap space are globally accessible whereas Stack memory is thread-specific and not accessible from other threads.
  • -Xmx JVM option defines heap size and -Xms defines stack memory size.
  • Heap memory is used by all the parts of the application whereas stack memory is used only by one thread of execution.
  • All the statements

Answer: first and third ones

The first statement is true: Objects in the heap are accessible globally as long as there is a reference to them, and each thread has its own stack that isn’t accessible to other threads.

The second statement is partially true: -Xmx defines the maximum heap size, but -Xms defines the initial (or starting) heap size, not the stack memory size. Stack memory size for each thread is typically defined by -Xss.

The third statement is true: Heap memory is a shared resource among all threads, whereas each thread in Java has its own stack memory.

Based on this, the correct statements, considering typical Java behavior, are the first and third ones. The second statement contains an inaccuracy regarding what -Xms stands for. If we need to select all that apply and there’s no option combining the first and third, “All the statements” would be incorrect due to the inaccuracy in the second statement.

Section: Java 8 Features

Question 1:
What is the benefit of using Generics in your code?


  1. Generics improve the performance of the code.
  2. Generics make code more readable.
  3. Generics add stability to your code by making errors detectable at compile time.
  4. Generics add stability to your code by making errors detectable at run time.

Correct Answer:

  1. Generics add stability to your code by making errors detectable at compile time.

Generics in Java are a language feature that allows for the definition and use of generic types and methods. They serve several purposes:

  • Type Safety: Generics provide stronger type checks at compile time and can catch errors that could otherwise only be detected at run time.
  • Elimination of Casts: Generics allow you to avoid casting, as you can communicate the type of a collection.
  • Generic Algorithms: By using generics, you can write algorithms that work on collections of different types.

One of the primary benefits of generics is indeed making errors detectable at compile time rather than at run time, which aligns with option 3. This is because, with generics, the compiler inserts the necessary casts for type parameters and checks that your code does not violate type safety.

Option 1 is incorrect because generics do not necessarily improve the performance of the code. The performance is typically the same as with non-generic code after type erasure by the Java compiler.

Option 2 is subjective; while generics can make code more readable by clearly specifying the types used, the primary benefit is type safety and compile-time checking.

Option 4 is incorrect; the whole point of generics is to shift error detection to compile time, not run time.

Question 2:

The original code is an anonymous class implementing the Runnable interface:

Runnable r = new Runnable(){
    public void run() {
        System.out.println("My Runnable");

The task is to choose the correct lambda expression equivalent.

The correct implementation using a lambda expression would be:

Runnable r = () -> {
    System.out.println("My Runnable");

Lambda expressions are a feature introduced in Java 8 that allow you to implement methods from functional interfaces (interfaces with a single abstract method) more concisely. Since Runnable is a functional interface with a single abstract method run(), it can be implemented with a lambda expression as shown above.

The screenshot indicates a question about lambda expressions in Java, specifically with the ToIntBiFunction functional interface.

Question 3:
The following
syntax is valid for which Java version:

ToIntBiFunction<Integer, Integer> add = (a, b) -> a + b;


  • None of the Java versions
  • Java 8 and later
  • Java 7 and later
  • Java 5 and later

Correct Answer:
Java 8 and later

Lambda expressions were introduced in Java 8. They provide a clear and concise way to represent a single-method interface using an expression. The ToIntBiFunction is a functional interface introduced in Java 8 in the java.util.function package. It represents a function that takes two arguments of type T and U and returns an int-valued result.

This syntax is not valid before Java 8 as lambda expressions and functional interfaces like ToIntBiFunction were not present in earlier versions of Java.

It seems there’s still a hiccup with the image processing. However, I can provide a general explanation based on the content of the image you’ve uploaded.

Question 4:
Choose the correct output for the following code snippet:

public class Example {
    public static void main(String[] args) {
        Optional<String> GOT = Optional.of("Game of Thrones");
        String[] str = new String[10];
        Optional<String> strOpt = Optional.ofNullable(str[9]);


  • false,
  • true
  • true
  • compiler error

Correct Answer:

  • false

The Optional.ofNullable method will create an Optional object that contains a value if the specified value is non-null, otherwise, the Optional object will be empty. Since str[9] is null (as it is not initialized), strOpt.isPresent() will return false.

The Optional.of method requires a non-null value to create an Optional object. Since “Game of Thrones” is a non-null value, GOT.isPresent() will return true.

Therefore, the output of the code will be false followed by true, corresponding to the correct option.



About Author

As Neelabh Singh, I am a Senior Software Engineer with 6.6 years of experience, specializing in Java technologies, Microservices, AWS, Algorithms, and Data Structures. I am also a technology blogger and an active participant in several online coding communities.