Java essentials: 50 cards on OOP, collections, generics and streams
Core Java with short snippets: equals vs ==, records, sealed types, collections, generics, exceptions, streams, lambdas and JVM basics.
Practice now
Study without an account
Scheduled with the default Askesis timings. Progress is saved in this browser.
All 50 cards
- 1Java’s eight primitive types
byte,short,int,long,float,double,charandboolean; everything else, includingStringand arrays, is a reference type - 2What does this print?java
System.out.println(7 / 2); System.out.println(7 / 2.0);3, then3.5: dividing twoints is integer division, which truncates toward zero - 3
==vs.equals()on strings==checks whether two references point to the same object;.equals()compares the characters. Use.equals()for content"a" == "a"can be true because literals are interned, which hides the bug until a string comes from user input. - 4What does this print?java
Integer a = 127, b = 127; Integer c = 128, d = 128; System.out.println(a == b); System.out.println(c == d);true, thenfalse: autoboxing reuses cachedIntegerobjects from -128 to 127, but larger values are separate objects. Compare boxed numbers with.equals() - 5What does this print?java
String s = "hello"; s.toUpperCase(); System.out.println(s);hello: strings are immutable, sotoUpperCase()returns a new string, which is thrown away hereWrites = s.toUpperCase();to keep the result. - 6Why use
StringBuilderto build a string in a loop?Eachs += xcopies the whole string into a new object, which is quadratic over a loop;StringBuilderappends into a growable bufferjavavar sb = new StringBuilder(); for (String w : words) sb.append(w).append(' '); String result = sb.toString(); - 7What does
vardo in Java?Infers a local variable’s type from its initializer at compile time (Java 10+); the variable is still statically typedOnly for local variables with an initializer (and loop variables), not fields, parameters or return types. - 8What is
Integer.MAX_VALUE + 1?-2147483648(Integer.MIN_VALUE):intarithmetic overflows silently and wraps aroundMath.addExactand friends throwArithmeticExceptionon overflow instead. - 9Is Java pass-by-value or pass-by-reference?Always pass-by-value. For objects the value copied is the reference, so a method can mutate the object, but reassigning the parameter doesn’t affect the caller
- 10A
switchexpression with arrow labelsjavaString size = switch (n) { case 0 -> "none"; case 1, 2 -> "few"; default -> "many"; };Java 14+. Arrow cases never fall through, and a switch expression must cover every possible value. - 11A multi-line string literaljava
String json = """ { "name": "Ada" } """;Text blocks (Java 15+) strip the common indentation; the position of the closing"""counts too. - 12Java’s four access levels
private(the class only), package-private (no modifier: the same package),protected(the package plus subclasses) andpublic(everywhere) - 13What does
staticmean on a field or method?It belongs to the class, not to an instance: there is one shared copy, accessed asClassName.member. Static methods have nothis - 14
finalon a variable, a method and a classAfinalvariable can’t be reassigned, afinalmethod can’t be overridden, and afinalclass can’t be subclassedAfinal List<String>can still be modified withadd; only the reference is fixed. - 15Abstract class vs interfaceA class can extend only one class, which may have fields and constructors; it can implement many interfaces, which hold no instance state but can have
default,staticandprivatemethods - 16Overloading vs overridingOverloading: same name, different parameter lists, picked at compile time. Overriding: a subclass redefines an inherited method with the same signature, picked at runtime from the object’s actual class
- 17What does this print?java
class Animal { String sound() { return "..."; } } class Dog extends Animal { String sound() { return "Woof"; } } Animal a = new Dog(); System.out.println(a.sound());Woof: instance methods are dispatched on the object’s runtime class, not the variable’s declared typeAnnotate overriding methods with@Overrideso the compiler catches signature typos. - 18If you override
equals, what else must you override?hashCode: objects that are equal must return the same hash code, orHashMapandHashSetwon’t find themRecords generate both methods for you. - 19What does
record Point(int x, int y) {}give you?An immutable data class (Java 16+): private final fields, a constructor, accessorsx()andy(), andequals,hashCodeandtoStringAccessors arep.x(), notp.getX(). Records are implicitly final and can’t extend another class. - 20Validate a record’s fieldsjava
record Range(int lo, int hi) { Range { if (lo > hi) throw new IllegalArgumentException("lo > hi"); } }A compact constructor has no parameter list; the fields are assigned automatically after its body runs. - 21What does
sealeddo?Limits which classes may extend or implement a type (Java 17+), so the compiler knows every subtypejavasealed interface Shape permits Circle, Square {} record Circle(double r) implements Shape {} record Square(double side) implements Shape {} - 22Check a type and cast it in one stepjava
if (obj instanceof String s && !s.isBlank()) { System.out.println(s.length()); }Pattern matching forinstanceof, Java 16+. - 23Switch over a sealed type without a
defaultjavadouble area = switch (shape) { case Circle c -> Math.PI * c.r() * c.r(); case Square s -> s.side() * s.side(); };Pattern matching forswitch(Java 21+). BecauseShapeis sealed, the compiler can check that the cases are exhaustive. - 24Destructure a record in a patternjava
if (obj instanceof Point(int x, int y)) { System.out.println(x + y); }Record patterns, Java 21+. They work inswitchcases too. - 25The core collection interfaces and their usual implementations
List(ordered, allows duplicates):ArrayList.Set(no duplicates):HashSet.Map(keys to values):HashMap.Deque(queue or stack):ArrayDeque - 26
ArrayListvsLinkedListArrayListhas O(1) indexed access and fast appends;LinkedListhas O(n) indexed access and poor memory locality, soArrayList(orArrayDequefor queues) is almost always the better choice - 27
HashMapvsLinkedHashMapvsTreeMapIteration order: unspecified, insertion order, and sorted by key. The hash maps are O(1) on average;TreeMapis O(log n) - 28What happens here?java
List<String> xs = List.of("a", "b"); xs.add("c");AnUnsupportedOperationException:List.of(Java 9+) returns an unmodifiable listIt also rejectsnullelements. Usenew ArrayList<>(List.of("a", "b"))for a mutable copy. - 29What goes wrong when you remove items from a list inside a for-each loop?It usually throws
ConcurrentModificationException. Uselist.removeIf(x -> …), or an explicitIteratorand itsremove() - 30Count words in a
Map<String, Integer>javacounts.merge(word, 1, Integer::sum);Stores 1 for a new key; otherwise adds 1 to the existing count. - 31Add to a
Map<String, List<String>>, creating each list on first usejavabyCity.computeIfAbsent(city, k -> new ArrayList<>()).add(name); - 32Sort people by age, then by namejava
people.sort(Comparator.comparing(Person::age) .thenComparing(Person::name));Add.reversed()to flip an order. - 33The
Arrays.asList(array)gotchaThe list is fixed-size and backed by the array:setwrites through to the array, butaddandremovethrowUnsupportedOperationException - 34Why doesn’t
List<int>compile?Type arguments must be reference types. UseList<Integer>; autoboxing converts betweenintandIntegerUnboxing anullIntegerinto anintthrowsNullPointerException. - 35What is type erasure?Generic type arguments exist only at compile time; at runtime
List<String>andList<Integer>are both plainList. Sonew T(),T.classandx instanceof List<String>aren’t allowed - 36Is a
List<Integer>aList<Number>?No. Generics are invariant; otherwise you could add aDoubleto a list of integers. AcceptList<? extends Number>to take bothArrays are covariant instead, soObject[] a = new String[1]; a[0] = 1;compiles and throwsArrayStoreException. - 37
? extends Tvs? super T“Producer extends, consumer super” (PECS): you can readTs out of aList<? extends T>and addTs to aList<? super T>javastatic void addOnes(List<? super Integer> xs) { xs.add(1); // works for List<Integer>, List<Number>, List<Object> } - 38Checked vs unchecked exceptionsChecked exceptions (subclasses of
Exceptionother thanRuntimeException) must be caught or declared withthrows; unchecked ones (RuntimeException,Errorand their subclasses) needn’t beIOExceptionis checked;NullPointerExceptionandIllegalArgumentExceptionare unchecked. - 39Read a file and make sure it gets closedjava
try (var reader = Files.newBufferedReader(path)) { return reader.readLine(); }try-with-resources closes anyAutoCloseablewhen the block exits, even when it throws. - 40What does
f()return?javastatic int f() { try { return 1; } finally { return 2; } }2:finallyruns even afterreturn, and areturninside it replaces the earlier oneNever return fromfinally: it also silently discards exceptions. - 41Handle two exception types in one
catchjavatry { load(); } catch (IOException | SQLException e) { log.error("load failed", e); } - 42Get the sorted names of all adults with a streamjava
List<String> names = people.stream() .filter(p -> p.age() >= 18) .map(Person::name) .sorted() .toList();Stream.toList()(Java 16+) returns an unmodifiable list; before that, usecollect(Collectors.toList()). - 43When do stream operations actually run?Lazily: intermediate operations like
filterandmapdo nothing until a terminal operation such astoList,forEachorcountrunsA stream can be consumed only once; reusing it throwsIllegalStateException. - 44How should you use the
Optionalreturned byfindFirst()?Unwrap it withorElse(default),orElseThrow(),map(…)orifPresent(…)instead of callingget()blindlyjavaString name = users.stream() .filter(User::isAdmin) .map(User::name) .findFirst() .orElse("nobody"); - 45Group people by cityjava
Map<String, List<Person>> byCity = people.stream() .collect(Collectors.groupingBy(Person::city));groupingBy(Person::city, Collectors.counting())counts per city instead. - 46What is a functional interface?An interface with a single abstract method, which a lambda or method reference can implement:
Function<T, R>,Predicate<T>,Supplier<T>,Consumer<T>,Runnable… - 47Why doesn’t this compile?java
int count = 0; list.forEach(x -> count++);Lambdas can only capture local variables that are effectively final, i.e. never reassignedUselist.size()or a stream’scount()instead. - 48What happens between
javacand running a Java program?javaccompiles.javasource into platform-independent bytecode (.classfiles); the JVM loads it, interprets it, and JIT-compiles hot code to native machine codeSince Java 11,java Main.javacompiles and runs a single source file in one step. - 49Stack vs heap in the JVMEach thread’s stack holds method frames with local variables and references; objects live on the shared heap, where the garbage collector frees them once they’re unreachableDeep recursion throws
StackOverflowError; running out of heap throwsOutOfMemoryError. - 50What are virtual threads?Lightweight threads scheduled by the JVM rather than the OS (Java 21+), so you can afford one thread per task for blocking I/O, even millions of themjava
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { urls.forEach(url -> executor.submit(() -> fetch(url))); } // close() waits for the tasks
Frequently asked questions
Which Java version do the cards use?
Modern Java: everything works on the current LTS releases (21 and 25). Newer features are marked with the version that introduced them, such as records (16), sealed classes (17) and virtual threads (21).
Is this deck useful for Java interviews?
Yes. It covers the classic questions (equals and hashCode, checked vs unchecked exceptions, ArrayList vs LinkedList, pass-by-value) alongside modern Java.
Does it cover Spring or other frameworks?
No. It sticks to the language, the standard library and the JVM, which every Java framework builds on.
More in Programming
JavaScript
Master the JavaScript every developer uses daily: scope, closures, equality, array methods, promises, async/await and the event loop.
50 cardsAdvanced JS
Fifty advanced JavaScript cards: event-loop ordering puzzles, generators and async iteration, this binding, Proxy and Reflect, modules, AbortController and coercion edge cases.
50 cardsTypeScript
Learn the TypeScript you use every day: narrowing, generics, keyof, mapped and conditional types, utility types, satisfies and strict mode, with code on every card.
50 cardsPython
Learn idiomatic Python fast: comprehensions, f-strings, args and kwargs, generators, decorators, context managers and the standard library.
50 cardsGit & terminal
The Git commands and shell skills developers use every day: branching, rebasing, undoing mistakes, pipes, redirects, permissions and processes.
50 cardsC#
C# and .NET fundamentals with short snippets: value vs reference types, properties, records, nullable reference types, LINQ, async/await and DI.
50 cardsKotlin
Kotlin fundamentals with short snippets: null safety, val vs var, data and sealed classes, extension functions, scope functions and coroutines.
50 cardsSwift
Swift fundamentals with short snippets: optionals, structs vs classes, protocols, enums with associated values, closures, ARC, async/await and SwiftUI.
50 cardsFlutter
Flutter and Dart basics: null safety, futures and streams, stateless vs stateful widgets, setState, hot reload, keys, layout and state management.
50 cardsPHP
Modern PHP 8 with short snippets: strict types, arrays, match, nullsafe and named arguments, enums, readonly, Composer, PDO and password_hash.
50 cardsRuby
Ruby fundamentals with short snippets: blocks, procs and lambdas, symbols, Enumerable, mixins, truthiness, method_missing, gems and Bundler.
50 cardsGo
Go (Golang) fundamentals with short, idiomatic snippets: slices vs arrays, maps, defer, error wrapping, interfaces, goroutines, channels, select and context.
50 cardsRust
Learn the Rust that the compiler keeps asking about: ownership, borrowing, lifetimes, Option and Result, traits, closures, smart pointers and async.
50 cardsC++
Modern C++ in short snippets: references vs pointers, RAII, smart pointers, move semantics, STL containers and algorithms, const, templates and UB.
50 cardsHaskell
Haskell fundamentals with short code: types and type classes, pattern matching, laziness, Maybe and Either, folds, Functor, Applicative and Monad.
50 cardsElixir
Elixir fundamentals with short snippets: immutability, pattern matching, the pipe operator, Enum vs Stream, processes, GenServer, supervisors and mix.
50 cardsx86-64 assembly
x86-64 assembly in Intel syntax: registers and sub-registers, flags, mov and lea, jumps, the stack frame, the System V calling convention and Linux syscalls.
50 cardsRegex
Learn regular expressions for good: anchors, classes, greedy vs lazy quantifiers, groups, lookarounds, flags, replacements and the backtracking trap.
50 cards