By the end, you will be able to:
java.net
and java.net.http
.extends
; specialize behavior with @Override
. Don’t overuse — prefer composition by default.Encapsulation guards state and funnels changes through business rules. Prefer throwing exceptions over printing errors.
public final class Person {
private String name;
private int age;
public Person(String name, int age) {
setName(name);
setAge(age);
}
public String getName() { return name; }
public void setName(String name) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("name must be non-blank");
}
this.name = name;
}
public int getAge() { return age; }
public void setAge(int age) {
if (age < 0 || age > 149) {
throw new IllegalArgumentException("age must be 0..149");
}
this.age = age;
}
}
Tip: When objects should never change after construction, make fields private final
and drop setters. Consider a record for simple data carriers:
public record Point2D(int x, int y) { }
class Vehicle {
protected int speed; // demo only; prefer private + getters/setters
public void accelerate(int delta) { speed += delta; }
public String info() { return "Vehicle@" + speed + "km/h"; }
}
class Car extends Vehicle {
private int gear = 1;
@Override
public void accelerate(int delta) {
super.accelerate(delta);
if (speed > 0 && gear < 6) gear = Math.min(6, 1 + speed / 20);
}
@Override
public String info() { return "Car@" + speed + "km/h, gear " + gear; }
}
public class Demo {
public static void main(String[] args) {
Vehicle v = new Car(); // polymorphism: reference type = Vehicle
v.accelerate(35);
System.out.println(v.info()); // calls Car.info()
}
}
Favor composition when behavior varies independently or “is-a” doesn’t hold. The class has a collaborator instead of is one.
interface Engine { int torque(); }
final class ElectricMotor implements Engine { public int torque() { return 320; } }
final class TurboDiesel implements Engine { public int torque() { return 420; } }
final class Truck {
private final Engine engine; // composition
Truck(Engine engine) { this.engine = engine; }
int pullingPower() { return engine.torque(); }
}
IllegalArgumentException
for bad inputs; IllegalStateException
for misuse of object state.try-with-resources
for I/O.import java.nio.file.*;
import java.io.*;
public class ReaderExample {
public static String readFirstLine(Path path) {
try (BufferedReader br = Files.newBufferedReader(path)) {
return br.readLine();
} catch (IOException ioe) {
throw new UncheckedIOException("Failed to read " + path, ioe);
}
}
}
We’ll use the Concurrency API and the modern HTTP client.
import java.net.http.*;
import java.net.URI;
import java.util.concurrent.*;
public class FetchTitle {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
CompletableFuture<String> title =
client.sendAsync(
HttpRequest.newBuilder(URI.create("https://example.com")).GET().build(),
HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenApply(body -> body.substring(0, Math.min(80, body.length()))); // demo
System.out.println(title.get(3, TimeUnit.SECONDS));
}
}
private
members are not visible to subclasses; access happens via public/protected methods.@Override
required for overriding checks; method signatures must match except for covariant return types.super(...)
.