All 75 Java quiz questions below come with a short explanation, visible right on the page — no sign-in needed. They're grouped by beginner and intermediate levels and 29 subtopics, so you can revise one part at a time. Choose Try Java quiz above to take a scored run and review the questions you got wrong.
A.true / true / true — all three hold "abc" so the JVM merges them into one object
B.true / false / false — String's equals() compares references like ==, so different objects are unequal
C.false / false / true — == on a String is always false because a String is an object; only equals() can compare
D.true / false / true — the two literals share the String pool while new String always creates a new object
Answer: D
It prints true / false / true. The two "abc" literals point to the same String pool object, so a == b is true. new String("abc") always creates a new object outside the pool, so a == c is false. equals() compares character content, so a.equals(c) is true. Rule: always compare Strings with equals(), never ==.
A.A compile error — calling a method without using its return value is invalid for String
B."hi" — Strings are immutable: both methods return new objects, and without reassignment they are lost
C."hi there" — concat() edits s directly while toUpperCase() only counts if reassigned
D."HI THERE" — the two methods concatenate and then uppercase s in turn
Answer: B
It prints "hi". String is immutable — once created its content cannot change. concat() and toUpperCase() do not modify s, they return new String objects; since nothing is reassigned, both results are discarded. To keep the result you must write s = s.concat(" there"). This is the fundamental difference from StringBuilder (mutable, modified in place).
A."..." — the variable is declared as Animal so the compiler picks Animal's method at compile time
B."Woof" — the method is dispatched at runtime by the object's actual type
C.It prints both "..." and "Woof" — the parent's version runs first and then the child's override
D.A compile error — a Dog object cannot be assigned to an Animal variable
Answer: B
It prints "Woof". Instance methods in Java are dispatched dynamically at runtime: the JVM looks at the object's actual type (Dog), not the variable's declared type (Animal), to choose which method implementation runs. This is runtime polymorphism through overriding — unlike overloading, which the compiler resolves at compile time based on the parameter types.
Which statement about the difference between ArrayList and LinkedList is correct?
A.LinkedList is always faster than ArrayList for adding or removing at any position
B.LinkedList has O(1) get(i) because each node holds a pointer to any position in the list
C.ArrayList (a dynamic array) has O(1) get(i) with good cache locality; LinkedList's get(i) is O(n)
D.ArrayList is thread-safe while LinkedList is not, so multithreaded code must use ArrayList
Answer: C
ArrayList is backed by a dynamic array: get(i) is O(1), contiguous memory gives good cache locality — the default choice for a List. LinkedList is a doubly-linked list: get(i) is O(n) since it must traverse nodes, and costs ~24 bytes per element for the node and pointers. If you need a FIFO queue/deque, use ArrayDeque — it's faster than LinkedList in every operation.
How do checked and unchecked exceptions differ in Java?
A.An Error such as OutOfMemoryError is a checked exception, so every method must declare throws
B.The compiler forces a checked exception to be handled with try-catch or throws; an unchecked one is not
C.A checked exception is detected at compile time while an unchecked one can only occur at runtime
D.NullPointerException is checked because it inherits from Exception
Answer: B
Checked exceptions (IOException, SQLException...) are every Exception outside the RuntimeException branch — the compiler forces try-catch or a throws declaration, representing recoverable situations. Unchecked ones (RuntimeException and subclasses: NPE, IllegalArgumentException...) are not forced to be handled and usually indicate programming bugs. Error (OutOfMemoryError) is a separate branch, unchecked, and should not be caught.
How do an abstract class and an interface differ in Java (Java 8 onward)?
A.Since Java 8, default methods make an interface fully equivalent to an abstract class — it can declare instance fields and constructors
B.An interface cannot contain any method with a body — every method must be abstract
C.Abstract class: extend one, with constructors and state; interface: implement many, with no state
D.A class can extend several abstract classes at once but implement only one interface
Answer: C
The core difference after Java 8: an abstract class can be extended only once, has constructors and instance fields (shared state); an interface can be implemented many times, has no constructor, and its fields are only public static final constants. Default/static methods (Java 8+) let an interface hold code but add no state. Rule of thumb: prefer interfaces by default; pick an abstract class only when you need shared state or constructor control.
A.(1) is valid and (2) is an error — final locks only the reference, not the object's contents
B.Both are compile errors — final makes the object fully immutable and forbids every modification
C.(1) is a compile error and (2) is valid — final forbids editing the contents but allows repointing at a new object
D.Both are valid — final is only documentation and the compiler does not check it
Answer: A
(1) is valid, (2) is a compile error. final on a variable means it's assigned exactly once — you can't point the variable at another object. But final doesn't make the object immutable: names.add("Ada") still modifies the list contents normally. To truly make a list unmodifiable, use List.copyOf(...) or List.of(...). Distinguishing "locking the reference" from "locking the object" is the point of this question.
A.A compile error — a record does not generate accessors, so getX() must be written by hand
B.false and 1 — a record does not override equals and so uses Object's default reference comparison
C.true and a compile error at a.x() — a record's accessors follow the JavaBean getX() convention
D.true and 1 — a record generates equals/hashCode by value, with accessors of the form x()
Answer: D
Prints true and 1. A record (Java 16+) auto-generates: the canonical constructor, accessors named after the component (x(), not getX()), equals/hashCode comparing component values, and toString. So two Point(1, 2) instances are equals even though they are different objects. Record fields are implicitly private final — a record is the most concise way to declare an immutable value type.
A.Comparator must be implemented inside the class being sorted, while Comparable is passed in from outside as a lambda
B.Comparable: compareTo() inside the class, one natural ordering; Comparator: defined outside
C.Collections.sort(list) works with any element type, even without Comparable or Comparator
D.A class implementing Comparable can no longer be sorted with a Comparator
Answer: B
Comparable: implement compareTo() inside the class, providing ONE natural ordering (String, Integer, LocalDate all have it). Comparator: defined externally via a separate class or lambda, providing MANY context-dependent orderings, usable even when the original class cannot be modified. A Comparator can override the natural ordering: list.sort(comparator). Java 8+ offers chaining helpers: comparing(), thenComparing(), reversed().
Which statement about Garbage Collection in Java is correct?
A.With a GC in place, a Java application cannot leak memory
B.Calling System.gc() forces the JVM to run a full GC immediately
C.An object is reclaimed the moment it stops being used, like a deterministic C++ destructor
D.The GC reclaims objects no longer reachable from the GC roots; System.gc() is only a hint
Answer: D
GC reclaims objects no longer reachable from GC roots (stack, static fields, running threads) — the criterion is reachability, not "still in use or not". System.gc() is only a hint; the JVM may ignore it. GC cannot prevent Java-style leaks: useless objects still held by references (static collections, caches without eviction, listeners never removed) are never reclaimed.
What does 5 / 2 between two int values yield in Java?
A.3 — the result is rounded up to the nearest integer
B.2 — integer division truncates the fractional part
C.2.5 — Java converts to a floating-point type automatically
D.A compile error because the result cannot be represented as an integer
Answer: B
The result is 2. Dividing two integers yields an integer and the fractional part is truncated, not rounded. To get a decimal result you must cast one operand to a floating-point type first.
What problem do text blocks (""") solve in Java 15?
A.Reducing string memory by compressing multi-line content
B.Allowing a string to change its contents after creation
C.Allowing expressions to be embedded in a string like a template literal
D.Writing multi-line strings without escaping and manual concatenation
Answer: D
It lets you write multi-line strings without escaping quotes and without manually joining lines. It suits JSON, SQL, and HTML embedded in code — previously such snippets were nearly unreadable because of dense escape characters.
How does List.of() (Java 9) differ from new ArrayList<>()?
A.It is optimised for random access more than an ordinary list
B.It sorts the elements into natural order automatically
C.It is immutable and rejects null elements
D.It can hold at most ten elements
Answer: C
It is immutable — any add, remove, or set operation throws an exception — and it does not accept null. It is also more memory-efficient and safe to share across threads without synchronization.
Where do objects and local variables live in JVM memory?
A.Both on the heap, because everything in Java is an object
B.It depends on size; small objects go on the stack as an optimisation
C.Objects on the heap, local variables and references on each thread's stack
D.Both on the stack so memory is freed faster
Answer: C
Objects live on the heap — the area shared between threads and managed by the GC. Local primitive variables and references live on each thread's own stack, freed automatically when the method ends.
Reassigning an object parameter inside a method — does the caller variable change?
A.No, because Java always passes by value
B.Yes, because objects are passed by reference
C.It depends on whether the parameter is declared final
D.Yes, but only for user-defined types
Answer: A
No. Java is always pass-by-value: the parameter gets a copy of the reference. Reassigning only changes that copy. But mutating the object's contents is visible to the caller, since both point to the same object.
How does final differ on a variable, a method, and a class?
A.In all three cases it means the contents cannot change
B.No reassignment, no overriding, no subclassing
C.It only affects variables; the other two are ignored
D.It becomes a compile-time constant in all three cases
Answer: B
On a variable it means it can't be reassigned; on a method it means a subclass can't override it; on a class it means no class can extend it. Three different constraints sharing one keyword.
Printing an object without overriding toString() gives a strange string. What is it?
A.The class name plus a hexadecimal hash code
B.The object's creation sequence number
C.A list of the object's fields as a string
D.The object's real memory address in the heap
Answer: A
It's the class name plus the hash in hexadecimal. The default implementation doesn't read any fields, so it carries no useful information — which is why classes used for logging should override it.
All three: no arguments (receives an empty array), several separate arguments, and an existing array. The compiler packs the separate arguments into an array before the call.
What is the most important difference between int and Integer?
A.One is for arithmetic while the other is only for display
B.One is a primitive while the other is an object accepting null
C.One is thread-safe and the other is not
D.One holds far larger numbers than the other
Answer: B
One is a primitive that stores the value directly; the other is an object, so it can be null and used in collections. In exchange, the object type uses more memory and risks null reference errors.
A."Parent" — a static method is hidden rather than overridden, and resolves at compile time
B."Parent" then "Child" — the JVM runs the parent's version then the child's along the inheritance chain
C.A compile error — a static method may not share a signature with the parent class's
D."Child" — the real object is a Child so Child's version is chosen, like any other method
Answer: A
Prints "Parent". Static methods don't participate in dynamic dispatch: declaring a static method with the same signature as the parent creates method hiding, not overriding. The call p.who() is resolved at compile time based on the declared type of the reference (Parent). Correct practice: always call static methods via the class name (Parent.who()), never through an instance.
Which statement about how HashMap works internally is FALSE?
A.Entries go into a bucket by hashCode(); within a bucket equals() distinguishes them
B.A HashMap guarantees iterating the keys in the order they were put in
C.Editing a key's field so its hashCode changes after the put makes the entry almost unfindable
D.Since Java 8, a bucket longer than the threshold of 8 is converted into a red-black tree
E.Exceeding capacity × load factor (0.75) doubles the bucket array
Answer: B
HashMap uses a bucket array: the key's hashCode() locates the bucket, collisions are resolved with a linked list plus equals() comparison. Java 8+ converts a list longer than 8 into a red-black tree (O(log n)). When capacity × 0.75 is exceeded, the array doubles and entries are redistributed. HashMap does not preserve insertion order, and a key whose hashCode is modified after put will lose its entry — keys should be immutable.
B.It throws a ClassCastException at runtime because Point does not implement Comparable
C."A" — equals() returned true for two Points with the same coordinates, so the HashMap finds the entry
D.null — the two objects are equal but their hashCode() differs, so it looks in a different bucket
Answer: D
The result is null. HashMap locates the bucket using hashCode() first, then compares with equals() inside that bucket. Since Point doesn't override hashCode(), the two objects use the default identity-based hashCode — which differ — so get() looks in a different bucket than the one put stored into. equals() returning true is meaningless when it's never reached. Always override both methods together.
What does the contract between equals() and hashCode() mandate?
A.Overriding hashCode() alone is enough, since Object's default equals() already compares field contents
B.hashCode() must return a unique value per distinct object or the HashMap misbehaves
C.If a.equals(b) then a.hashCode() must equal b.hashCode(); the converse is not required
D.If a.hashCode() equals b.hashCode() then a.equals(b) must be true — an equal hash means an equal value
Answer: C
Contract: if a.equals(b) is true, then a.hashCode() must equal b.hashCode(). The reverse is not required — two different objects may share a hashCode (a valid collision). Reason: HashMap/HashSet locate the bucket by hashCode first and only then compare with equals, so two "equal" objects must land in the same bucket. So always override both methods using the same set of fields.
Unboxing null from Map.get — what happens at runtime with this code?
java
Map<String, Integer> m = Map.of("a", 1);
intx= m.get("b");
System.out.println(x);
A.A compile error — an Integer (object) cannot be assigned to an int (primitive) variable
B.It prints 0 — a missing key means the int takes the numeric type's default value
C.It throws a NullPointerException — get("b") returns null and unboxing that null Integer to an int fails
D.It throws a NoSuchElementException because Map.of() creates an immutable map that forbids missing-key access
Answer: C
Throws NullPointerException. m.get("b") returns null because the key doesn't exist. Assigning it to an int variable triggers auto-unboxing — equivalent to calling intValue() on null — which causes the NPE. This is a sneaky source of NPEs because there's no dot method call anywhere in the code. Avoid it by using getOrDefault("b", 0), or by taking an Integer and checking for null.
A.parallelStream() is always faster than a sequential stream() because it uses several CPU cores
B.A stream is single-use — reusing one after its terminal operation throws IllegalStateException
C.toList() (Java 16+) returns an UNMODIFIABLE list, unlike collect(Collectors.toList()) which returns a mutable one
D.peek() is mainly for debugging and should not be used to update external state
E.Intermediate operations (filter, map, sorted) are lazy — running only when the pipeline has a terminal operation
Answer: A
Three correct points: a stream is single-use (reusing it throws IllegalStateException); intermediate ops are lazy — they only run when a terminal op is present; toList() (Java 16+) returns an unmodifiable list, unlike collect(Collectors.toList()). Two common misconceptions: parallelStream() isn't always faster — it only pays off with large datasets and stateless ops; peek() is for debugging only, not for business side effects.
Two threads each call increment() 1,000 times. What is the final value of count?
java
classCounter {
volatileintcount=0;
voidincrement() {
count++;
}
}
// thread A: 1000 x increment()// thread B: 1000 x increment()
A.Always exactly 2000 — the JVM locks a volatile variable for the duration of the ++ to avoid a race
B.It may be less than 2000 — count++ is not atomic, and volatile only guarantees visibility
C.A compile error — the ++ operator may not be used on a volatile variable
D.Always exactly 2000 — volatile forces every read and write to main memory so the threads cannot conflict
Answer: B
The result can be less than 2000. count++ is three steps: read — add — write, and is not atomic. volatile only guarantees visibility (reads/writes go straight to main memory), not atomicity: two threads can read the same value and overwrite each other — a lost update. Correct fix: AtomicInteger.incrementAndGet() (CAS, lock-free) or synchronized around the increment.
A.A compile error — C inherits two default hello() methods with the same signature and must override it
B.A compile error because a class may never implement two interfaces that both have default methods
C.It compiles fine — the JVM picks one of the two at runtime depending on the object
D.It compiles fine — A's version wins because A comes first in the implements list
Answer: A
Compile error. C inherits two default hello() methods with the same signature from two unrelated interfaces — Java doesn't pick one automatically but reports an error, forcing C to override hello() to resolve it. In the override, A.super.hello() or B.super.hello() lets you explicitly delegate to one side. This is how Java handles the diamond problem once default methods (Java 8) put code into interfaces.
Which rule for writing an immutable class in Java is FALSE?
A.A mutable field must be defensively copied both on the way in and on the way out
B.A record (Java 16+) is only immutable at the level of its component references, not deeply
C.Every field private final and no setters — the state is assigned once through the constructor
D.Declaring every field final is enough, since the inner objects become immutable with it
E.Declare the class final so a subclass cannot override methods and expose the state
Answer: D
Three necessary rules: make the class final (block subclasses from breaking the contract); all fields private final with no setters; defensive copy both ways for mutable fields (copy on the way in via the constructor, copy or List.copyOf on the way out). Two misconceptions: final on a field only locks the reference, it doesn't make the inner object immutable; records are also only shallowly immutable — mutable components still need defensive copying.
A.It prints 1 and then "finally" — the method returns first and finally cleans up afterwards
B.It prints "finally" then 1 — the return value is computed first, finally runs, and only then does it return
C.A compile error — a return may not sit inside a try that has a finally
D.It prints only 1 — a return in try ends the method immediately so finally is skipped
Answer: B
It prints "finally" then 1. The order per the JLS: the return expression in try is evaluated first (the value 1 is saved), then finally runs, then the method returns the saved value. finally always runs whether try ends with return or an exception — only System.exit() or a JVM crash skips it. Note: putting a return in finally overrides both the try's return and any exception — avoid it.
Optional.get() on an empty Optional — what happens at runtime with this code?
java
Optional<String> o = Optional.ofNullable(null);
System.out.println(o.isPresent());
System.out.println(o.get());
A.It throws a NullPointerException on the first line — Optional does not accept a null value
B.It prints false, then get() throws NoSuchElementException — ofNullable(null) gives an empty Optional
C.It prints true then null — Optional wraps the null inside so isPresent() is true
D.It prints false then null — get() on an empty Optional returns null like Map.get() with a missing key
Answer: B
It prints false, then get() throws NoSuchElementException. Optional.ofNullable(null) returns Optional.empty() (unlike Optional.of(null), which throws NPE immediately). get() on an empty Optional throws rather than returning null. Calling get() without checking first just turns an NPE into a NoSuchElementException — use orElse/orElseGet/orElseThrow or a map/filter chain instead.
How do the fail-fast iterators of ArrayList/HashMap differ from those of CopyOnWriteArrayList and ConcurrentHashMap?
A.A ConcurrentModificationException means the collection's data is corrupted and unusable
B.Fail-fast throws ConcurrentModificationException; CopyOnWrite iterates a snapshot; ConcurrentHashMap is weakly consistent
C.CopyOnWriteArrayList also throws ConcurrentModificationException, only later, once the iterator reaches the modified element
D.Fail-fast only triggers with several threads — adding or removing inside a for-each on one thread is safe
Answer: B
Three levels of handling "modifying a collection while iterating": fail-fast (ArrayList, HashMap) tracks modCount and throws ConcurrentModificationException on a best-effort basis to surface bugs early; snapshot (CopyOnWriteArrayList) iterates a copy, never throwing but not seeing new changes; weakly-consistent (ConcurrentHashMap) never throws and may or may not see changes. Removing during single-threaded iteration: use iterator.remove() or removeIf().
A.It compiles but throws IllegalStateException at run() for accessing a changed variable
B.It compiles and prints 0 — the lambda captures count's value at the moment it was created
C.It compiles and prints 1 — the lambda reads count's latest value at the moment run() is called
D.A compile error — count++ stops the variable being effectively final, so the lambda is rejected
Answer: D
Compile error. A lambda (and anonymous class) may only capture local variables that are final or effectively final — never reassigned anywhere after initialization. count++ breaks that condition, so the compiler rejects it right at the reference inside the lambda. Reason: the lambda holds a COPY of the value (the local lives on a stack frame that may already be gone); forbidding reassignment keeps the copy and the original from ever diverging.
Why does comparing two Integer values with == work for 100 but not for 1000?
A.Because 1000 exceeds the integer type's representable range
B.Because the JVM caches Integer objects in the range −128 to 127
C.Because the comparison operator calls the value-comparison method automatically for small numbers
D.Because the compiler optimises small constants into primitives
Answer: B
Because the JVM caches the wrapper objects for the range −128 to 127. Within that range autoboxing returns the same object, so reference comparison matches. Outside that range each creation makes a new object, so the comparison gives a wrong result.
Given Integer a = null; int b = 0;, what does Integer x = flag ? a : b; with flag true cause?
A.A compile error because the two branches have incompatible types
B.It assigns 0 because the compiler substitutes the default value for null
C.It assigns null to the variable as normal
D.It throws a NullPointerException from unboxing a null value
Answer: D
It throws NullPointerException. One branch of the ternary operator is int, so the common type of the whole expression is widened to int — a must be unboxed before assignment, and unboxing null throws NPE. Declaring x as Integer does not help, because unboxing happens before the assignment.
Why should double not be used to store monetary amounts?
A.Because the type cannot be compared with the ordinary operators
B.Because the type is not large enough to hold big amounts
C.Because arithmetic on this type is noticeably slower than on integers
D.Because binary floating point cannot represent many decimal numbers exactly
Answer: D
Because binary floating point cannot represent many decimal values exactly. 0.1 is only an approximation, so adding it ten times does not give exactly 1.0. For money, the accumulated error over thousands of transactions is unacceptable.
What is wrong with concatenating strings using += inside a 10,000-iteration loop?
A.The garbage collector cannot clean up the intermediate strings created
B.The final result is truncated once it exceeds the maximum string length
C.Each iteration creates a new string, making it quadratic
D.The compiler refuses to compile it, detecting an inefficient loop
Answer: C
Strings are immutable, so each concatenation creates a new string and copies all the old content. Over n iterations the total cost is quadratic in n. Using StringBuilder the cost is linear because it writes into an expandable buffer.
A.A thread pool dedicated to operations on large strings
B.A structure holding compressed strings to save memory
C.A memory area holding string constants so the same object can be reused
D.A cache of the results of recent string concatenations
Answer: C
It is the memory region holding string literals for reuse. Two identical literals point to the same object. Strings created with an initialization operator or concatenated at runtime are not in it, so reference comparison between them gives a wrong result.
A.It is equivalent to declaring the type as Object and casting when needed
B.It infers the type at compile time; the variable still has a fixed static type
C.It lets the variable hold a value of any type at runtime
D.It defers deciding the type until the first assignment at runtime
Answer: B
The compiler infers the type from the initializer expression, and the variable still has a fixed static type afterwards. Java is still a statically typed language — this is only shorthand, not dynamic typing, and assigning a different type later is still a compile error.
What is the most important difference between a switch expression (Java 14) and the old switch statement?
A.It runs faster because the compiler generates a jump table
B.It can match expressions rather than only constants
C.It allows several labels in one branch
D.It produces a value, does not fall through, and must cover every case
Answer: D
Three things: it returns a value, it does not fall through, so no exit statement is needed, and it requires exhaustive coverage of all cases. These three remove exactly the three most common sources of bugs in the old form.
What does pattern matching for instanceof (Java 16) change?
A.It allows matching on the values of an object's inner properties
B.It allows full generic type checking at runtime
C.It fully replaces the need for polymorphism in class design
D.It merges the type check and the cast into one, declaring the cast variable inline
Answer: D
It merges the type check and the cast into one step: if the check matches, the cast variable is already available to use. It eliminates the repeated cast line that always sat right after the check.
How does a Java enum differ from a set of static final int constants?
A.It is type-safe and can carry its own fields and methods
B.It must be compared with the equality method rather than the operator
C.It allows new values to be added at runtime when needed
D.It uses less memory because it is represented as an integer
Answer: A
It is type-safe — it only accepts the declared constants, rather than any integer. Also, each constant is an object, so it can carry its own fields, constructor, and methods, including a different implementation per constant.
What is the initialisation order when creating an instance of a subclass?
A.All of the subclass's parts first, then the parent's
B.In the order the lines appear in the source file
C.The parent's and child's statics first, then the parent's instance parts, then the child's
D.The static blocks run again each time an object is created
Answer: C
Parent class statics, then child class statics (once only, at class loading), then the parent's initializer blocks and constructor, then the child's. Within a single class, fields and blocks run in the order they appear in the source code.
What risk does a non-static inner class holding a reference to its outer instance create?
A.A memory leak when the inner object outlives the outer one
B.An inner class can never be serialised
C.It cannot access the outer class's private fields
D.Every method call must pass through an indirection layer that slows it down
Answer: A
A memory leak. The implicit reference to the outer object keeps it in memory as long as the inner object is alive — for example, a listener registered somewhere will keep the outer object alive too, even when nobody uses it anymore.
Why can a lambda only capture "effectively final" local variables?
A.Because the specification forbids any access to variables outside the lambda's scope
B.Because the compiler cannot determine the type of a changing variable
C.Because a lambda always runs on a different thread from where it was declared
D.Because a local variable lives on the stack and may disappear before the lambda runs
Answer: D
Because a local variable lives on the stack and may disappear before the lambda runs. The lambda holds a copy of the value, so if the variable were allowed to change afterwards, the copy and the original would diverge — a source of confusing bugs.
How do the four functional interfaces Function, Supplier, Consumer, Predicate differ?
A.By whether they take an input and whether they return a result
B.By whether they run synchronously or asynchronously
C.By how many threads they may run on
D.By whether they may throw a checked exception
Answer: A
By input and output. Takes one value and returns one value; the return type may be the same as or different from the input type. Takes nothing, returns a value. Takes one value, returns nothing. Takes one value, returns a boolean. These four basic combinations cover most needs.
Which lambda is the method reference String::length equivalent to?
A.() -> String.length() — a reference to a static method
B.s -> s.length() — a reference to an instance method of an arbitrary type
C.s -> new String(s).length() — creating a new object and then calling
D.(a, b) -> a.length() + b.length() — taking two arguments
Answer: B
Equivalent to a lambda that takes a string and returns its length. This is the reference-to-instance-method-of-an-arbitrary-type form — the first argument becomes the receiver of the call.
What are the characteristics of the list returned by Arrays.asList()?
A.Fully immutable, so every write operation is refused
B.Fixed size, and a view over the original array
C.An ordinary list supporting every operation in full
D.An independent copy of the original array
Answer: B
Fixed size, and it is a view of the backing array. Adding or removing elements throws UnsupportedOperationException; but setting an element at an index is allowed, and that change is written straight to the backing array.
Two "content-equal" objects are added to a HashSet but it holds 2 elements. Why?
A.Because a set only deduplicates when the elements have exactly the same type
B.Because the two objects were added from two different threads
C.Because a compaction method must be called to remove the duplicates
D.Because the class overrides neither equals() nor hashCode()
Answer: D
Because the class doesn't override the two comparison and hashing methods. The default implementation compares by object identity, so two different objects are always considered unequal even if every field is identical.
What happens when removing an element from a List while iterating with for-each?
A.The element is removed but the loop skips the next one
B.The loop stops immediately with no error reported
C.The loop runs normally because a list supports modification while iterating
D.It usually throws a ConcurrentModificationException on the next iteration
Answer: D
Usually a ConcurrentModificationException is thrown when the iterator continues. The iterator records the collection's modification count at the start and compares it on each step, but fail-fast is best-effort, not an absolute guarantee.
B.By the keys' hash codes, like other hash structures
C.By the keys' natural order, or by a comparator passed in
D.With no defined order, depending on how the tree balances
Answer: C
By the natural order of the keys, or by a comparator passed in at construction. It's a balanced search tree, so every operation costs logarithmic rather than constant like a hash structure — in exchange you get ordering and range queries.
A stream has only filter and map operations and no terminal operation. What happens?
A.Nothing runs at all — the intermediate operations are lazy
B.Both operations run and the result is discarded
C.A compile error because the stream was never consumed
D.A runtime exception when the stream is garbage collected
Answer: A
Nothing runs. Intermediate operations are lazy — they only build the processing chain. Only when a terminal operation exists does the data actually get traversed through that chain.
What structure does Collectors.groupingBy() return?
A.A set of the grouping keys found
B.A list of the grouped sublists
C.A new stream in which the elements have been ordered by group
D.A Map from the grouping key to a list of the elements in that group
Answer: D
A mapping from grouping key to the list of elements in that group. There's a form that also takes a downstream collector to transform the values: counting, summing, or collecting into a set instead of a list.
Is using Optional as an entity field type or a method parameter appropriate?
A.Yes; using it everywhere eliminates null pointer errors entirely
B.It does not matter; this is purely a coding style question
C.No; it was designed for method return types
D.Yes for fields but not for method parameters
Answer: C
No. It's designed for a method's return type, to tell the caller that the result may not exist. As a field it can't be serialized and costs an extra object per instance; as a parameter the caller still has to wrap the value.
When wrapping one exception in another, what must you do to avoid losing information?
A.Copy the original exception's message into the new one
B.Log the original exception first and then throw the new one
C.Rethrow the original exception after throwing the new one
D.Pass the original exception into the constructor as the cause
Answer: D
Pass the original exception into the constructor as the cause. Then the printed stack trace contains both levels with a "Caused by" section, so the original line of code is still visible — instead of only the outer wrapper.
How does AtomicInteger differ from using synchronized for a counter?
A.It uses the CPU's CAS instruction and so does not block the thread
B.It can protect several variables at once in one operation
C.It lets several threads write the value without losing updates
D.It is faster in every case whatever the level of contention
Answer: A
It uses the CPU's compare-and-swap instruction instead of locks, so threads are not blocked — on failure it retries in a loop. With moderate contention this is notably faster because it avoids the cost of parking and waking threads.
A.It detects and resolves deadlocks between threads automatically
B.It lets the same thread reacquire a lock it already holds
C.It lets several threads enter the protected region when they are only reading
D.Timed and interruptible lock attempts, plus several wait conditions
Answer: D
Three main capabilities: try acquiring a lock with a time limit instead of waiting indefinitely, interruptible lock waiting, and multiple condition objects waiting on the same lock. In return you must release the lock yourself in a cleanup block, whereas the synchronized keyword releases it automatically.
A.Automatically retrying a task when a transient error occurs
B.Running a task on several threads at once to speed it up
C.Guaranteeing the task always completes even when an exception occurs
D.Chaining and combining several tasks without blocking to get a result
Answer: D
The ability to chain and combine multiple tasks without blocking. The old type only has a blocking result-getting method, so chaining three sequential calls forces you to wait at each step. The new type declares the chain and lets it run itself.
What different causes underlie OutOfMemoryError and StackOverflowError?
A.The first is catchable with try/catch while the second is not
B.The first from an exhausted heap, the second from a call chain that is too deep
C.The first at compile time, the second at runtime
D.The first from too many threads, the second from too many objects
Answer: B
The first error comes from an exhausted heap — objects still reachable exceed the memory limit. The second comes from a thread's stack being exhausted due to too-deep call chains, almost always recursion missing a stopping condition.
How do LocalDateTime, Instant and ZonedDateTime differ?
A.They differ only in the precision of their fractional seconds
B.The first carries no timezone, the middle is a point on the UTC line, the last has both
C.The first is the legacy type and the other two are its modern replacements
D.They differ in whether they can be changed after creation
Answer: B
The first type is a date-time without a time zone — suitable for birthdays or appointments in local time. The middle type is a point on the UTC timeline — suitable for event timestamps. The last type carries both the full date-time and time zone.
Why is SimpleDateFormat unsafe as a shared static variable?
A.Because it is markedly slower than creating a new one on each use
B.Because it holds internal state and is not thread-safe
C.Because it holds a reference to the default timezone and leaks memory
D.Because it does not support internationally standard date formats
Answer: B
Because it holds internal state while formatting and parsing, so it is not thread-safe. Multiple threads calling it will overwrite each other's state, producing wrong results or exceptions randomly — very hard to reproduce.
A.When the annotation is used on several kinds of element
B.When the annotation must be read by reflection at runtime
C.When the annotation has a parameter with a default value
D.When the annotation must be inherited by subclasses
Answer: B
When the annotation needs to be read via reflection at runtime. The default retention only writes it to the class file but does not load it into memory, so reflection can't see it. This is why a custom annotation isn't picked up by the framework.
Why does timing a plain loop usually give wrong Java performance results?
A.Because the garbage collector always runs just as the measurement begins
B.Because Java code is recompiled on every program run
C.Because Java's system clock is not precise enough
D.Because the JIT needs warm-up time and may eliminate code whose result is unused
Answer: D
Two causes: the JIT needs a few thousand iterations to finish optimizing, so the early iterations run much slower, and it may eliminate entirely code whose result is never used.
D.A constructor plus getters and setters for each field
Answer: C
A constructor taking all components, an accessor method for each component, plus three methods for equality, hashing, and string conversion. The fields are immutable, and the class cannot extend another class.
Why can you not write new T[10] inside a generic class?
A.Because an array may not hold elements of a type parameter
B.Because type erasure removes the type information, so at runtime it does not know what array to create
C.Because an array's size must be a compile-time constant
D.Because generics only work with types from the standard library
Answer: B
Because generic type information is erased at compile time, so at runtime the VM doesn't know which type's array to create. Arrays are the opposite — they keep their element type at runtime to check every write.
What must be done with an ExecutorService after use?
A.Call shutdown() and then wait; otherwise the JVM may never exit
B.Set the reference to it to null to release the resources
C.Nothing, because the garbage collector cleans up the thread pool
D.Call cancel on each task submitted to the pool
Answer: A
Call the shutdown method, then wait for the tasks to finish. Otherwise the pool's threads — which are not daemon threads by default — keep the VM alive and the program won't exit even after main returns.
B.One produces an immutable string and the other a mutable one
C.One synchronizes its methods and the other does not
D.One is only for old Java and the other for modern Java
Answer: C
One class synchronizes its methods to be safe when multiple threads use it, the other doesn't. Since these objects are almost always a local variable inside a method, the unsynchronized class is the right choice in most cases.
Collecting a stream into a map with duplicate keys — what happens?
A.It keeps the later value and drops the earlier one
B.It keeps the first value and ignores the rest
C.It merges both values into a list under the same key
D.It throws an exception because it does not know which value to keep
Answer: D
It throws an exception. The two-argument call has no duplicate-handling rule, so the library errors out instead of silently dropping data. To handle it, pass a merge function that decides which value to keep.
How does orElse(compute()) differ from orElseGet(() -> compute())?
A.The first always runs the function even when it is not needed
B.The first throws an exception when the value is empty
C.The second only works with primitive values
D.The two are entirely equivalent in behaviour
Answer: A
The first always runs the function, because the argument is evaluated before the call, even when a value is already present and the result is discarded. The second only runs the function when a fallback value is actually needed.
Sorting by several criteria (department, then salary descending) — how?
A.Concatenate the two fields into one string and compare that
B.Write one comparator comparing both fields by hand
C.Chain the comparators with the "then comparing" method
D.Sort twice in turn by the two different criteria
Answer: C
Chain the comparators: sort by the first criterion, then use the next comparison method for the second criterion, and reverse only the criterion that should be descending. This is shorter and less error-prone than writing comparison logic by hand.
Creating a new HashMap<>() then adding a million entries — what happens inside?
A.The entries are stored in one single linked list
B.The map switches to a tree structure once it grows large
C.The capacity is precomputed from the first entries added
D.The internal array is resized and everything rehashed several times
Answer: D
The internal array is resized and rehashed multiple times — each time the load threshold is exceeded, it doubles and redistributes all entries. Pre-declaring an expected capacity avoids most of those resizes.
In equals(), check type with instanceof or getClass()?
A.It depends on whether a subclass may be considered equal to its parent
B.Always instanceof because it also handles null
C.Always getClass() because it is more accurate in every case
D.Both give the same result so either will do
Answer: A
Depends on the design: use exact type checking when subclasses should not be considered equal to the parent — this preserves symmetry. Use the flexible check when you want a subclass to compare equal to the parent, but then the subclass must not add fields to the comparison.
Calling a checked-exception method inside a stream.map() lambda errors. Why?
A.A lambda may not contain a try-catch block
B.The matching interface declares no thrown exception
C.Checked exceptions were removed from recent Java versions
D.A stream must handle every error in its terminal operation
Answer: B
Because the lambda must match the signature of the functional interface, and that signature does not declare a checked exception. The fix is to catch the exception inside the lambda, wrap it into an unchecked exception, or move it out of the stream.
Reading a file with Files.lines(path) and processing the stream — what matters?
A.The stream holds the file open so it must be closed
B.The whole file's content is loaded into memory before processing
C.Each re-traversal automatically rereads the file from the start
D.The stream can only read files with a standard character encoding
Answer: A
The stream keeps the file open, so you must close it — usually by wrapping it in an try-with-resources block. Unlike streams from in-memory collections, this stream is tied to a system resource and does not release itself.
What is wrong with log.debug("User " + user + " logged in")?
A.The logging library does not accept a dynamically built string
B.The message displays incorrectly when it contains special characters
C.The debug level is ignored entirely when running in production
D.The string is still concatenated even when the debug level is off
Answer: D
The string is still concatenated even when debug level is off, because arguments are evaluated before the method is called. The right way is to use placeholder syntax and pass the object in, so string conversion only happens if the log is actually written.