Add fresher-qa module: 50 Java interview questions for freshers, one runnable demo each, asserted transcripts, javac error captures

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017ic4b5DfjBGLBr7F5km2AN
This commit is contained in:
Claude
2026-11-11 19:48:45 +05:30
parent 22181e1a17
commit c5c435ae20
25 changed files with 1630 additions and 0 deletions
+1
View File
@@ -19,6 +19,7 @@ One module per article. This repository currently holds:
| [`binary-tree-traversals`](binary-tree-traversals/) | Binary Tree Traversals in Java: Inorder, Preorder, Postorder and Level Order (Recursive and Iterative) | this commit |
| [`sliding-window`](sliding-window/) | Sliding Window and Two Pointers in Java: 12 Interview Problems Solved | this commit |
| [`dynamic-programming`](dynamic-programming/) | Dynamic Programming in Java for Beginners: Memoization vs Tabulation (10 Classic Problems) | this commit |
| [`fresher-qa`](fresher-qa/) | Top 50 Java Interview Questions for Freshers (2026) with Simple Answers | this commit |
## `collections` module
+32
View File
@@ -0,0 +1,32 @@
# fresher-qa
Runnable companion for the ankurm.com article
[Top 50 Java Interview Questions for Freshers (2026) with Simple Answers](https://ankurm.com/top-50-java-interview-questions-for-freshers/).
One small demo per question, grouped in six classes. Tests assert what each demo prints and write the
transcripts the article quotes. There is no `docs/` folder on purpose: the explanations live in the article.
| Component | Version | Verified against |
|---|---|---|
| JDK | 25.0.5+8 (Temurin, LTS) | `java -version` |
| JUnit | 6.1.3 | `maven-metadata.xml` on Maven Central |
| Maven | 3.9.11 | `mvn -version` |
```bash
export JAVA_HOME=/path/to/jdk-25 && export PATH="$JAVA_HOME/bin:$PATH"
cd fresher-qa
mvn test # 6 tests; rewrites output/01-06
./scripts/run-all.sh # also regenerates output/07 (javac's own error messages for src/broken/)
```
| Class | Questions | Transcript |
|---|---|---|
| `BasicsQa` | 1-9 | `output/01-basics.txt` |
| `OopQa` | 10-20 | `output/02-oop.txt` |
| `StringsQa` | 21-27 | `output/03-strings.txt` |
| `CollectionsQa` | 28-38 | `output/04-collections.txt` |
| `ExceptionsQa` | 39-43 | `output/05-exceptions.txt` |
| `ModernJavaQa` | 44-50 | `output/06-modern-java.txt` |
`src/broken/` holds five files that must NOT compile (one of them only fails below Java 25); `scripts/compile-errors.sh` runs `javac` on each and
commits the real message to `output/07-compile-errors.txt`. They are excluded from the Maven build.
+43
View File
@@ -0,0 +1,43 @@
=== Q01 Why is Java platform independent? ===
magic = CAFEBABE
class file major version = 69
=== Q02 JDK vs JRE vs JVM ===
running on Java 25
JVM: OpenJDK 64-Bit Server VM
compiler available: true
=== Q03 Primitive types and their sizes ===
byte 1 byte, -128 to 127
short 2 bytes, -32768 to 32767
int 4 bytes, -2147483648 to 2147483647
long 8 bytes, -9223372036854775808 to 9223372036854775807
float 4 bytes, double 8 bytes, char 2 bytes
field defaults: 0, false, null
=== Q04 Type casting and overflow ===
7 / 2 = 3, (double) 7 / 2 = 3.5
(byte) 130 = -126
Integer.MAX_VALUE + 1 = -2147483648
c + 1 = 66, (char) (c + 1) = B
0.1 + 0.2 = 0.30000000000000004
Math.addExact: integer overflow
=== Q05 Autoboxing and the Integer cache ===
127 == 127 -> true
128 == 128 -> false
128 equals 128 -> true
Long 127 equals Integer 127 -> false
=== Q06 Is Java pass by value or pass by reference? ===
after reassign: original
after mutate: original + mutated
=== Q07 static variables, static blocks and initialisation order ===
static block runs once, when the class loads
instance block runs before each constructor body
constructor #1
instance block runs before each constructor body
constructor #2
=== Q08 final, finally and finalize ===
final array contents changed: 99
in try
finally always runs
Object.finalize forRemoval = true, since 9
=== Q09 Stack vs heap ===
heap array length = 1000000
StackOverflowError after many frames: true
+36
View File
@@ -0,0 +1,36 @@
=== Q10 The four pillars of OOP ===
Circle area = 3.14
Rectangle area = 6.00
rejected: amount must be positive, balance still 500.0
=== Q11 Inheritance and constructor chaining ===
Animal constructor
Dog constructor
Animal constructor
Puppy constructor for Bruno
=== Q12 Method overloading vs overriding ===
FancyPrinter.show(Object)
show(String)
FancyPrinter.show(Object)
=== Q13 Abstract class vs interface ===
Scooter has 2 wheels, charging, plug Type 2
=== Q14 Polymorphism: what is and is not dynamic ===
Child.who() | Parent.field | Parent.static | Child.static
=== Q15 Can you override static, private or final methods? ===
Base.secret | Base.locked
=== Q16 How do you create an immutable class? ===
members: [Asha, Ravi]
add blocked: UnsupportedOperationException
=== Q17 Composition vs inheritance (is-a vs has-a) ===
stack = [99, 1, 2], pop gives 2
=== Q18 Access modifiers ===
a -> public
b -> protected
c -> (package-private)
d -> private
=== Q19 Object class methods: toString, equals, hashCode ===
default toString looks like ClassName@hex: true
p1.equals(p2) = true
set contains an equal point: false
=== Q20 Constructors: default, chained and private ===
default config: dev:8080
same Registry instance: true
+31
View File
@@ -0,0 +1,31 @@
=== Q21 == vs equals() on Strings ===
a == b -> true
a == c -> false
a.equals(c) -> true
=== Q22 Why is String immutable? ===
s = java
upper = JAVA
same object returned when nothing changes: true
=== Q23 String vs StringBuilder vs StringBuffer ===
builder result: cba-
append is synchronized: StringBuffer=true, StringBuilder=false
=== Q24 The string pool, compile-time constants and intern() ===
"hel" + "lo" == "hello" -> true
"hel" + lo == "hello" -> false
"hel" + finalLo == "hello" -> true
("hel" + lo).intern() == "hello" -> true
=== Q25 Reverse a string and check for a palindrome ===
weivretni
true
false
=== Q26 Useful String methods and the split() surprises ===
trim().length() = 6
strip().length() = 2
" ".isBlank() = true, "ab".repeat(3) = ababab
"a,b,,".split(",").length = 2
"a,b,,".split(",", -1).length = 4
String.join: 2026-11-11
=== Q27 Count characters, find the first non-repeating one, check anagrams ===
frequency: {s=3, w=1, i=1}
first non-repeating: w
listen/silent anagrams: true
+49
View File
@@ -0,0 +1,49 @@
=== Q28 The Collections Framework hierarchy ===
ArrayList extends AbstractList implements [List, RandomAccess, Cloneable, Serializable]
LinkedList extends AbstractSequentialList implements [List, Deque, Cloneable, Serializable]
HashSet extends AbstractSet implements [Set, Cloneable, Serializable]
TreeSet extends AbstractSet implements [NavigableSet, Cloneable, Serializable]
ArrayDeque extends AbstractCollection implements [Deque, Cloneable, Serializable]
HashMap extends AbstractMap implements [Map, Cloneable, Serializable]
TreeMap extends AbstractMap implements [NavigableMap, Cloneable, Serializable]
=== Q29 ArrayList vs LinkedList ===
ArrayList is RandomAccess: true
LinkedList is RandomAccess: false
LinkedList is also a Deque: true
after add(0, 5): [5, 10, 20, 30], get(2) = 20
=== Q30 How HashMap works internally ===
Aa: hashCode=2112, bucket (16 slots)=0
BB: hashCode=2112, bucket (16 slots)=0
Ankur: hashCode=63412443, bucket (16 slots)=12
both survive a collision: first, second, size 2
=== Q31 HashMap vs Hashtable vs ConcurrentHashMap vs TreeMap ===
HashMap: null key accepted
Hashtable: null key throws NullPointerException
ConcurrentHashMap: null key throws NullPointerException
TreeMap: null key throws NullPointerException
=== Q32 HashSet vs LinkedHashSet vs TreeSet ===
HashSet [banana, apple, cherry, pear, mango]
LinkedHashSet [pear, apple, mango, banana, cherry]
TreeSet [apple, banana, cherry, mango, pear]
=== Q33 Comparable vs Comparator ===
natural (Comparable): [Student[name=Asha, marks=88], Student[name=Meena, marks=88], Student[name=Ravi, marks=90]]
marks desc, then name: [Student[name=Ravi, marks=90], Student[name=Asha, marks=88], Student[name=Meena, marks=88]]
=== Q34 Fail-fast iterators and ConcurrentModificationException ===
removing 2 inside for-each -> ConcurrentModificationException
removing the second-to-last element threw nothing, list = [1, 2, 4]
removeIf even -> [1, 3, 5]
=== Q35 Arrays.asList() and List.of() pitfalls ===
write-through to the array: changed
Arrays.asList().add -> UnsupportedOperationException
Arrays.asList(int[]) has 1 element
List.of(.., null) -> NullPointerException
=== Q36 Queue, Deque and PriorityQueue ===
PriorityQueue polls: 1 2 3 4 5
ArrayDeque as a stack pops: cba
=== Q37 Mutable keys and the equals()/hashCode() contract in a HashMap ===
get with the mutated key: null
get with a fresh "A1" key: null
size is still 1
=== Q38 unmodifiableList() view vs List.copyOf() snapshot ===
view sees the change: [a, b, c]
copy does not: [a, b]
+21
View File
@@ -0,0 +1,21 @@
=== Q39 Checked vs unchecked exceptions ===
checked: NoSuchFileException (is an IOException: true)
unchecked: ArithmeticException: / by zero
NoSuchFileException is checked: true
=== Q40 try, catch, finally and return ===
finally runs before the method actually returns
returned 1
primitiveSnapshot = 10
finallyOverrides = 7
=== Q41 throw vs throws, and custom exceptions ===
withdrawal refused <- cause: balance 100 < 500
=== Q42 try-with-resources and suppressed exceptions ===
open first
open second
close second
close first
caught: body failed
suppressed: close failed: second
=== Q43 Error vs Exception, and multi-catch ===
Error, not Exception: Requested array size exceeds VM limit
multi-catch caught ClassCastException
+27
View File
@@ -0,0 +1,27 @@
=== Q44 Lambdas and functional interfaces ===
180.0 true 6 hello 5
=== Q45 Streams: map, filter, collect, laziness ===
[ASHA, ARJUN]
{4=2, 5=2}
nothing visited yet: no terminal operation
visited asha
first = asha
reuse -> stream has already been operated upon or closed
=== Q46 Optional ===
expensive() called
orElse : value
orElseGet : value
nothing here
=== Q47 Records ===
Point[x=1, y=2] equals Point[x=1, y=2]: true, x() = 1
rejected: negative coordinate
=== Q48 var, switch expressions and text blocks ===
{"name": "asha",
"grade": "A"}
=== Q49 Method references and default methods ===
abc
walk and swim
=== Q50 Threads: start() vs run(), and virtual threads ===
running on: main
running on: worker-1
virtual: true
+38
View File
@@ -0,0 +1,38 @@
=== javac FinalOverride.java ===
FinalOverride.java:6: error: locked() in Derived cannot override locked() in Base
String locked() { return "Derived.locked"; }
^
overridden method is final
1 error
=== javac CheckedNotHandled.java ===
CheckedNotHandled.java:6: error: unreported exception IOException; must be caught or declared to be thrown
String s = Files.readString(Path.of("missing.txt"));
^
1 error
=== javac LossyCast.java ===
LossyCast.java:3: error: incompatible types: possible lossy conversion from double to int
int x = 3.5;
^
LossyCast.java:4: error: incompatible types: possible lossy conversion from int to byte
byte b = 200;
^
2 errors
=== javac MissingReturnAndUnreachable.java ===
MissingReturnAndUnreachable.java:4: error: missing return statement
}
^
1 error
=== javac --release 21 PreSuper.java ===
PreSuper.java:8: error: flexible constructors is not supported in -source 21
super();
^
(use -source 25 or higher to enable flexible constructors)
1 error
=== javac --release 25 PreSuper.java ===
compiled without errors
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ankurm.interviewlab</groupId>
<artifactId>fresher-qa</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>java-interview-lab :: fresher-qa</name>
<description>
Runnable companion code for ankurm.com's "Top 50 Java Interview Questions for Freshers" article:
one small demo per question, with tests that assert what each demo prints and write the transcripts the article quotes.
</description>
<properties>
<maven.compiler.release>25</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>6.1.3</junit.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<argLine>-Xmx512m -Xss1m -Duser.timezone=UTC -Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# Compiles each file in src/broken/ (they are NOT part of the Maven build) and captures javac's own message.
set -uo pipefail
cd "$(dirname "$0")/../src/broken"
out=../../output/07-compile-errors.txt
: > "$out"
for f in FinalOverride CheckedNotHandled LossyCast MissingReturnAndUnreachable; do
echo "=== javac $f.java ===" >> "$out"
javac --release 25 -d /tmp/fresher-broken "$f.java" 2>&1 | grep -v '^Picked up JAVA_TOOL_OPTIONS' >> "$out"
echo >> "$out"
done
# The same file under both language levels: an error before Java 25, fine from Java 25 (JEP 513).
for rel in 21 25; do
echo "=== javac --release $rel PreSuper.java ===" >> "$out"
if javac --release "$rel" -d /tmp/fresher-broken "PreSuper.java" 2>&1 | grep -v '^Picked up JAVA_TOOL_OPTIONS' >> "$out"; [ "${PIPESTATUS[0]}" -eq 0 ]; then
echo "compiled without errors" >> "$out"
fi
echo >> "$out"
done
cat "$out"
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Regenerates every file in output/. Needs JDK 25 and Maven (first Maven run online).
# 01-06 are written by JUnit tests that assert the lines they write; 07 is javac's own output for src/broken/.
set -euo pipefail
cd "$(dirname "$0")/.."
mvn -B -q -T1 test
./scripts/compile-errors.sh > /dev/null
echo "done:"; ls -1 output
@@ -0,0 +1,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
class CheckedNotHandled {
public static void main(String[] args) {
String s = Files.readString(Path.of("missing.txt"));
}
}
+7
View File
@@ -0,0 +1,7 @@
class Base {
final String locked() { return "Base.locked"; }
}
class Derived extends Base {
String locked() { return "Derived.locked"; }
}
+6
View File
@@ -0,0 +1,6 @@
class LossyCast {
public static void main(String[] args) {
int x = 3.5;
byte b = 200;
}
}
@@ -0,0 +1,5 @@
class MissingReturnAndUnreachable {
static int sign(int n) {
if (n > 0) return 1;
}
}
+10
View File
@@ -0,0 +1,10 @@
class Animal {
Animal() { }
}
class Puppy extends Animal {
Puppy(String name) {
if (name.isBlank()) throw new IllegalArgumentException("name required");
super();
}
}
@@ -0,0 +1,167 @@
package com.ankurm.interviewlab.fresherqa;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
/** Questions 1-9: how Java runs, primitives, casting, boxing, pass-by-value, static, final, stack and heap. */
public final class BasicsQa {
private BasicsQa() {}
public static void main(String[] args) throws Exception {
run();
}
public static void run() throws Exception {
q01(); q02(); q03(); q04(); q05(); q06(); q07(); q08(); q09();
}
static void q01() throws IOException {
Qa.header(1, "Why is Java platform independent?");
// >>> q01
try (InputStream in = BasicsQa.class.getResourceAsStream("BasicsQa.class");
DataInputStream data = new DataInputStream(in)) {
int magic = data.readInt(); // first four bytes of every .class file
data.readUnsignedShort(); // minor version
int major = data.readUnsignedShort(); // class-file format version
System.out.println("magic = " + Integer.toHexString(magic).toUpperCase());
System.out.println("class file major version = " + major);
}
// <<< q01
}
static void q02() {
Qa.header(2, "JDK vs JRE vs JVM");
// >>> q02
System.out.println("running on Java " + Runtime.version().feature());
System.out.println("JVM: " + System.getProperty("java.vm.name"));
System.out.println("compiler available: " + (javax.tools.ToolProvider.getSystemJavaCompiler() != null));
// <<< q02
}
static int defaultInt;
static boolean defaultBoolean;
static String defaultString;
static void q03() {
Qa.header(3, "Primitive types and their sizes");
// >>> q03
System.out.println("byte " + Byte.BYTES + " byte, " + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE);
System.out.println("short " + Short.BYTES + " bytes, " + Short.MIN_VALUE + " to " + Short.MAX_VALUE);
System.out.println("int " + Integer.BYTES + " bytes, " + Integer.MIN_VALUE + " to " + Integer.MAX_VALUE);
System.out.println("long " + Long.BYTES + " bytes, " + Long.MIN_VALUE + " to " + Long.MAX_VALUE);
System.out.println("float " + Float.BYTES + " bytes, double " + Double.BYTES + " bytes, char " + Character.BYTES + " bytes");
System.out.println("field defaults: " + defaultInt + ", " + defaultBoolean + ", " + defaultString);
// <<< q03
}
static void q04() {
Qa.header(4, "Type casting and overflow");
// >>> q04
System.out.println("7 / 2 = " + (7 / 2) + ", (double) 7 / 2 = " + ((double) 7 / 2));
System.out.println("(byte) 130 = " + (byte) 130);
System.out.println("Integer.MAX_VALUE + 1 = " + (Integer.MAX_VALUE + 1));
char c = 'A';
System.out.println("c + 1 = " + (c + 1) + ", (char) (c + 1) = " + (char) (c + 1));
System.out.println("0.1 + 0.2 = " + (0.1 + 0.2));
try {
Math.addExact(Integer.MAX_VALUE, 1);
} catch (ArithmeticException e) {
System.out.println("Math.addExact: " + e.getMessage());
}
// <<< q04
}
static void q05() {
Qa.header(5, "Autoboxing and the Integer cache");
// >>> q05
Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println("127 == 127 -> " + (a == b));
System.out.println("128 == 128 -> " + (c == d));
System.out.println("128 equals 128 -> " + c.equals(d));
Long boxed = 127L;
System.out.println("Long 127 equals Integer 127 -> " + boxed.equals(127));
// <<< q05
}
// >>> q06
static void reassign(StringBuilder sb) {
sb = new StringBuilder("new object"); // changes only the local copy of the reference
}
static void mutate(StringBuilder sb) {
sb.append(" + mutated"); // follows the reference to the same object
}
// <<< q06
static void q06() {
Qa.header(6, "Is Java pass by value or pass by reference?");
// >>> q06b
StringBuilder sb = new StringBuilder("original");
reassign(sb);
System.out.println("after reassign: " + sb);
mutate(sb);
System.out.println("after mutate: " + sb);
// <<< q06b
}
// >>> q07
static class Order {
static int created;
static { System.out.println("static block runs once, when the class loads"); }
{ System.out.println("instance block runs before each constructor body"); }
Order() {
created++;
System.out.println("constructor #" + created);
}
}
// <<< q07
static void q07() {
Qa.header(7, "static variables, static blocks and initialisation order");
// >>> q07b
new Order();
new Order();
// <<< q07b
}
static void q08() throws Exception {
Qa.header(8, "final, finally and finalize");
// >>> q08
final int[] numbers = {1, 2, 3};
numbers[0] = 99; // legal: final fixes the reference, not the contents
System.out.println("final array contents changed: " + numbers[0]);
try {
System.out.println("in try");
} finally {
System.out.println("finally always runs");
}
Deprecated d = Object.class.getDeclaredMethod("finalize").getAnnotation(Deprecated.class);
System.out.println("Object.finalize forRemoval = " + d.forRemoval() + ", since " + d.since());
// <<< q08
}
// >>> q09
static int depth;
static void recurseForever() {
depth++;
recurseForever();
}
// <<< q09
static void q09() {
Qa.header(9, "Stack vs heap");
// >>> q09b
int[] onHeap = new int[1_000_000]; // the array lives on the heap; only the reference sits on the stack
System.out.println("heap array length = " + onHeap.length);
try {
recurseForever();
} catch (StackOverflowError e) {
System.out.println("StackOverflowError after many frames: " + (depth > 1000));
}
// <<< q09b
}
}
@@ -0,0 +1,213 @@
package com.ankurm.interviewlab.fresherqa;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.RandomAccess;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
/** Questions 28-38: the framework, ArrayList vs LinkedList, HashMap internals, sets, sorting, iterators, pitfalls. */
public final class CollectionsQa {
private CollectionsQa() {}
public static void main(String[] args) {
run();
}
public static void run() {
q28(); q29(); q30(); q31(); q32(); q33(); q34(); q35(); q36(); q37(); q38();
}
static void q28() {
Qa.header(28, "The Collections Framework hierarchy");
// >>> q28
for (Class<?> c : List.of(ArrayList.class, LinkedList.class, HashSet.class, TreeSet.class, ArrayDeque.class, HashMap.class, TreeMap.class)) {
String parents = Arrays.stream(c.getInterfaces()).map(Class::getSimpleName).toList().toString();
System.out.println(c.getSimpleName() + " extends " + c.getSuperclass().getSimpleName() + " implements " + parents);
}
// <<< q28
}
static void q29() {
Qa.header(29, "ArrayList vs LinkedList");
// >>> q29
System.out.println("ArrayList is RandomAccess: " + (new ArrayList<>() instanceof RandomAccess));
System.out.println("LinkedList is RandomAccess: " + (new LinkedList<>() instanceof RandomAccess));
System.out.println("LinkedList is also a Deque: " + (new LinkedList<>() instanceof Deque));
List<Integer> list = new ArrayList<>(List.of(10, 20, 30));
list.add(0, 5); // ArrayList shifts every later element one slot right
System.out.println("after add(0, 5): " + list + ", get(2) = " + list.get(2));
// <<< q29
}
static void q30() {
Qa.header(30, "How HashMap works internally");
// >>> q30
// Same formula as java.util.HashMap.hash() followed by the (table.length - 1) mask
for (String key : new String[] {"Aa", "BB", "Ankur"}) {
int h = key.hashCode();
int spread = h ^ (h >>> 16);
System.out.println(key + ": hashCode=" + h + ", bucket (16 slots)=" + (spread & 15));
}
Map<String, String> map = new HashMap<>();
map.put("Aa", "first");
map.put("BB", "second"); // same hashCode, so same bucket, but not equals()
System.out.println("both survive a collision: " + map.get("Aa") + ", " + map.get("BB") + ", size " + map.size());
// <<< q30
}
static void q31() {
Qa.header(31, "HashMap vs Hashtable vs ConcurrentHashMap vs TreeMap");
// >>> q31
Map<String, Map<String, Integer>> maps = new LinkedHashMap<>();
maps.put("HashMap", new HashMap<>());
maps.put("Hashtable", new Hashtable<>());
maps.put("ConcurrentHashMap", new ConcurrentHashMap<>());
maps.put("TreeMap", new TreeMap<>());
for (var e : maps.entrySet()) {
try {
e.getValue().put(null, 1);
System.out.println(e.getKey() + ": null key accepted");
} catch (NullPointerException ex) {
System.out.println(e.getKey() + ": null key throws NullPointerException");
}
}
// <<< q31
}
static void q32() {
Qa.header(32, "HashSet vs LinkedHashSet vs TreeSet");
// >>> q32
List<String> fruit = List.of("pear", "apple", "mango", "banana", "cherry");
System.out.println("HashSet " + new HashSet<>(fruit));
System.out.println("LinkedHashSet " + new LinkedHashSet<>(fruit));
System.out.println("TreeSet " + new TreeSet<>(fruit));
// <<< q32
}
// >>> q33
record Student(String name, int marks) implements Comparable<Student> {
@Override
public int compareTo(Student other) { // the "natural" order: by name
return name.compareTo(other.name);
}
}
// <<< q33
static void q33() {
Qa.header(33, "Comparable vs Comparator");
// >>> q33b
List<Student> students = new ArrayList<>(List.of(new Student("Ravi", 90), new Student("Asha", 88), new Student("Meena", 88)));
Collections.sort(students);
System.out.println("natural (Comparable): " + students);
students.sort(Comparator.comparingInt(Student::marks).reversed().thenComparing(Student::name));
System.out.println("marks desc, then name: " + students);
// <<< q33b
}
static void q34() {
Qa.header(34, "Fail-fast iterators and ConcurrentModificationException");
// >>> q34
List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5));
try {
for (Integer n : list) {
if (n == 2) list.remove(n); // structural change while the for-each iterator is live
}
} catch (java.util.ConcurrentModificationException e) {
System.out.println("removing 2 inside for-each -> ConcurrentModificationException");
}
List<Integer> second = new ArrayList<>(List.of(1, 2, 3, 4));
for (Integer n : second) {
if (n == 3) second.remove(n); // removing the second-to-last element: no exception, loop just stops
}
System.out.println("removing the second-to-last element threw nothing, list = " + second);
list.removeIf(n -> n % 2 == 0); // the safe way
System.out.println("removeIf even -> " + list);
// <<< q34
}
static void q35() {
Qa.header(35, "Arrays.asList() and List.of() pitfalls");
// >>> q35
String[] array = {"x", "y"};
List<String> view = Arrays.asList(array);
view.set(0, "changed");
System.out.println("write-through to the array: " + array[0]);
try {
view.add("z");
} catch (UnsupportedOperationException e) {
System.out.println("Arrays.asList().add -> UnsupportedOperationException");
}
System.out.println("Arrays.asList(int[]) has " + Arrays.asList(new int[] {1, 2, 3}).size() + " element");
try {
List.of("a", null);
} catch (NullPointerException e) {
System.out.println("List.of(.., null) -> NullPointerException");
}
// <<< q35
}
static void q36() {
Qa.header(36, "Queue, Deque and PriorityQueue");
// >>> q36
Queue<Integer> pq = new PriorityQueue<>(List.of(5, 1, 4, 2, 3));
StringBuilder order = new StringBuilder();
while (!pq.isEmpty()) order.append(pq.poll()).append(' ');
System.out.println("PriorityQueue polls: " + order.toString().trim());
Deque<String> stack = new ArrayDeque<>();
stack.push("a"); stack.push("b"); stack.push("c");
System.out.println("ArrayDeque as a stack pops: " + stack.pop() + stack.pop() + stack.pop());
// <<< q36
}
// >>> q37
static class Key {
String id;
Key(String id) { this.id = id; }
@Override public boolean equals(Object o) { return o instanceof Key k && k.id.equals(id); }
@Override public int hashCode() { return id.hashCode(); }
}
// <<< q37
static void q37() {
Qa.header(37, "Mutable keys and the equals()/hashCode() contract in a HashMap");
// >>> q37b
Map<Key, String> map = new HashMap<>();
Key k = new Key("A1");
map.put(k, "value");
k.id = "B2"; // the hashCode changes after the entry was filed
System.out.println("get with the mutated key: " + map.get(k));
System.out.println("get with a fresh \"A1\" key: " + map.get(new Key("A1")));
System.out.println("size is still " + map.size());
// <<< q37b
}
static void q38() {
Qa.header(38, "unmodifiableList() view vs List.copyOf() snapshot");
// >>> q38
List<String> original = new ArrayList<>(List.of("a", "b"));
List<String> view = Collections.unmodifiableList(original);
List<String> copy = List.copyOf(original);
original.add("c");
System.out.println("view sees the change: " + view);
System.out.println("copy does not: " + copy);
// <<< q38
}
}
@@ -0,0 +1,149 @@
package com.ankurm.interviewlab.fresherqa;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
/** Questions 39-43: checked vs unchecked, finally and return, custom exceptions, try-with-resources, Error vs Exception. */
public final class ExceptionsQa {
private ExceptionsQa() {}
public static void main(String[] args) {
run();
}
public static void run() {
q39(); q40(); q41(); q42(); q43();
}
static void q39() {
Qa.header(39, "Checked vs unchecked exceptions");
// >>> q39
try {
Files.readString(Path.of("missing.txt")); // checked: the compiler forces you to deal with IOException
} catch (IOException e) {
System.out.println("checked: " + e.getClass().getSimpleName() + " (is an IOException: " + (e instanceof IOException) + ")");
}
try {
int zero = 0;
System.out.println(10 / zero); // unchecked: no try/catch required
} catch (ArithmeticException e) {
System.out.println("unchecked: ArithmeticException: " + e.getMessage());
}
System.out.println("NoSuchFileException is checked: " + !RuntimeException.class.isAssignableFrom(NoSuchFileException.class));
// <<< q39
}
// >>> q40
@SuppressWarnings("finally")
static int tryOrFinally() {
try {
return 1;
} finally {
System.out.println("finally runs before the method actually returns");
}
}
static int primitiveSnapshot() {
int x = 10;
try {
return x; // value 10 is copied aside here
} finally {
x = 99; // too late to change what is returned
}
}
@SuppressWarnings("finally")
static int finallyOverrides() {
try {
throw new IllegalStateException("lost");
} finally {
return 7; // swallows the exception: never do this
}
}
// <<< q40
static void q40() {
Qa.header(40, "try, catch, finally and return");
// >>> q40b
System.out.println("returned " + tryOrFinally());
System.out.println("primitiveSnapshot = " + primitiveSnapshot());
System.out.println("finallyOverrides = " + finallyOverrides());
// <<< q40b
}
// >>> q41
static class InsufficientFundsException extends Exception {
InsufficientFundsException(String message, Throwable cause) { super(message, cause); }
}
static void withdraw(int balance, int amount) throws InsufficientFundsException {
try {
if (amount > balance) throw new IllegalArgumentException("balance " + balance + " < " + amount);
} catch (IllegalArgumentException e) {
throw new InsufficientFundsException("withdrawal refused", e); // wrap, keep the cause
}
}
// <<< q41
static void q41() {
Qa.header(41, "throw vs throws, and custom exceptions");
// >>> q41b
try {
withdraw(100, 500);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage() + " <- cause: " + e.getCause().getMessage());
}
// <<< q41b
}
// >>> q42
static class Res implements AutoCloseable {
private final String name;
private final boolean failOnClose;
Res(String name, boolean failOnClose) {
this.name = name;
this.failOnClose = failOnClose;
System.out.println("open " + name);
}
@Override
public void close() {
System.out.println("close " + name);
if (failOnClose) throw new IllegalStateException("close failed: " + name);
}
}
// <<< q42
static void q42() {
Qa.header(42, "try-with-resources and suppressed exceptions");
// >>> q42b
try (Res first = new Res("first", false); Res second = new Res("second", true)) {
throw new RuntimeException("body failed");
} catch (RuntimeException e) {
System.out.println("caught: " + e.getMessage());
System.out.println("suppressed: " + e.getSuppressed()[0].getMessage());
}
// <<< q42b
}
static void q43() {
Qa.header(43, "Error vs Exception, and multi-catch");
// >>> q43
try {
long[] tooBig = new long[Integer.MAX_VALUE];
System.out.println(tooBig.length);
} catch (OutOfMemoryError e) {
System.out.println("Error, not Exception: " + e.getMessage());
}
try {
Object o = "text";
Integer n = (Integer) o;
} catch (ClassCastException | NullPointerException e) { // multi-catch: one handler, several types
System.out.println("multi-catch caught " + e.getClass().getSimpleName());
}
// <<< q43
}
}
@@ -0,0 +1,151 @@
package com.ankurm.interviewlab.fresherqa;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** Questions 44-50: lambdas, streams, Optional, records, var/switch/text blocks, method references, threads. */
public final class ModernJavaQa {
private ModernJavaQa() {}
public static void main(String[] args) throws Exception {
run();
}
public static void run() throws Exception {
q44(); q45(); q46(); q47(); q48(); q49(); q50();
}
// >>> q44
@FunctionalInterface
interface Discount {
double apply(double price);
}
// <<< q44
static void q44() {
Qa.header(44, "Lambdas and functional interfaces");
// >>> q44b
Discount tenOff = price -> price * 0.9;
Predicate<String> isEmpty = String::isEmpty;
Function<String, Integer> length = String::length;
Supplier<String> greeting = () -> "hello";
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
System.out.println(tenOff.apply(200) + " " + isEmpty.test("") + " " + length.apply("lambda")
+ " " + greeting.get() + " " + add.apply(2, 3));
// <<< q44b
}
static void q45() {
Qa.header(45, "Streams: map, filter, collect, laziness");
// >>> q45
List<String> names = List.of("asha", "ravi", "meena", "arjun");
System.out.println(names.stream().filter(n -> n.startsWith("a")).map(String::toUpperCase).collect(Collectors.toList()));
System.out.println(names.stream().collect(Collectors.groupingBy(String::length, Collectors.counting())));
Stream<String> lazy = names.stream().peek(n -> System.out.println("visited " + n));
System.out.println("nothing visited yet: no terminal operation");
System.out.println("first = " + lazy.findFirst().get()); // stops after the first element
Stream<String> used = names.stream();
used.count();
try {
used.count();
} catch (IllegalStateException e) {
System.out.println("reuse -> " + e.getMessage());
}
// <<< q45
}
static String expensive() {
System.out.println("expensive() called");
return "default";
}
static void q46() {
Qa.header(46, "Optional");
// >>> q46
Optional<String> present = Optional.of("value");
System.out.println("orElse : " + present.orElse(expensive())); // argument is evaluated even though unused
System.out.println("orElseGet : " + present.orElseGet(() -> expensive())); // lambda is never run
Optional<String> empty = Optional.empty();
System.out.println(empty.map(String::toUpperCase).orElse("nothing here"));
// <<< q46
}
// >>> q47
record Point(int x, int y) {
Point { // compact constructor: validation
if (x < 0 || y < 0) throw new IllegalArgumentException("negative coordinate");
}
}
// <<< q47
static void q47() {
Qa.header(47, "Records");
// >>> q47b
Point p = new Point(1, 2);
System.out.println(p + " equals " + new Point(1, 2) + ": " + p.equals(new Point(1, 2)) + ", x() = " + p.x());
try {
new Point(-1, 0);
} catch (IllegalArgumentException e) {
System.out.println("rejected: " + e.getMessage());
}
// <<< q47b
}
static void q48() {
Qa.header(48, "var, switch expressions and text blocks");
// >>> q48
var scores = Map.of("asha", 91);
int marks = scores.get("asha");
String grade = switch (marks / 10) {
case 10, 9 -> "A";
case 8 -> "B";
default -> "C";
};
String json = """
{"name": "asha",
"grade": "%s"}
""".formatted(grade);
System.out.print(json);
// <<< q48
}
// >>> q49
interface Walker { default String move() { return "walk"; } }
interface Swimmer { default String move() { return "swim"; } }
static class Duck implements Walker, Swimmer {
@Override public String move() { return Walker.super.move() + " and " + Swimmer.super.move(); }
}
// <<< q49
static void q49() {
Qa.header(49, "Method references and default methods");
// >>> q49b
List<String> items = List.of("b", "a", "c");
items.stream().sorted(String::compareTo).forEach(System.out::print); // static-style and bound references
System.out.println();
System.out.println(new Duck().move());
// <<< q49b
}
static void q50() throws Exception {
Qa.header(50, "Threads: start() vs run(), and virtual threads");
// >>> q50
Runnable task = () -> System.out.println("running on: " + Thread.currentThread().getName());
Thread t = new Thread(task, "worker-1");
t.run(); // plain method call, still on main
t.start(); // new thread
t.join();
Thread v = Thread.ofVirtual().name("virtual-1").start(() ->
System.out.println("virtual: " + Thread.currentThread().isVirtual()));
v.join();
// <<< q50
}
}
@@ -0,0 +1,309 @@
package com.ankurm.interviewlab.fresherqa;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
/** Questions 10-20: the four pillars, constructors, overloading vs overriding, abstract vs interface, immutability. */
public final class OopQa {
private OopQa() {}
public static void main(String[] args) {
run();
}
public static void run() {
q10(); q11(); q12(); q13(); q14(); q15(); q16(); q17(); q18(); q19(); q20();
}
// ---------------------------------------------------------------- Q10
// >>> q10
interface Shape { // abstraction: callers only know "area()"
double area();
}
record Circle(double radius) implements Shape {
public double area() { return Math.PI * radius * radius; }
}
record Rectangle(double w, double h) implements Shape {
public double area() { return w * h; }
}
static class Account {
private double balance; // encapsulation: no outside code can touch this directly
void deposit(double amount) {
if (amount <= 0) throw new IllegalArgumentException("amount must be positive");
balance += amount;
}
double balance() { return balance; }
}
// <<< q10
static void q10() {
Qa.header(10, "The four pillars of OOP");
// >>> q10b
List<Shape> shapes = List.of(new Circle(1), new Rectangle(2, 3));
for (Shape s : shapes) { // polymorphism: one call, different behaviour
System.out.printf("%s area = %.2f%n", s.getClass().getSimpleName(), s.area());
}
Account account = new Account();
account.deposit(500);
try {
account.deposit(-1);
} catch (IllegalArgumentException e) {
System.out.println("rejected: " + e.getMessage() + ", balance still " + account.balance());
}
// <<< q10b
}
// ---------------------------------------------------------------- Q11
// >>> q11
static class Animal {
Animal() { System.out.println("Animal constructor"); }
}
static class Dog extends Animal {
Dog() {
super(); // implicit if you leave it out
System.out.println("Dog constructor");
}
}
static class Puppy extends Animal {
Puppy(String name) {
if (name.isBlank()) throw new IllegalArgumentException("name required"); // before super(): legal since Java 25
super();
System.out.println("Puppy constructor for " + name);
}
}
// <<< q11
static void q11() {
Qa.header(11, "Inheritance and constructor chaining");
// >>> q11b
new Dog();
new Puppy("Bruno");
// <<< q11b
}
// ---------------------------------------------------------------- Q12
// >>> q12
static class Printer {
String show(Object o) { return "show(Object)"; }
String show(String s) { return "show(String)"; }
}
static class FancyPrinter extends Printer {
@Override
String show(Object o) { return "FancyPrinter.show(Object)"; }
}
// <<< q12
static void q12() {
Qa.header(12, "Method overloading vs overriding");
// >>> q12b
Printer p = new FancyPrinter();
Object text = "hello";
System.out.println(p.show(text)); // compile time picks show(Object) from the declared type; run time picks FancyPrinter's override
System.out.println(p.show("hello")); // compile time picks show(String); FancyPrinter never overrode it
System.out.println(p.show((Object) 42)); // same as the first line: overload by declared type, body by real class
// <<< q12b
}
// ---------------------------------------------------------------- Q13
// >>> q13
abstract static class Vehicle { // abstract class: state + constructor + partial code
protected final String name;
Vehicle(String name) { this.name = name; }
abstract int wheels();
String describe() { return name + " has " + wheels() + " wheels"; }
}
interface Electric { // interface: a capability, many allowed
default String charge() { return "charging"; }
static String standard() { return "Type 2"; }
}
static class Scooter extends Vehicle implements Electric {
Scooter() { super("Scooter"); }
int wheels() { return 2; }
}
// <<< q13
static void q13() {
Qa.header(13, "Abstract class vs interface");
// >>> q13b
Scooter s = new Scooter();
System.out.println(s.describe() + ", " + s.charge() + ", plug " + Electric.standard());
// <<< q13b
}
// ---------------------------------------------------------------- Q14
// >>> q14
static class Parent {
String name = "Parent.field";
static String kind() { return "Parent.static"; }
String who() { return "Parent.who()"; }
}
static class Child extends Parent {
String name = "Child.field"; // hides, does not override
static String kind() { return "Child.static"; } // hides, does not override
@Override String who() { return "Child.who()"; }
}
// <<< q14
static void q14() {
Qa.header(14, "Polymorphism: what is and is not dynamic");
// >>> q14b
Parent p = new Child();
System.out.println(p.who() + " | " + p.name + " | " + Parent.kind() + " | " + Child.kind());
// <<< q14b
}
// ---------------------------------------------------------------- Q15
// >>> q15
static class Base {
static String hello() { return "Base.hello"; }
private String secret() { return "Base.secret"; }
final String locked() { return "Base.locked"; }
String callSecret() { return secret(); }
}
static class Derived extends Base {
static String hello() { return "Derived.hello"; } // legal: hides
private String secret() { return "Derived.secret"; } // legal: a new, unrelated method
// final String locked() { ... } // compile error: cannot override final
}
// <<< q15
static void q15() {
Qa.header(15, "Can you override static, private or final methods?");
// >>> q15b
Base b = new Derived();
System.out.println(b.callSecret() + " | " + b.locked());
// <<< q15b
}
// ---------------------------------------------------------------- Q16
// >>> q16
static final class Team { // final class: nobody can subclass and add mutators
private final String name;
private final List<String> members;
Team(String name, List<String> members) {
this.name = name;
this.members = List.copyOf(members); // defensive copy in
}
String name() { return name; }
List<String> members() { return members; } // already unmodifiable, safe to return
}
// <<< q16
static void q16() {
Qa.header(16, "How do you create an immutable class?");
// >>> q16b
List<String> input = new ArrayList<>(List.of("Asha", "Ravi"));
Team team = new Team("Core", input);
input.add("Intruder"); // does not leak into the Team
System.out.println("members: " + team.members());
try {
team.members().add("Hacker");
} catch (UnsupportedOperationException e) {
System.out.println("add blocked: UnsupportedOperationException");
}
// <<< q16b
}
// ---------------------------------------------------------------- Q17
static void q17() {
Qa.header(17, "Composition vs inheritance (is-a vs has-a)");
// >>> q17
Stack<Integer> stack = new Stack<>(); // java.util.Stack EXTENDS Vector, so it inherits all of Vector
stack.push(1);
stack.push(2);
stack.add(0, 99); // legal, and it breaks "last in, first out"
System.out.println("stack = " + stack + ", pop gives " + stack.pop());
// <<< q17
}
// ---------------------------------------------------------------- Q18
// >>> q18
static class Modifiers {
public int a;
protected int b;
int c; // package-private: no keyword at all
private int d;
}
// <<< q18
static void q18() {
Qa.header(18, "Access modifiers");
// >>> q18b
for (Field f : Modifiers.class.getDeclaredFields()) {
String m = Modifier.toString(f.getModifiers());
System.out.println(f.getName() + " -> " + (m.isEmpty() ? "(package-private)" : m));
}
// <<< q18b
}
// ---------------------------------------------------------------- Q19
// >>> q19
static class Point {
final int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
@Override public boolean equals(Object o) {
return o instanceof Point p && p.x == x && p.y == y;
}
// hashCode() deliberately NOT overridden
}
// <<< q19
static void q19() {
Qa.header(19, "Object class methods: toString, equals, hashCode");
// >>> q19b
Object plain = new Object();
System.out.println("default toString looks like ClassName@hex: " + plain.toString().matches("java\\.lang\\.Object@[0-9a-f]+"));
Point p1 = new Point(1, 2), p2 = new Point(1, 2);
System.out.println("p1.equals(p2) = " + p1.equals(p2));
Set<Point> set = new HashSet<>(List.of(p1));
System.out.println("set contains an equal point: " + set.contains(p2));
// <<< q19b
}
// ---------------------------------------------------------------- Q20
// >>> q20
static class Config {
final String env;
final int port;
Config() { this("dev", 8080); } // this(...) chains to another constructor
Config(String env, int port) { this.env = env; this.port = port; }
// The moment you write ANY constructor, the free no-argument one disappears.
// So Config() above had to be written by hand.
}
static class Registry {
private static final Registry INSTANCE = new Registry();
private Registry() {} // private constructor: nobody else can call new
static Registry get() { return INSTANCE; }
}
// <<< q20
static void q20() {
Qa.header(20, "Constructors: default, chained and private");
// >>> q20b
Config c = new Config();
System.out.println("default config: " + c.env + ":" + c.port);
System.out.println("same Registry instance: " + (Registry.get() == Registry.get()));
// <<< q20b
}
}
@@ -0,0 +1,14 @@
package com.ankurm.interviewlab.fresherqa;
/** Tiny helper shared by the six question classes: prints the section header the transcripts use. */
final class Qa {
private Qa() {}
static void header(int n, String title) {
System.out.println("=== Q" + (n < 10 ? "0" : "") + n + " " + title + " ===");
}
static void blank() {
System.out.println();
}
}
@@ -0,0 +1,127 @@
package com.ankurm.interviewlab.fresherqa;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
/** Questions 21-27: equality and the string pool, immutability, StringBuilder, intern, reverse, methods, frequency. */
public final class StringsQa {
private StringsQa() {}
public static void main(String[] args) throws Exception {
run();
}
public static void run() throws Exception {
q21(); q22(); q23(); q24(); q25(); q26(); q27();
}
static void q21() {
Qa.header(21, "== vs equals() on Strings");
// >>> q21
String a = "java";
String b = "java";
String c = new String("java");
System.out.println("a == b -> " + (a == b)); // two literals share one pooled object
System.out.println("a == c -> " + (a == c)); // new always builds a separate object
System.out.println("a.equals(c) -> " + a.equals(c)); // equals compares the characters
// <<< q21
}
static void q22() {
Qa.header(22, "Why is String immutable?");
// >>> q22
String s = "java";
String upper = s.toUpperCase();
System.out.println("s = " + s);
System.out.println("upper = " + upper);
System.out.println("same object returned when nothing changes: " + (s.toLowerCase() == s));
// <<< q22
}
static void q23() throws Exception {
Qa.header(23, "String vs StringBuilder vs StringBuffer");
// >>> q23
StringBuilder sb = new StringBuilder("a");
sb.append("b").append("c").insert(0, "-").reverse();
System.out.println("builder result: " + sb);
boolean buf = Modifier.isSynchronized(StringBuffer.class.getMethod("append", String.class).getModifiers());
boolean bld = Modifier.isSynchronized(StringBuilder.class.getMethod("append", String.class).getModifiers());
System.out.println("append is synchronized: StringBuffer=" + buf + ", StringBuilder=" + bld);
// <<< q23
}
static void q24() {
Qa.header(24, "The string pool, compile-time constants and intern()");
// >>> q24
String lo = "lo";
final String finalLo = "lo";
System.out.println("\"hel\" + \"lo\" == \"hello\" -> " + ("hel" + "lo" == "hello"));
System.out.println("\"hel\" + lo == \"hello\" -> " + ("hel" + lo == "hello"));
System.out.println("\"hel\" + finalLo == \"hello\" -> " + ("hel" + finalLo == "hello"));
System.out.println("(\"hel\" + lo).intern() == \"hello\" -> " + (("hel" + lo).intern() == "hello"));
// <<< q24
}
// >>> q25
static String reverse(String s) {
return new StringBuilder(s).reverse().toString();
}
static boolean isPalindrome(String s) {
String cleaned = s.toLowerCase().replaceAll("[^a-z0-9]", "");
return cleaned.equals(reverse(cleaned));
}
// <<< q25
static void q25() {
Qa.header(25, "Reverse a string and check for a palindrome");
// >>> q25b
System.out.println(reverse("interview"));
System.out.println(isPalindrome("A man, a plan, a canal: Panama"));
System.out.println(isPalindrome("hello"));
// <<< q25b
}
static void q26() {
Qa.header(26, "Useful String methods and the split() surprises");
// >>> q26
String spaced = "\u2003 hi \u2003"; // an em space on each side
System.out.println("trim().length() = " + spaced.trim().length());
System.out.println("strip().length() = " + spaced.strip().length());
System.out.println("\" \".isBlank() = " + " ".isBlank() + ", \"ab\".repeat(3) = " + "ab".repeat(3));
System.out.println("\"a,b,,\".split(\",\").length = " + "a,b,,".split(",").length);
System.out.println("\"a,b,,\".split(\",\", -1).length = " + "a,b,,".split(",", -1).length);
System.out.println("String.join: " + String.join("-", "2026", "11", "11"));
// <<< q26
}
// >>> q27
static Map<Character, Integer> frequency(String s) {
Map<Character, Integer> counts = new LinkedHashMap<>(); // keeps first-seen order
for (char ch : s.toCharArray()) {
counts.merge(ch, 1, Integer::sum);
}
return counts;
}
static boolean areAnagrams(String x, String y) {
char[] a = x.toCharArray(), b = y.toCharArray();
Arrays.sort(a);
Arrays.sort(b);
return Arrays.equals(a, b);
}
// <<< q27
static void q27() {
Qa.header(27, "Count characters, find the first non-repeating one, check anagrams");
// >>> q27b
Map<Character, Integer> counts = frequency("swiss");
System.out.println("frequency: " + counts);
char first = counts.entrySet().stream().filter(e -> e.getValue() == 1).findFirst().get().getKey();
System.out.println("first non-repeating: " + first);
System.out.println("listen/silent anagrams: " + areAnagrams("listen", "silent"));
// <<< q27b
}
}
@@ -0,0 +1,94 @@
package com.ankurm.interviewlab.fresherqa;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Callable;
import org.junit.jupiter.api.Test;
/** Runs each question class, asserts the claims the article makes, and writes output/NN-*.txt. */
class TranscriptsTest {
private static String capture(String file, Callable<Void> body) throws Exception {
PrintStream original = System.out;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
System.setOut(new PrintStream(buffer, true, StandardCharsets.UTF_8));
try {
body.call();
} finally {
System.setOut(original);
}
String text = buffer.toString(StandardCharsets.UTF_8);
Files.createDirectories(Path.of("output"));
Files.writeString(Path.of("output", file), text);
return text;
}
private static void has(String text, String... expected) {
for (String e : expected) assertTrue(text.contains(e), "missing: " + e + "\n" + text);
}
@Test
void basics() throws Exception {
String t = capture("01-basics.txt", () -> { BasicsQa.run(); return null; });
has(t, "magic = CAFEBABE", "class file major version = 69", "running on Java 25",
"(byte) 130 = -126", "Integer.MAX_VALUE + 1 = -2147483648", "0.1 + 0.2 = 0.30000000000000004",
"127 == 127 -> true", "128 == 128 -> false", "Long 127 equals Integer 127 -> false",
"after reassign: original", "after mutate: original + mutated",
"Object.finalize forRemoval = true", "StackOverflowError after many frames: true");
assertTrue(t.indexOf("static block") < t.indexOf("instance block"));
assertTrue(t.indexOf("instance block") < t.indexOf("constructor #1"));
}
@Test
void oop() throws Exception {
String t = capture("02-oop.txt", () -> { OopQa.run(); return null; });
has(t, "rejected: amount must be positive, balance still 500.0",
"Animal constructor\nDog constructor", "Puppy constructor for Bruno",
"FancyPrinter.show(Object)\nshow(String)\nFancyPrinter.show(Object)",
"Child.who() | Parent.field | Parent.static | Child.static",
"Base.secret | Base.locked", "members: [Asha, Ravi]", "add blocked: UnsupportedOperationException",
"stack = [99, 1, 2], pop gives 2", "p1.equals(p2) = true", "set contains an equal point: false",
"same Registry instance: true", "d -> private", "c -> (package-private)");
}
@Test
void strings() throws Exception {
String t = capture("03-strings.txt", () -> { StringsQa.run(); return null; });
has(t, "a == b -> true", "a == c -> false", "a.equals(c) -> true",
"append is synchronized: StringBuffer=true, StringBuilder=false",
"trim().length() = 6", "strip().length() = 2",
"\"a,b,,\".split(\",\").length = 2", "\"a,b,,\".split(\",\", -1).length = 4",
"first non-repeating: w", "listen/silent anagrams: true");
}
@Test
void collections() throws Exception {
String t = capture("04-collections.txt", () -> { CollectionsQa.run(); return null; });
has(t, "Aa: hashCode=2112", "BB: hashCode=2112", "both survive a collision: first, second, size 2",
"HashMap: null key accepted", "Hashtable: null key throws NullPointerException",
"TreeMap: null key throws NullPointerException",
"LinkedHashSet [pear, apple, mango, banana, cherry]", "TreeSet [apple, banana, cherry, mango, pear]",
"removing 2 inside for-each -> ConcurrentModificationException",
"get with the mutated key: null", "get with a fresh \"A1\" key: null", "size is still 1",
"view sees the change: [a, b, c]", "copy does not: [a, b]");
}
@Test
void exceptions() throws Exception {
String t = capture("05-exceptions.txt", () -> { ExceptionsQa.run(); return null; });
has(t, "primitiveSnapshot = 10", "finallyOverrides = 7", "withdrawal refused <- cause: balance 100 < 500",
"close second\nclose first", "suppressed: close failed: second");
}
@Test
void modern() throws Exception {
String t = capture("06-modern-java.txt", () -> { ModernJavaQa.run(); return null; });
has(t, "180.0 true 6 hello 5", "[ASHA, ARJUN]", "reuse -> stream has already been operated upon or closed",
"running on: main", "running on: worker-1", "virtual: true", "walk and swim");
}
}