void main() just workvoid main() just workpublic static void main(String[] args) first, then falls back to void main()final — no inheritance, can't implement interfaces, can't extend anything (except Object)this works// Minimal runnable Java file — no class, no psvm
String greeting = "Hello, World!";
void main() {
System.out.println(greeting);
}_ for declared-but-never-used variables — signals intentional ignore// Old: forced to name x, y, z even if only x needed
if (obj instanceof Location(int x, int y, int z)) { ... }
// New: underscore for ignored components
if (obj instanceof Location(int x, _, _)) {
System.out.println("X is " + x);
}
// Also valid in catch
try { ... } catch (Exception _) { ... }// Basic email regex
email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$");| Part | Meaning |
|---|---|
^ | Start of string |
[A-Za-z0-9+_.-]+ | Local part — allowed chars, 1 or more |
@ | Mandatory separator |
[A-Za-z0-9.-]+ | Domain — allowed chars, 1 or more |
$ | End of string |
ClassName::methodName or instance::methodName| Kind | Syntax | Example |
|---|---|---|
| Static method | Class::staticMethod | System.out::println |
| Instance (specific obj) | obj::method | myComparator::compare |
| Instance (arbitrary obj) | Class::instanceMethod | Integer::compareTo |
| Constructor | Class::new | TreeSet::new |
// Static — forEach list.forEach(System.out::println); // Specific instance list.stream().sorted(customComparator::compare); // Arbitrary instance list.stream().sorted(Integer::compareTo); // Constructor ref Supplier<TreeSet> s = TreeSet::new;
@FunctionalInterface — compiler enforces exactly one SAMprivate (utility), static (common utility), or default (backward compat) methods| Name | About | Method |
|---|---|---|
| Predicate | Takes one input & gives a Boolean output | test |
| Supplier | Takes no args, gives one output | get |
| Consumer | Takes input and performs action, returns nothing | accept |
| Function | Takes one input & gives one output | apply |
| BiFunction | Operates on two distinct types (T, U → R) | apply |
| BinaryOperator | Operates on a single type (T, T → T) | apply |
x())toString(), equals(), hashCode()public record User(String name, int age) {}final — cannot be extendedstatic, so can't access enclosing method varsequals, hashCode, toStringfinal, no setters — but mutable fields (e.g. Map) can still be mutated externallythis.field = field at endpublic record User(String username) {
public User { // compact — no () needed
if (username == null)
throw new IllegalArgumentException("null!");
// this.username = username ← auto-added
}
}public sealed class Shape
permits Circle, Rectangle, Square {}permits clause can be omitted| Modifier | Effect |
|---|---|
final | Cannot be extended further |
sealed | Can only extend to its own permits list |
non-sealed | Open to any subclass — sealed can't prevent this |
sealed interface Inter permits A, B, C {}record can be named in permits (records are implicitly final)final, it and a disjoint interface are incompatible → cast fails at compile timeClass::permittedSubclasses() → ClassDesc[]Class::isSealed() → boolean// Old way
if (s instanceof Rectangle) {
Rectangle r = (Rectangle) s;
return 2 * r.length() + 2 * r.width();
}
// New — binding var in instanceof
if (s instanceof Rectangle r) {
return 2 * r.length() + 2 * r.width();
}return switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
case null -> "It is null";
default -> obj.toString();
};switch (obj) {
case String s when s.length() == 1
-> System.out.println("Short: " + s);
case String s -> System.out.println(s);
default -> System.out.println("Not a string");
}// Verbose if-else chain
if (s instanceof Rectangle r)
return 2*r.length() + 2*r.width();
else if (s instanceof Circle c)
return 2*c.radius()*Math.PI;
else throw new IllegalArgumentException(...);
// Clean switch expression
return switch (s) {
case Rectangle r -> 2*r.length() + 2*r.width();
case Circle c -> 2*c.radius()*Math.PI;
default -> throw new IllegalArgumentException(...);
};default to cover the restMatchException thrownnull case can only be combined with default: case null, default -> ...NullPointerException as usualswitch (obj) {
case String s -> println("String: " + s);
case null, default -> println("null or other");
}T type · E element · K key · V value · N numberList<String> is NOT a subtype of List<Object>new T[n] illegal. Can make array of wildcard.// Generic class
class Test<T, I> { T obj; I obj2; }
// Generic method
class Abc { <T> void func(T elem) { ... } }<T extends Number> — T must be Number or subclass (resolved at compile time)<T extends Number & Comparable<T>>T super Number — type erasure resolves to upper bound at compile time; upper bound would be Object (pointless)| Variance | Meaning | Java |
|---|---|---|
| Invariant | No subtype relation | Plain generics List<T> |
| Covariant | Subtype accepted | Arrays, ? extends T |
| Contravariant | Supertype accepted | ? super T |
List<? extends T>List<? super T>| Wildcard | Syntax | Use when |
|---|---|---|
| Unbounded | List<?> | Type irrelevant to logic |
| Upper bounded | List<? extends N> | Read-only, any subtype of N |
| Lower bounded | List<? super I> | Write ops, any supertype of I |
? as a method return type — unknown type is unusable by callerT, multiple params can each be a different unknown type with wildcardsObject (or upper bound) in bytecodeinstanceof List<String> — at runtime it's just ListList<String> vs List<Integer> — same signature after erasure → compile errorList list = new ArrayList()) disable compile-time checks — avoid| Use | When |
|---|---|
<T> generic | Need type consistency, adding to collection, specific return type |
? wildcard | Only reading, type doesn't need to be named/reused |
method(List<String>) · Child: method(List<Integer>)method(List) → compile errorSerializable (marker interface — no methods)private static final long serialVersionUID = 1L; — used to detect class version mismatch on deserializationObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("data.bin"));
oos.writeObject(myObj);serialVersionUID, field metadata + values → binarystatic fields not serialized (belong to class, not instance)ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("data.bin"));
MyClass obj = (MyClass) ois.readObject();transient fields restored to default values (0, null, false)transient | Field skipped during serialization |
static | Not serialized — gets assigned value on class load |
| UUID mismatch | Deserialization fails with InvalidClassException |
| No UUID declared | Auto-generated from class structure — any change breaks deserialization |
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // write normal fields
// write custom data...
}
private void readObject(ObjectInputStream in) throws ... {
in.defaultReadObject();
// restore custom data...
}// Empty optional
Optional<String> empty = Optional.empty();
// From a non-null value (throws NPE if null)
Optional<String> present = Optional.of("hello");
// From a possibly-null value — safe
Optional<String> maybe = Optional.ofNullable(getValue());// get() — throws NoSuchElementException if empty; avoid raw get()
String val = opt.get();
// orElse — always evaluates the fallback expression
String val = opt.orElse("default");
// orElseGet — lazy; fallback only called if empty (prefer this)
String val = opt.orElseGet(() -> computeDefault());
// orElseThrow — throws if empty; no-arg = NoSuchElementException
String val = opt.orElseThrow();
String val = opt.orElseThrow(() -> new IllegalStateException("missing"));
// or — returns another Optional if empty (Java 9+)
Optional<String> result = opt.or(() -> Optional.of("fallback"));// isPresent / isEmpty (Java 11+)
if (opt.isPresent()) { ... }
if (opt.isEmpty()) { ... }
// ifPresent — runs action only if value exists
opt.ifPresent(System.out::println);
// ifPresentOrElse (Java 9+) — branch on presence
opt.ifPresentOrElse(
val -> System.out.println("Got: " + val),
() -> System.out.println("Empty")
);// map — transforms value if present, returns Optional of result
Optional<Integer> len = opt.map(String::length);
// flatMap — use when mapper itself returns an Optional (avoids Optional<Optional<T>>)
Optional<String> city = userOpt.flatMap(u -> u.getAddress())
.flatMap(a -> a.getCity());
// filter — keeps value only if predicate matches, else empty
Optional<String> long_ = opt.filter(s -> s.length() > 5);| Method | Returns | Notes |
|---|---|---|
of(v) | Optional<T> | NPE if v is null |
ofNullable(v) | Optional<T> | Safe — empty if null |
empty() | Optional<T> | Singleton empty |
get() | T | Throws if empty — avoid |
orElse(v) | T | Always evaluates v |
orElseGet(s) | T | Lazy — prefer over orElse |
orElseThrow() | T | Throws if empty |
or(s) | Optional<T> | Java 9+ — fallback Optional |
map(f) | Optional<R> | Transform if present |
flatMap(f) | Optional<R> | f returns Optional — no nesting |
filter(p) | Optional<T> | Empty if predicate false |
isPresent() | boolean | True if value present |
isEmpty() | boolean | Java 11+ — inverse of isPresent |
ifPresent(c) | void | Run consumer if present |
ifPresentOrElse(c,r) | void | Java 9+ — branch on presence |
stream() | Stream<T> | Java 9+ — 0 or 1 element |
// stream() (Java 9+) — 0 or 1 element stream; great for flatMap
List<String> names = optionals.stream()
.flatMap(Optional::stream) // unwrap all present values
.toList();// ❌ Antipattern — just use if-null check instead
if (opt.isPresent()) {
return opt.get();
} else {
return "default";
}
// ✅ Use orElse / orElseGet
return opt.orElse("default");
// ❌ Never use Optional as a field or method parameter
// — it's designed as a return type only
class User { Optional<String> nickname; } // bad
// ❌ Don't wrap primitives — use OptionalInt, OptionalLong, OptionalDouble
Optional<Integer> count = ...; // allocates — use OptionalInt insteadOptionalInt, OptionalLong, OptionalDouble for primitives — avoids boxing overhead.RandomGenerator interface + impls (SplittableRandom etc.)static String formatter(Object obj) {
return switch (obj) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case null -> "null";
default -> "Unknown";
};
}void main() Preview_ PreviewSequencedCollection / SequencedMap interfaces added — uniform API for ordered collections (addFirst, getLast, reversed())| Feature | Version |
|---|---|
| Lambdas, Streams, Optional | Java 8 |
| var (local type inference) | Java 10 |
| Records, Sealed (preview) | Java 14/15 |
| Pattern instanceof | Java 16 |
| Records, Sealed (final) | Java 16/17 |
| Switch pattern match (final) | Java 21 |
| Virtual threads (final) | Java 21 |
| SequencedCollection | Java 21 |