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:
@@ -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 |
|
| [`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 |
|
| [`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 |
|
| [`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
|
## `collections` module
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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]
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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>
|
||||||
Executable
+20
@@ -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"
|
||||||
Executable
+8
@@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class Base {
|
||||||
|
final String locked() { return "Base.locked"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Derived extends Base {
|
||||||
|
String locked() { return "Derived.locked"; }
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user