Modern Java Types
Records
Concise Data Classes
You need a Point class with x and y. Writing constructor, getters, equals,
hashCode, and toString is tedious. Records do all this in one line:
record Point(int x, int y) {}. Immutable data carriers with no boilerplate.
Basic record
Define a data class in one line.
// Basic record definition and usage
// Concept: record - immutable data carrier
// Define a record
record Point(int x, int y) {
}
public class BasicRecord {
public static void main(String[] args) {
// Create record instance
int pointX = 10;
Point p1 = new Point(pointX, 20);
// Access fields via accessor methods
System.out.println("x: " + p1.x());
System.out.println("y: " + p1.y());
// Automatic toString()
System.out.println("Point: " + p1);
// Create another instance
Point p2 = new Point(10, 20);
Point p3 = new Point(15, 25);
// Automatic equals()
System.out.println("\np1 equals p2: " + p1.equals(p2));
System.out.println("p1 equals p3: " + p1.equals(p3));
// Use == for reference comparison
System.out.println("p1 == p2: " + (p1 == p2));
// More record examples
record Person(String name, int age) {}
Person alice = new Person("Alice", 30);
System.out.println("\nPerson: " + alice);
System.out.println("Name: " + alice.name());
System.out.println("Age: " + alice.age());
}
}
// Basic record definition and usage
// Concept: record - immutable data carrier
// Define a record
record Point(int x, int y) {
}
public class BasicRecord {
public static void main(String[] args) {
// Create record instance
int pointX = 5;
Point p1 = new Point(pointX, 20);
// Access fields via accessor methods
System.out.println("x: " + p1.x());
System.out.println("y: " + p1.y());
// Automatic toString()
System.out.println("Point: " + p1);
// Create another instance
Point p2 = new Point(10, 20);
Point p3 = new Point(15, 25);
// Automatic equals()
System.out.println("\np1 equals p2: " + p1.equals(p2));
System.out.println("p1 equals p3: " + p1.equals(p3));
// Use == for reference comparison
System.out.println("p1 == p2: " + (p1 == p2));
// More record examples
record Person(String name, int age) {}
Person alice = new Person("Alice", 30);
System.out.println("\nPerson: " + alice);
System.out.println("Name: " + alice.name());
System.out.println("Age: " + alice.age());
}
}
// Basic record definition and usage
// Concept: record - immutable data carrier
// Define a record
record Point(int x, int y) {
}
public class BasicRecord {
public static void main(String[] args) {
// Create record instance
int pointX = 100;
Point p1 = new Point(pointX, 20);
// Access fields via accessor methods
System.out.println("x: " + p1.x());
System.out.println("y: " + p1.y());
// Automatic toString()
System.out.println("Point: " + p1);
// Create another instance
Point p2 = new Point(10, 20);
Point p3 = new Point(15, 25);
// Automatic equals()
System.out.println("\np1 equals p2: " + p1.equals(p2));
System.out.println("p1 equals p3: " + p1.equals(p3));
// Use == for reference comparison
System.out.println("p1 == p2: " + (p1 == p2));
// More record examples
record Person(String name, int age) {}
Person alice = new Person("Alice", 30);
System.out.println("\nPerson: " + alice);
System.out.println("Name: " + alice.name());
System.out.println("Age: " + alice.age());
}
}
pointX ← 10, p1 ← Point[x=10, y=20], p2 ← Point[x=10, y=20], p3 ← Point[x=15, y=25]
8public class BasicRecord {9 public static void main(String[] args) {10 // Create record instance11 int pointX→ 10 = 10;12 //@pointX=10, 5, 10013 Point p1→ Point[x=10, y=20] = new Point(pointX, 20);1415 // Access fields via accessor methods16 System.out.println("x: " + p1.x());17 System.out.println("y: " + p1.y());18 19 //@help h120 // record Point(int x, int y) creates:21 // - private final int x, y fields22 // - public int x(), int y() accessors23 // - constructor Point(int x, int y)24 // - equals(), hashCode(), toString()25 //@end26 27 // Automatic toString()28 System.out.println("Point: " + p1Point[x=10, y=20]);29 30 // Create another instance31 Point p2→ Point[x=10, y=20] = new Point(10, 20);32 Point p3→ Point[x=15, y=25] = new Point(15, 25);33 34 // Automatic equals()35 System.out.println("\np1 equals p2: " + p1.equals(p2Point[x=10, y=20]));36 System.out.println("p1 equals p3: " + p1.equals(p3Point[x=15, y=25]));37 38 // Use == for reference comparison39 System.out.println("p1 == p2: " + (p1Point[x=10, y=20] == p2Point[x=10, y=20]));40 41 // More record examples42 record Person(String name, int age) {}43 44 Person alice = new Person("Alice", 30);45 System.out.println("\nPerson: " + alicePerson[name=Alice, age=30]);46 System.out.println("Name: " + alice.name());47 System.out.println("Age: " + alice.age());outputx: 10 y: 20 Point: Point[x=10, y=20] p1 equals p2: true p1 equals p3: false p1 == p2: false Person: Person[name=Alice, age=30] Name: Alice Age: 30
pointX ← 5, p1 ← Point[x=5, y=20], p2 ← Point[x=10, y=20], p3 ← Point[x=15, y=25]
8public class BasicRecord {9 public static void main(String[] args) {10 // Create record instance11 int pointX→ 5 = 5;12 Point p1→ Point[x=5, y=20] = new Point(pointX, 20);1314 // Access fields via accessor methods15 System.out.println("x: " + p1.x());16 System.out.println("y: " + p1.y());17 18 19 // Automatic toString()20 System.out.println("Point: " + p1Point[x=5, y=20]);21 22 // Create another instance23 Point p2→ Point[x=10, y=20] = new Point(10, 20);24 Point p3→ Point[x=15, y=25] = new Point(15, 25);25 26 // Automatic equals()27 System.out.println("\np1 equals p2: " + p1.equals(p2Point[x=10, y=20]));28 System.out.println("p1 equals p3: " + p1.equals(p3Point[x=15, y=25]));29 30 // Use == for reference comparison31 System.out.println("p1 == p2: " + (p1Point[x=5, y=20] == p2Point[x=10, y=20]));32 33 // More record examples34 record Person(String name, int age) {}35 36 Person alice = new Person("Alice", 30);37 System.out.println("\nPerson: " + alicePerson[name=Alice, age=30]);38 System.out.println("Name: " + alice.name());39 System.out.println("Age: " + alice.age());outputx: 5 y: 20 Point: Point[x=5, y=20] p1 equals p2: false p1 equals p3: false p1 == p2: false Person: Person[name=Alice, age=30] Name: Alice Age: 30
pointX ← 100, p1 ← Point[x=100, y=20], p2 ← Point[x=10, y=20]
8public class BasicRecord {9 public static void main(String[] args) {10 // Create record instance11 int pointX→ 100 = 100;12 Point p1→ Point[x=100, y=20] = new Point(pointX, 20);1314 // Access fields via accessor methods15 System.out.println("x: " + p1.x());16 System.out.println("y: " + p1.y());17 18 19 // Automatic toString()20 System.out.println("Point: " + p1Point[x=100, y=20]);21 22 // Create another instance23 Point p2→ Point[x=10, y=20] = new Point(10, 20);24 Point p3→ Point[x=15, y=25] = new Point(15, 25);25 26 // Automatic equals()27 System.out.println("\np1 equals p2: " + p1.equals(p2Point[x=10, y=20]));28 System.out.println("p1 equals p3: " + p1.equals(p3Point[x=15, y=25]));29 30 // Use == for reference comparison31 System.out.println("p1 == p2: " + (p1Point[x=100, y=20] == p2Point[x=10, y=20]));32 33 // More record examples34 record Person(String name, int age) {}35 36 Person alice = new Person("Alice", 30);37 System.out.println("\nPerson: " + alicePerson[name=Alice, age=30]);38 System.out.println("Name: " + alice.name());39 System.out.println("Age: " + alice.age());outputx: 100 y: 20 Point: Point[x=100, y=20] p1 equals p2: false p1 equals p3: false p1 == p2: false Person: Person[name=Alice, age=30] Name: Alice Age: 30
record Name(Type field1, Type field2) {} - complete data class.
Automatic methods
What records give you for free.
// Automatic methods in records
// Concept: automatic methods - equals, hashCode, toString
record Book(String title, String author, int year) {
}
public class AutomaticMethods {
public static void main(String[] args) {
// Create book instances
Book b1 = new Book("1984", "Orwell", 1949);
Book b2 = new Book("1984", "Orwell", 1949);
Book b3 = new Book("Dune", "Herbert", 1965);
// toString() - readable representation
System.out.println("Book 1: " + b1);
System.out.println("Book 2: " + b2);
System.out.println("Book 3: " + b3);
// equals() - value-based equality
System.out.println("\nb1.equals(b2): " + b1.equals(b2));
System.out.println("b1.equals(b3): " + b1.equals(b3));
// hashCode() - consistent with equals
System.out.println("\nHash codes:");
System.out.println("b1: " + b1.hashCode());
System.out.println("b2: " + b2.hashCode());
System.out.println("b3: " + b3.hashCode());
System.out.println("\nSame hash? " + (b1.hashCode() == b2.hashCode()));
// Use in collections
java.util.Set<Book> books = new java.util.HashSet<>();
books.add(b1);
books.add(b2); // Won't add (equals b1)
books.add(b3);
System.out.println("\nUnique books in set: " + books.size());
// Use as map key
java.util.Map<Book, Integer> stock = new java.util.HashMap<>();
stock.put(b1, 10);
stock.put(b2, 5); // Updates b1's value (same key)
stock.put(b3, 7);
System.out.println("\nStock levels:");
for (var entry : stock.entrySet()) {
System.out.println(" " + entry.getKey().title() + ": " + entry.getValue());
}
// Compare different types
record Movie(String title, String director, int year) {}
Movie m1 = new Movie("1984", "Radford", 1984);
// Different types, even with same values
System.out.println("\nBook equals Movie: " + b1.equals(m1));
}
}
b1 ← Book[title=1984, author=Orwell, year=1949], b2 ← Book[title=1984, author=Orwell, year=1949]
7public class AutomaticMethods {8 public static void main(String[] args) {9 // Create book instances10 Book b1→ Book[title=1984, author=Orwell, year=1949] = new Book("1984", "Orwell", 1949);11 Book b2→ Book[title=1984, author=Orwell, year=1949] = new Book("1984", "Orwell", 1949);12 Book b3→ Book[title=Dune, author=Herbert, year=1965] = new Book("Dune", "Herbert", 1965);13 14 // toString() - readable representation15 System.out.println("Book 1: " + b1Book[title=1984, author=Orwell, year=1949]);16 System.out.println("Book 2: " + b2Book[title=1984, author=Orwell, year=1949]);17 System.out.println("Book 3: " + b3Book[title=Dune, author=Herbert, year=1965]);18 19 // equals() - value-based equality20 System.out.println("\nb1.equals(b2): " + b1.equals(b2Book[title=1984, author=Orwell, year=1949]));21 System.out.println("b1.equals(b3): " + b1.equals(b3Book[title=Dune, author=Herbert, year=1965]));22 23 //@help h124 // Records compare by value, not reference25 // All fields must match for equality26 // toString() shows all field values27 //@end28 29 // hashCode() - consistent with equals30 System.out.println("\nHash codes:");31 System.out.println("b1: " + b1.hashCode());32 System.out.println("b2: " + b2.hashCode());33 System.out.println("b3: " + b3.hashCode());34 35 System.out.println("\nSame hash? " + (b1.hashCode() == b2.hashCode()));36 37 // Use in collections38 java.util.Set<Book> books→ [] = new java.util.HashSet<>();39 books.add(b1Book[title=1984, author=Orwell, year=1949]);40 books.add(b2Book[title=1984, author=Orwell, year=1949]); // Won't add (equals b1)41 books.add(b3Book[title=Dune, author=Herbert, year=1965]);42 43 System.out.println("\nUnique books in set: " + books.size());44 45 // Use as map key46 java.util.Map<Book, Integer> stock→ {} = new java.util.HashMap<>();47 stock.put(b1Book[title=1984, author=Orwell, year=1949], 10);48 stock.put(b2Book[title=1984, author=Orwell, year=1949], 5); // Updates b1's value (same key)49 stock.put(b3Book[title=Dune, author=Herbert, year=1965], 7);50 51 System.out.println("\nStock levels:");52 for (var entry : stock.entrySet()) {outputBook 1: Book[title=1984, author=Orwell, year=1949] Book 2: Book[title=1984, author=Orwell, year=1949] Book 3: Book[title=Dune, author=Herbert, year=1965] b1.equals(b2): true b1.equals(b3): false Hash codes: b1: 1932274320 b2: 1932274320 b3: 1492444379 Same hash? true Unique books in set: 2 Stock levels:for (var entry : stock.entrySet())
pass 1 of 251System.out.println("\nStock levels:");52for (var entry : stock.entrySet()) {53 System.out.println(" " + entry.getKey().title() + ": " + entry.getValue());54}output 1984: 5for (var entry : stock.entrySet())
pass 2 of 251System.out.println("\nStock levels:");52for (var entry : stock.entrySet()) {53 System.out.println(" " + entry.getKey().title() + ": " + entry.getValue());54}output Dune: 7m1 ← Movie[title=1984, director=Radford, year=1984]
59 Movie m1→ Movie[title=1984, director=Radford, year=1984] = new Movie("1984", "Radford", 1984);60 61 // Different types, even with same values62 System.out.println("\nBook equals Movie: " + b1.equals(m1Movie[title=1984, director=Radford, year=1984]));63}output Book equals Movie: false
Accessor methods: point.x(). Plus equals, hashCode, toString.
Compact constructor
Validate fields in a compact constructor.
// Compact constructor for validation
// Concept: compact constructor - validate record creation
record Temperature(double celsius) {
// Compact constructor for validation
public Temperature {
if (celsius < -273.15) {
throw new IllegalArgumentException(
"Temperature below absolute zero: " + celsius);
}
}
// Add computed methods
public double fahrenheit() {
return celsius * 9.0 / 5.0 + 32;
}
public double kelvin() {
return celsius + 273.15;
}
}
record Range(int min, int max) {
// Compact constructor with normalization
public Range {
if (min > max) {
// Swap if needed
int temp = min;
min = max;
max = temp;
}
}
public boolean contains(int value) {
return value >= min && value <= max;
}
public int size() {
return max - min + 1;
}
}
public class CompactConstructor {
public static void main(String[] args) {
// Create temperature with validation
Temperature t1 = new Temperature(25.0);
System.out.println("Temperature: " + t1.celsius() + "°C");
System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");
System.out.println("Kelvin: " + t1.kelvin() + "K");
// Validation prevents invalid state
try {
Temperature invalid = new Temperature(-300);
System.out.println("Created: " + invalid);
} catch (IllegalArgumentException e) {
System.out.println("\nError: " + e.getMessage());
}
// Range with auto-correction
Range r1 = new Range(1, 10);
Range r2 = new Range(10, 1); // Will be swapped
System.out.println("\nr1: " + r1);
System.out.println("r2: " + r2);
System.out.println("r1 equals r2: " + r1.equals(r2));
// Use range methods
Range range = new Range(5, 15);
System.out.println("\nRange: " + range);
System.out.println("Size: " + range.size());
System.out.println("Contains 10: " + range.contains(10));
System.out.println("Contains 20: " + range.contains(20));
// Multiple validations
record Email(String address) {
public Email {
if (address == null || address.isEmpty()) {
throw new IllegalArgumentException("Email cannot be empty");
}
if (!address.contains("@")) {
throw new IllegalArgumentException("Invalid email format");
}
// Normalize to lowercase
address = address.toLowerCase();
}
}
Email e1 = new Email("Alice@Example.COM");
Email e2 = new Email("alice@example.com");
System.out.println("\ne1: " + e1.address());
System.out.println("e2: " + e2.address());
System.out.println("Equal: " + e1.equals(e2));
}
}
// Compact constructor for validation
// Concept: compact constructor - validate record creation
record Temperature(double celsius) {
// Compact constructor for validation
public Temperature {
if (celsius < -273.15) {
throw new IllegalArgumentException(
"Temperature below absolute zero: " + celsius);
}
}
// Add computed methods
public double fahrenheit() {
return celsius * 9.0 / 5.0 + 32;
}
public double kelvin() {
return celsius + 273.15;
}
}
record Range(int min, int max) {
// Compact constructor with normalization
public Range {
if (min > max) {
// Swap if needed
int temp = min;
min = max;
max = temp;
}
}
public boolean contains(int value) {
return value >= min && value <= max;
}
public int size() {
return max - min + 1;
}
}
public class CompactConstructor {
public static void main(String[] args) {
// Create temperature with validation
Temperature t1 = new Temperature(0);
System.out.println("Temperature: " + t1.celsius() + "°C");
System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");
System.out.println("Kelvin: " + t1.kelvin() + "K");
// Validation prevents invalid state
try {
Temperature invalid = new Temperature(-300);
System.out.println("Created: " + invalid);
} catch (IllegalArgumentException e) {
System.out.println("\nError: " + e.getMessage());
}
// Range with auto-correction
Range r1 = new Range(1, 10);
Range r2 = new Range(10, 1); // Will be swapped
System.out.println("\nr1: " + r1);
System.out.println("r2: " + r2);
System.out.println("r1 equals r2: " + r1.equals(r2));
// Use range methods
Range range = new Range(5, 15);
System.out.println("\nRange: " + range);
System.out.println("Size: " + range.size());
System.out.println("Contains 10: " + range.contains(10));
System.out.println("Contains 20: " + range.contains(20));
// Multiple validations
record Email(String address) {
public Email {
if (address == null || address.isEmpty()) {
throw new IllegalArgumentException("Email cannot be empty");
}
if (!address.contains("@")) {
throw new IllegalArgumentException("Invalid email format");
}
// Normalize to lowercase
address = address.toLowerCase();
}
}
Email e1 = new Email("Alice@Example.COM");
Email e2 = new Email("alice@example.com");
System.out.println("\ne1: " + e1.address());
System.out.println("e2: " + e2.address());
System.out.println("Equal: " + e1.equals(e2));
}
}
// Compact constructor for validation
// Concept: compact constructor - validate record creation
record Temperature(double celsius) {
// Compact constructor for validation
public Temperature {
if (celsius < -273.15) {
throw new IllegalArgumentException(
"Temperature below absolute zero: " + celsius);
}
}
// Add computed methods
public double fahrenheit() {
return celsius * 9.0 / 5.0 + 32;
}
public double kelvin() {
return celsius + 273.15;
}
}
record Range(int min, int max) {
// Compact constructor with normalization
public Range {
if (min > max) {
// Swap if needed
int temp = min;
min = max;
max = temp;
}
}
public boolean contains(int value) {
return value >= min && value <= max;
}
public int size() {
return max - min + 1;
}
}
public class CompactConstructor {
public static void main(String[] args) {
// Create temperature with validation
Temperature t1 = new Temperature(100);
System.out.println("Temperature: " + t1.celsius() + "°C");
System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");
System.out.println("Kelvin: " + t1.kelvin() + "K");
// Validation prevents invalid state
try {
Temperature invalid = new Temperature(-300);
System.out.println("Created: " + invalid);
} catch (IllegalArgumentException e) {
System.out.println("\nError: " + e.getMessage());
}
// Range with auto-correction
Range r1 = new Range(1, 10);
Range r2 = new Range(10, 1); // Will be swapped
System.out.println("\nr1: " + r1);
System.out.println("r2: " + r2);
System.out.println("r1 equals r2: " + r1.equals(r2));
// Use range methods
Range range = new Range(5, 15);
System.out.println("\nRange: " + range);
System.out.println("Size: " + range.size());
System.out.println("Contains 10: " + range.contains(10));
System.out.println("Contains 20: " + range.contains(20));
// Multiple validations
record Email(String address) {
public Email {
if (address == null || address.isEmpty()) {
throw new IllegalArgumentException("Email cannot be empty");
}
if (!address.contains("@")) {
throw new IllegalArgumentException("Invalid email format");
}
// Normalize to lowercase
address = address.toLowerCase();
}
}
Email e1 = new Email("Alice@Example.COM");
Email e2 = new Email("alice@example.com");
System.out.println("\ne1: " + e1.address());
System.out.println("e2: " + e2.address());
System.out.println("Equal: " + e1.equals(e2));
}
}
public static void main(String[] args)
43public class CompactConstructor {44 public static void main(String[] args) {45 // Create temperature with validation46 Temperature t1 = new Temperature(25.0);47 //@t1=new Temperature(25.0), new Temperature(0), new Temperature(100)t1 ← Temperature[celsius=25.0]
45// Create temperature with validation46Temperature t1→ Temperature[celsius=25.0] = new Temperature(25.0);47//@t1=new Temperature(25.0), new Temperature(0), new Temperature(100)48System.out.println("Temperature: " + t1.celsius() + "°C");49System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");50System.out.println("Kelvin: " + t1.kelvin() + "K");outputTemperature: 25.0°Cpublic double fahrenheit()
13// Add computed methods14public double fahrenheit() {15 return celsius25.0 * 9.0 / 5.0 + 32;16}System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");
48System.out.println("Temperature: " + t1.celsius() + "°C");49System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");50System.out.println("Kelvin: " + t1.kelvin() + "K");outputFahrenheit: 77.0°Fpublic double kelvin()
18public double kelvin() {19 return celsius25.0 + 273.15;20}System.out.println("Kelvin: " + t1.kelvin() + "K");
49System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");50System.out.println("Kelvin: " + t1.kelvin() + "K");outputKelvin: 298.15Kif (celsius < -273.15)
6public Temperature {7 if (celsius-300.0 < -273.15) {8 throw new IllegalArgumentException(9 "Temperature below absolute zero: " + celsius);10 }catch (IllegalArgumentException e)
62 System.out.println("Created: " + invalid);63} catch (IllegalArgumentException ejava.lang.IllegalArgumentException: Temperature below absolute zero: -300.0) {64 System.out.println("\nError: " + e.getMessage());65}output Error: Temperature below absolute zero: -300.0Range r1 = new Range(1, 10);
67// Range with auto-correction68Range r1 = new Range(1, 10);69Range r2 = new Range(10, 1); // Will be swappedpublic Range
pass 1 of 324// Compact constructor with normalization25public Range {26 if (min > max) {All 3 passes — pass 1 is the card above pass tempminmax1 — — — 2 10 10 → 1 1 → 10 3 — — — r1 ← Range[min=1, max=10]
67// Range with auto-correction68Range r1→ Range[min=1, max=10] = new Range(1, 10);69Range r2 = new Range(10, 1); // Will be swappedtemp ← 10, min ← 1, max ← 10
25public Range {26 if (min10 > max1) {27 // Swap if needed28 int temp→ 10 = min;29 min→ 1 = max1;30 max→ 10 = temp10;31 }r2 ← Range[min=1, max=10]
68Range r1 = new Range(1, 10);69Range r2→ Range[min=1, max=10] = new Range(10, 1); // Will be swapped7071System.out.println("\nr1: " + r1Range[min=1, max=10]);72System.out.println("r2: " + r2Range[min=1, max=10]);73System.out.println("r1 equals r2: " + r1.equals(r2Range[min=1, max=10]));7475// Use range methods76Range range = new Range(5, 15);output r1: Range[min=1, max=10] r2: Range[min=1, max=10] r1 equals r2: truerange ← Range[min=5, max=15]
75// Use range methods76Range range→ Range[min=5, max=15] = new Range(5, 15);7778System.out.println("\nRange: " + rangeRange[min=5, max=15]);79System.out.println("Size: " + range.size());80System.out.println("Contains 10: " + range.contains(10));output Range: Range[min=5, max=15]public int size()
38public int size() {39 return max15 - min5 + 1;40}System.out.println("Size: " + range.size());
78System.out.println("\nRange: " + range);79System.out.println("Size: " + range.size());80System.out.println("Contains 10: " + range.contains(10));81System.out.println("Contains 20: " + range.contains(20));outputSize: 11public boolean contains(int value)
pass 1 of 234public boolean contains(int value10) {35 return value10 >= min5 && value <= max15;36}System.out.println("Contains 10: " + range.contains(10));
79System.out.println("Size: " + range.size());80System.out.println("Contains 10: " + range.contains(10));81System.out.println("Contains 20: " + range.contains(20));outputContains 10: truepublic boolean contains(int value)
pass 2 of 234public boolean contains(int value20) {35 return value20 >= min5 && value <= max15;36}System.out.println("Contains 20: " + range.contains(20));
80System.out.println("Contains 10: " + range.contains(10));81System.out.println("Contains 20: " + range.contains(20));8283// Multiple validations84record Email(String address) {85 public Email {86 if (address == null || address.isEmpty()) {87 throw new IllegalArgumentException("Email cannot be empty");88 }89 if (!address.contains("@")) {90 throw new IllegalArgumentException("Invalid email format");91 }92 // Normalize to lowercase93 address = address.toLowerCase();94 }95}9697Email e1 = new Email("Alice@Example.COM");98Email e2 = new Email("alice@example.com");outputContains 20: falseaddress ← alice@example.com
pass 1 of 284record Email(String address) {85 public Email {86 if (address == null || address.isEmpty()) {87 throw new IllegalArgumentException("Email cannot be empty");88 }89 if (!address.contains("@")) {90 throw new IllegalArgumentException("Invalid email format");91 }92 // Normalize to lowercase93 address→ alice@example.com = address.toLowerCase();94 }e1 ← Email[address=alice@example.com]
97Email e1→ Email[address=alice@example.com] = new Email("Alice@Example.COM");98Email e2 = new Email("alice@example.com");address ← alice@example.com
pass 2 of 284record Email(String address) {85 public Email {86 if (address == null || address.isEmpty()) {87 throw new IllegalArgumentException("Email cannot be empty");88 }89 if (!address.contains("@")) {90 throw new IllegalArgumentException("Invalid email format");91 }92 // Normalize to lowercase93 address→ alice@example.com = address.toLowerCase();94 }e2 ← Email[address=alice@example.com]
97Email e1 = new Email("Alice@Example.COM");98Email e2→ Email[address=alice@example.com] = new Email("alice@example.com");99100System.out.println("\ne1: " + e1.address());101System.out.println("e2: " + e2.address());102System.out.println("Equal: " + e1.equals(e2Email[address=alice@example.com]));output e1: alice@example.com e2: alice@example.com Equal: true
public static void main(String[] args)
43public class CompactConstructor {44 public static void main(String[] args) {45 // Create temperature with validation46 Temperature t1 = new Temperature(0);47 System.out.println("Temperature: " + t1.celsius() + "°C");t1 ← Temperature[celsius=0.0]
45// Create temperature with validation46Temperature t1→ Temperature[celsius=0.0] = new Temperature(0);47System.out.println("Temperature: " + t1.celsius() + "°C");48System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");49System.out.println("Kelvin: " + t1.kelvin() + "K");outputTemperature: 0.0°Cpublic double fahrenheit()
13// Add computed methods14public double fahrenheit() {15 return celsius0.0 * 9.0 / 5.0 + 32;16}System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");
47System.out.println("Temperature: " + t1.celsius() + "°C");48System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");49System.out.println("Kelvin: " + t1.kelvin() + "K");outputFahrenheit: 32.0°Fpublic double kelvin()
18public double kelvin() {19 return celsius0.0 + 273.15;20}System.out.println("Kelvin: " + t1.kelvin() + "K");
48System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");49System.out.println("Kelvin: " + t1.kelvin() + "K");outputKelvin: 273.15Kif (celsius < -273.15)
6public Temperature {7 if (celsius-300.0 < -273.15) {8 throw new IllegalArgumentException(9 "Temperature below absolute zero: " + celsius);10 }catch (IllegalArgumentException e)
55 System.out.println("Created: " + invalid);56} catch (IllegalArgumentException ejava.lang.IllegalArgumentException: Temperature below absolute zero: -300.0) {57 System.out.println("\nError: " + e.getMessage());58}output Error: Temperature below absolute zero: -300.0Range r1 = new Range(1, 10);
60// Range with auto-correction61Range r1 = new Range(1, 10);62Range r2 = new Range(10, 1); // Will be swappedpublic Range
pass 1 of 324// Compact constructor with normalization25public Range {26 if (min > max) {All 3 passes — pass 1 is the card above pass tempminmax1 — — — 2 10 10 → 1 1 → 10 3 — — — r1 ← Range[min=1, max=10]
60// Range with auto-correction61Range r1→ Range[min=1, max=10] = new Range(1, 10);62Range r2 = new Range(10, 1); // Will be swappedtemp ← 10, min ← 1, max ← 10
25public Range {26 if (min10 > max1) {27 // Swap if needed28 int temp→ 10 = min;29 min→ 1 = max1;30 max→ 10 = temp10;31 }r2 ← Range[min=1, max=10]
61Range r1 = new Range(1, 10);62Range r2→ Range[min=1, max=10] = new Range(10, 1); // Will be swapped6364System.out.println("\nr1: " + r1Range[min=1, max=10]);65System.out.println("r2: " + r2Range[min=1, max=10]);66System.out.println("r1 equals r2: " + r1.equals(r2Range[min=1, max=10]));6768// Use range methods69Range range = new Range(5, 15);output r1: Range[min=1, max=10] r2: Range[min=1, max=10] r1 equals r2: truerange ← Range[min=5, max=15]
68// Use range methods69Range range→ Range[min=5, max=15] = new Range(5, 15);7071System.out.println("\nRange: " + rangeRange[min=5, max=15]);72System.out.println("Size: " + range.size());73System.out.println("Contains 10: " + range.contains(10));output Range: Range[min=5, max=15]public int size()
38public int size() {39 return max15 - min5 + 1;40}System.out.println("Size: " + range.size());
71System.out.println("\nRange: " + range);72System.out.println("Size: " + range.size());73System.out.println("Contains 10: " + range.contains(10));74System.out.println("Contains 20: " + range.contains(20));outputSize: 11public boolean contains(int value)
pass 1 of 234public boolean contains(int value10) {35 return value10 >= min5 && value <= max15;36}System.out.println("Contains 10: " + range.contains(10));
72System.out.println("Size: " + range.size());73System.out.println("Contains 10: " + range.contains(10));74System.out.println("Contains 20: " + range.contains(20));outputContains 10: truepublic boolean contains(int value)
pass 2 of 234public boolean contains(int value20) {35 return value20 >= min5 && value <= max15;36}System.out.println("Contains 20: " + range.contains(20));
73System.out.println("Contains 10: " + range.contains(10));74System.out.println("Contains 20: " + range.contains(20));7576// Multiple validations77record Email(String address) {78 public Email {79 if (address == null || address.isEmpty()) {80 throw new IllegalArgumentException("Email cannot be empty");81 }82 if (!address.contains("@")) {83 throw new IllegalArgumentException("Invalid email format");84 }85 // Normalize to lowercase86 address = address.toLowerCase();87 }88}8990Email e1 = new Email("Alice@Example.COM");91Email e2 = new Email("alice@example.com");outputContains 20: falseaddress ← alice@example.com
pass 1 of 277record Email(String address) {78 public Email {79 if (address == null || address.isEmpty()) {80 throw new IllegalArgumentException("Email cannot be empty");81 }82 if (!address.contains("@")) {83 throw new IllegalArgumentException("Invalid email format");84 }85 // Normalize to lowercase86 address→ alice@example.com = address.toLowerCase();87 }e1 ← Email[address=alice@example.com]
90Email e1→ Email[address=alice@example.com] = new Email("Alice@Example.COM");91Email e2 = new Email("alice@example.com");address ← alice@example.com
pass 2 of 277record Email(String address) {78 public Email {79 if (address == null || address.isEmpty()) {80 throw new IllegalArgumentException("Email cannot be empty");81 }82 if (!address.contains("@")) {83 throw new IllegalArgumentException("Invalid email format");84 }85 // Normalize to lowercase86 address→ alice@example.com = address.toLowerCase();87 }e2 ← Email[address=alice@example.com]
90Email e1 = new Email("Alice@Example.COM");91Email e2→ Email[address=alice@example.com] = new Email("alice@example.com");9293System.out.println("\ne1: " + e1.address());94System.out.println("e2: " + e2.address());95System.out.println("Equal: " + e1.equals(e2Email[address=alice@example.com]));output e1: alice@example.com e2: alice@example.com Equal: true
public static void main(String[] args)
43public class CompactConstructor {44 public static void main(String[] args) {45 // Create temperature with validation46 Temperature t1 = new Temperature(100);47 System.out.println("Temperature: " + t1.celsius() + "°C");t1 ← Temperature[celsius=100.0]
45// Create temperature with validation46Temperature t1→ Temperature[celsius=100.0] = new Temperature(100);47System.out.println("Temperature: " + t1.celsius() + "°C");48System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");49System.out.println("Kelvin: " + t1.kelvin() + "K");outputTemperature: 100.0°Cpublic double fahrenheit()
13// Add computed methods14public double fahrenheit() {15 return celsius100.0 * 9.0 / 5.0 + 32;16}System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");
47System.out.println("Temperature: " + t1.celsius() + "°C");48System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");49System.out.println("Kelvin: " + t1.kelvin() + "K");outputFahrenheit: 212.0°Fpublic double kelvin()
18public double kelvin() {19 return celsius100.0 + 273.15;20}System.out.println("Kelvin: " + t1.kelvin() + "K");
48System.out.println("Fahrenheit: " + t1.fahrenheit() + "°F");49System.out.println("Kelvin: " + t1.kelvin() + "K");outputKelvin: 373.15Kif (celsius < -273.15)
6public Temperature {7 if (celsius-300.0 < -273.15) {8 throw new IllegalArgumentException(9 "Temperature below absolute zero: " + celsius);10 }catch (IllegalArgumentException e)
55 System.out.println("Created: " + invalid);56} catch (IllegalArgumentException ejava.lang.IllegalArgumentException: Temperature below absolute zero: -300.0) {57 System.out.println("\nError: " + e.getMessage());58}output Error: Temperature below absolute zero: -300.0Range r1 = new Range(1, 10);
60// Range with auto-correction61Range r1 = new Range(1, 10);62Range r2 = new Range(10, 1); // Will be swappedpublic Range
pass 1 of 324// Compact constructor with normalization25public Range {26 if (min > max) {All 3 passes — pass 1 is the card above pass tempminmax1 — — — 2 10 10 → 1 1 → 10 3 — — — r1 ← Range[min=1, max=10]
60// Range with auto-correction61Range r1→ Range[min=1, max=10] = new Range(1, 10);62Range r2 = new Range(10, 1); // Will be swappedtemp ← 10, min ← 1, max ← 10
25public Range {26 if (min10 > max1) {27 // Swap if needed28 int temp→ 10 = min;29 min→ 1 = max1;30 max→ 10 = temp10;31 }r2 ← Range[min=1, max=10]
61Range r1 = new Range(1, 10);62Range r2→ Range[min=1, max=10] = new Range(10, 1); // Will be swapped6364System.out.println("\nr1: " + r1Range[min=1, max=10]);65System.out.println("r2: " + r2Range[min=1, max=10]);66System.out.println("r1 equals r2: " + r1.equals(r2Range[min=1, max=10]));6768// Use range methods69Range range = new Range(5, 15);output r1: Range[min=1, max=10] r2: Range[min=1, max=10] r1 equals r2: truerange ← Range[min=5, max=15]
68// Use range methods69Range range→ Range[min=5, max=15] = new Range(5, 15);7071System.out.println("\nRange: " + rangeRange[min=5, max=15]);72System.out.println("Size: " + range.size());73System.out.println("Contains 10: " + range.contains(10));output Range: Range[min=5, max=15]public int size()
38public int size() {39 return max15 - min5 + 1;40}System.out.println("Size: " + range.size());
71System.out.println("\nRange: " + range);72System.out.println("Size: " + range.size());73System.out.println("Contains 10: " + range.contains(10));74System.out.println("Contains 20: " + range.contains(20));outputSize: 11public boolean contains(int value)
pass 1 of 234public boolean contains(int value10) {35 return value10 >= min5 && value <= max15;36}System.out.println("Contains 10: " + range.contains(10));
72System.out.println("Size: " + range.size());73System.out.println("Contains 10: " + range.contains(10));74System.out.println("Contains 20: " + range.contains(20));outputContains 10: truepublic boolean contains(int value)
pass 2 of 234public boolean contains(int value20) {35 return value20 >= min5 && value <= max15;36}System.out.println("Contains 20: " + range.contains(20));
73System.out.println("Contains 10: " + range.contains(10));74System.out.println("Contains 20: " + range.contains(20));7576// Multiple validations77record Email(String address) {78 public Email {79 if (address == null || address.isEmpty()) {80 throw new IllegalArgumentException("Email cannot be empty");81 }82 if (!address.contains("@")) {83 throw new IllegalArgumentException("Invalid email format");84 }85 // Normalize to lowercase86 address = address.toLowerCase();87 }88}8990Email e1 = new Email("Alice@Example.COM");91Email e2 = new Email("alice@example.com");outputContains 20: falseaddress ← alice@example.com
pass 1 of 277record Email(String address) {78 public Email {79 if (address == null || address.isEmpty()) {80 throw new IllegalArgumentException("Email cannot be empty");81 }82 if (!address.contains("@")) {83 throw new IllegalArgumentException("Invalid email format");84 }85 // Normalize to lowercase86 address→ alice@example.com = address.toLowerCase();87 }e1 ← Email[address=alice@example.com]
90Email e1→ Email[address=alice@example.com] = new Email("Alice@Example.COM");91Email e2 = new Email("alice@example.com");address ← alice@example.com
pass 2 of 277record Email(String address) {78 public Email {79 if (address == null || address.isEmpty()) {80 throw new IllegalArgumentException("Email cannot be empty");81 }82 if (!address.contains("@")) {83 throw new IllegalArgumentException("Invalid email format");84 }85 // Normalize to lowercase86 address→ alice@example.com = address.toLowerCase();87 }e2 ← Email[address=alice@example.com]
90Email e1 = new Email("Alice@Example.COM");91Email e2→ Email[address=alice@example.com] = new Email("alice@example.com");9293System.out.println("\ne1: " + e1.address());94System.out.println("e2: " + e2.address());95System.out.println("Equal: " + e1.equals(e2Email[address=alice@example.com]));output e1: alice@example.com e2: alice@example.com Equal: true
Constructor without parameters - validates/normalizes before assignment.
Custom methods
Add your own methods to records.
// Custom methods in records
// Concept: custom methods - add behavior to records
record Circle(double radius) {
// Add custom methods
public double area() {
return Math.PI * radius * radius;
}
public double circumference() {
return 2 * Math.PI * radius;
}
public double diameter() {
return 2 * radius;
}
// Static factory method
public static Circle fromDiameter(double diameter) {
return new Circle(diameter / 2);
}
}
record Money(double amount, String currency) {
// Methods with logic
public Money add(Money other) {
if (!currency.equals(other.currency)) {
throw new IllegalArgumentException("Currency mismatch");
}
return new Money(amount + other.amount, currency);
}
public Money multiply(double factor) {
return new Money(amount * factor, currency);
}
public String formatted() {
return String.format("%.2f %s", amount, currency);
}
}
public class CustomMethods {
public static void main(String[] args) {
// Use custom methods
Circle c1 = new Circle(5.0);
System.out.println("Circle: " + c1);
System.out.println("Radius: " + c1.radius());
System.out.printf("Area: %.2f%n", c1.area());
System.out.printf("Circumference: %.2f%n", c1.circumference());
System.out.printf("Diameter: %.2f%n", c1.diameter());
// Use static factory
Circle c2 = Circle.fromDiameter(20);
System.out.println("\nFrom diameter 20: " + c2);
System.out.printf("Radius: %.1f%n", c2.radius());
// Money operations
Money price1 = new Money(10.50, "USD");
Money price2 = new Money(5.25, "USD");
System.out.println("\nPrice 1: " + price1.formatted());
System.out.println("Price 2: " + price2.formatted());
Money total = price1.add(price2);
System.out.println("Total: " + total.formatted());
Money doubled = price1.multiply(2);
System.out.println("Doubled: " + doubled.formatted());
// Currency mismatch
try {
Money euros = new Money(10, "EUR");
Money combined = price1.add(euros);
System.out.println("Combined: " + combined);
} catch (IllegalArgumentException e) {
System.out.println("\nError: " + e.getMessage());
}
// Complex record with methods
record Rectangle(double width, double height) {
public double area() {
return width * height;
}
public double perimeter() {
return 2 * (width + height);
}
public boolean isSquare() {
return width == height;
}
public Rectangle scale(double factor) {
return new Rectangle(width * factor, height * factor);
}
}
Rectangle rect = new Rectangle(10, 5);
System.out.println("\nRectangle: " + rect);
System.out.printf("Area: %.1f%n", rect.area());
System.out.printf("Perimeter: %.1f%n", rect.perimeter());
System.out.println("Is square: " + rect.isSquare());
Rectangle scaled = rect.scale(2);
System.out.println("Scaled 2x: " + scaled);
}
}
// Custom methods in records
// Concept: custom methods - add behavior to records
record Circle(double radius) {
// Add custom methods
public double area() {
return Math.PI * radius * radius;
}
public double circumference() {
return 2 * Math.PI * radius;
}
public double diameter() {
return 2 * radius;
}
// Static factory method
public static Circle fromDiameter(double diameter) {
return new Circle(diameter / 2);
}
}
record Money(double amount, String currency) {
// Methods with logic
public Money add(Money other) {
if (!currency.equals(other.currency)) {
throw new IllegalArgumentException("Currency mismatch");
}
return new Money(amount + other.amount, currency);
}
public Money multiply(double factor) {
return new Money(amount * factor, currency);
}
public String formatted() {
return String.format("%.2f %s", amount, currency);
}
}
public class CustomMethods {
public static void main(String[] args) {
// Use custom methods
Circle c1 = new Circle(10);
System.out.println("Circle: " + c1);
System.out.println("Radius: " + c1.radius());
System.out.printf("Area: %.2f%n", c1.area());
System.out.printf("Circumference: %.2f%n", c1.circumference());
System.out.printf("Diameter: %.2f%n", c1.diameter());
// Use static factory
Circle c2 = Circle.fromDiameter(20);
System.out.println("\nFrom diameter 20: " + c2);
System.out.printf("Radius: %.1f%n", c2.radius());
// Money operations
Money price1 = new Money(10.50, "USD");
Money price2 = new Money(5.25, "USD");
System.out.println("\nPrice 1: " + price1.formatted());
System.out.println("Price 2: " + price2.formatted());
Money total = price1.add(price2);
System.out.println("Total: " + total.formatted());
Money doubled = price1.multiply(2);
System.out.println("Doubled: " + doubled.formatted());
// Currency mismatch
try {
Money euros = new Money(10, "EUR");
Money combined = price1.add(euros);
System.out.println("Combined: " + combined);
} catch (IllegalArgumentException e) {
System.out.println("\nError: " + e.getMessage());
}
// Complex record with methods
record Rectangle(double width, double height) {
public double area() {
return width * height;
}
public double perimeter() {
return 2 * (width + height);
}
public boolean isSquare() {
return width == height;
}
public Rectangle scale(double factor) {
return new Rectangle(width * factor, height * factor);
}
}
Rectangle rect = new Rectangle(10, 5);
System.out.println("\nRectangle: " + rect);
System.out.printf("Area: %.1f%n", rect.area());
System.out.printf("Perimeter: %.1f%n", rect.perimeter());
System.out.println("Is square: " + rect.isSquare());
Rectangle scaled = rect.scale(2);
System.out.println("Scaled 2x: " + scaled);
}
}
// Custom methods in records
// Concept: custom methods - add behavior to records
record Circle(double radius) {
// Add custom methods
public double area() {
return Math.PI * radius * radius;
}
public double circumference() {
return 2 * Math.PI * radius;
}
public double diameter() {
return 2 * radius;
}
// Static factory method
public static Circle fromDiameter(double diameter) {
return new Circle(diameter / 2);
}
}
record Money(double amount, String currency) {
// Methods with logic
public Money add(Money other) {
if (!currency.equals(other.currency)) {
throw new IllegalArgumentException("Currency mismatch");
}
return new Money(amount + other.amount, currency);
}
public Money multiply(double factor) {
return new Money(amount * factor, currency);
}
public String formatted() {
return String.format("%.2f %s", amount, currency);
}
}
public class CustomMethods {
public static void main(String[] args) {
// Use custom methods
Circle c1 = new Circle(3.5);
System.out.println("Circle: " + c1);
System.out.println("Radius: " + c1.radius());
System.out.printf("Area: %.2f%n", c1.area());
System.out.printf("Circumference: %.2f%n", c1.circumference());
System.out.printf("Diameter: %.2f%n", c1.diameter());
// Use static factory
Circle c2 = Circle.fromDiameter(20);
System.out.println("\nFrom diameter 20: " + c2);
System.out.printf("Radius: %.1f%n", c2.radius());
// Money operations
Money price1 = new Money(10.50, "USD");
Money price2 = new Money(5.25, "USD");
System.out.println("\nPrice 1: " + price1.formatted());
System.out.println("Price 2: " + price2.formatted());
Money total = price1.add(price2);
System.out.println("Total: " + total.formatted());
Money doubled = price1.multiply(2);
System.out.println("Doubled: " + doubled.formatted());
// Currency mismatch
try {
Money euros = new Money(10, "EUR");
Money combined = price1.add(euros);
System.out.println("Combined: " + combined);
} catch (IllegalArgumentException e) {
System.out.println("\nError: " + e.getMessage());
}
// Complex record with methods
record Rectangle(double width, double height) {
public double area() {
return width * height;
}
public double perimeter() {
return 2 * (width + height);
}
public boolean isSquare() {
return width == height;
}
public Rectangle scale(double factor) {
return new Rectangle(width * factor, height * factor);
}
}
Rectangle rect = new Rectangle(10, 5);
System.out.println("\nRectangle: " + rect);
System.out.printf("Area: %.1f%n", rect.area());
System.out.printf("Perimeter: %.1f%n", rect.perimeter());
System.out.println("Is square: " + rect.isSquare());
Rectangle scaled = rect.scale(2);
System.out.println("Scaled 2x: " + scaled);
}
}
c1 ← Circle[radius=5.0]
42public class CustomMethods {43 public static void main(String[] args) {44 // Use custom methods45 Circle c1→ Circle[radius=5.0] = new Circle(5.0);46 //@c1=new Circle(5.0), new Circle(10), new Circle(3.5)47 48 System.out.println("Circle: " + c1Circle[radius=5.0]);49 System.out.println("Radius: " + c1.radius());50 System.out.printf("Area: %.2f%n", c1.area());51 System.out.printf("Circumference: %.2f%n", c1.circumference());outputCircle: Circle[radius=5.0] Radius: 5.0public double area()
5// Add custom methods6public double area() {7 return Math.PI * radius5.0 * radius;8}System.out.printf("Area: %.2f%n", c1.area());
49System.out.println("Radius: " + c1.radius());50System.out.printf("Area: %.2f%n", c1.area());51System.out.printf("Circumference: %.2f%n", c1.circumference());52System.out.printf("Diameter: %.2f%n", c1.diameter());public double circumference()
10public double circumference() {11 return 2 * Math.PI * radius5.0;12}System.out.printf("Circumference: %.2f%n", c1.circumference());
50System.out.printf("Area: %.2f%n", c1.area());51System.out.printf("Circumference: %.2f%n", c1.circumference());52System.out.printf("Diameter: %.2f%n", c1.diameter());public double diameter()
14public double diameter() {15 return 2 * radius5.0;16}System.out.printf("Diameter: %.2f%n", c1.diameter());
51System.out.printf("Circumference: %.2f%n", c1.circumference());52System.out.printf("Diameter: %.2f%n", c1.diameter());5354//@help h155// Records can have instance and static methods56// Methods can access record components57// Records remain immutable - methods return new instances58//@end5960// Use static factory61Circle c2 = Circle.fromDiameter(20);62System.out.println("\nFrom diameter 20: " + c2);public static Circle fromDiameter(double diameter)
18// Static factory method19public static Circle fromDiameter(double diameter20.0) {20 return new Circle(diameter / 2);21}c2 ← Circle[radius=10.0], price1 ← Money[amount=10.5, currency=USD]
60// Use static factory61Circle c2→ Circle[radius=10.0] = Circle.fromDiameter(20);62System.out.println("\nFrom diameter 20: " + c2Circle[radius=10.0]);63System.out.printf("Radius: %.1f%n", c2.radius());6465// Money operations66Money price1→ Money[amount=10.5, currency=USD] = new Money(10.50, "USD");67Money price2→ Money[amount=5.25, currency=USD] = new Money(5.25, "USD");6869System.out.println("\nPrice 1: " + price1.formatted());70System.out.println("Price 2: " + price2.formatted());output From diameter 20: Circle[radius=10.0]public String formatted()
pass 1 of 437public String formatted() {38 return String.format("%.2f %s", amount10.5, currencyUSD);39}All 4 passes — pass 1 is the card above pass amount1 10.5 2 5.25 3 15.75 4 21.0 System.out.println(" Price 1: " + price1.formatted());
69System.out.println("\nPrice 1: " + price1.formatted());70System.out.println("Price 2: " + price2.formatted());output Price 1: 10.50 USDMoney total = price1.add(price2);
69System.out.println("\nPrice 1: " + price1.formatted());70System.out.println("Price 2: " + price2.formatted());7172Money total = price1.add(price2Money[amount=5.25, currency=USD]);73System.out.println("Total: " + total.formatted());outputPrice 2: 5.25 USDpublic Money add(Money other)
pass 1 of 225// Methods with logic26public Money add(Money otherMoney[amount=5.25, currency=USD]) {27 if (!currency.equals(other.currency)) {28 throw new IllegalArgumentException("Currency mismatch");29 }30 return new Money(amount + other.amount, currency);31}total ← Money[amount=15.75, currency=USD]
72Money total→ Money[amount=15.75, currency=USD] = price1.add(price2Money[amount=5.25, currency=USD]);73System.out.println("Total: " + total.formatted());System.out.println("Total: " + total.formatted());
72Money total = price1.add(price2);73System.out.println("Total: " + total.formatted());7475Money doubled = price1.multiply(2);76System.out.println("Doubled: " + doubled.formatted());outputTotal: 15.75 USDpublic Money multiply(double factor)
33public Money multiply(double factor2.0) {34 return new Money(amount * factor, currency);35}doubled ← Money[amount=21.0, currency=USD]
75Money doubled→ Money[amount=21.0, currency=USD] = price1.multiply(2);76System.out.println("Doubled: " + doubled.formatted());System.out.println("Doubled: " + doubled.formatted());
75Money doubled = price1.multiply(2);76System.out.println("Doubled: " + doubled.formatted());outputDoubled: 21.00 USDeuros ← Money[amount=10.0, currency=EUR]
78// Currency mismatch79try {80 Money euros→ Money[amount=10.0, currency=EUR] = new Money(10, "EUR");81 Money combined = price1.add(eurosMoney[amount=10.0, currency=EUR]);82 System.out.println("Combined: " + combined);public Money add(Money other)
pass 2 of 225// Methods with logic26public Money add(Money otherMoney[amount=10.0, currency=EUR]) {27 if (!currency.equals(other.currency)) {if (!currency.equals(other.currency))
26public Money add(Money other) {27 if (!currency.equals(other.currencyEUR)) {28 throw new IllegalArgumentException("Currency mismatch");29 }catch (IllegalArgumentException e)
82 System.out.println("Combined: " + combined);83} catch (IllegalArgumentException ejava.lang.IllegalArgumentException: Currency mismatch) {84 System.out.println("\nError: " + e.getMessage());85}output Error: Currency mismatchrect ← Rectangle[width=10.0, height=5.0]
106Rectangle rect→ Rectangle[width=10.0, height=5.0] = new Rectangle(10, 5);107108System.out.println("\nRectangle: " + rectRectangle[width=10.0, height=5.0]);109System.out.printf("Area: %.1f%n", rect.area());110System.out.printf("Perimeter: %.1f%n", rect.perimeter());output Rectangle: Rectangle[width=10.0, height=5.0]public double area()
88record Rectangle(double width, double height) {89 public double area() {90 return width10.0 * height5.0;91 }System.out.printf("Area: %.1f%n", rect.area());
108System.out.println("\nRectangle: " + rect);109System.out.printf("Area: %.1f%n", rect.area());110System.out.printf("Perimeter: %.1f%n", rect.perimeter());111System.out.println("Is square: " + rect.isSquare());public double perimeter()
93public double perimeter() {94 return 2 * (width10.0 + height5.0);95}System.out.printf("Perimeter: %.1f%n", rect.perimeter());
109System.out.printf("Area: %.1f%n", rect.area());110System.out.printf("Perimeter: %.1f%n", rect.perimeter());111System.out.println("Is square: " + rect.isSquare());public boolean isSquare()
97public boolean isSquare() {98 return width10.0 == height5.0;99}System.out.println("Is square: " + rect.isSquare());
110System.out.printf("Perimeter: %.1f%n", rect.perimeter());111System.out.println("Is square: " + rect.isSquare());112113Rectangle scaled = rect.scale(2);114System.out.println("Scaled 2x: " + scaled);outputIs square: falsepublic Rectangle scale(double factor)
101public Rectangle scale(double factor2.0) {102 return new Rectangle(width * factor, height * factor);103}scaled ← Rectangle[width=20.0, height=10.0]
113Rectangle scaled→ Rectangle[width=20.0, height=10.0] = rect.scale(2);114System.out.println("Scaled 2x: " + scaledRectangle[width=20.0, height=10.0]);outputScaled 2x: Rectangle[width=20.0, height=10.0]
c1 ← Circle[radius=10.0]
42public class CustomMethods {43 public static void main(String[] args) {44 // Use custom methods45 Circle c1→ Circle[radius=10.0] = new Circle(10);46 47 System.out.println("Circle: " + c1Circle[radius=10.0]);48 System.out.println("Radius: " + c1.radius());49 System.out.printf("Area: %.2f%n", c1.area());50 System.out.printf("Circumference: %.2f%n", c1.circumference());outputCircle: Circle[radius=10.0] Radius: 10.0public double area()
5// Add custom methods6public double area() {7 return Math.PI * radius10.0 * radius;8}System.out.printf("Area: %.2f%n", c1.area());
48System.out.println("Radius: " + c1.radius());49System.out.printf("Area: %.2f%n", c1.area());50System.out.printf("Circumference: %.2f%n", c1.circumference());51System.out.printf("Diameter: %.2f%n", c1.diameter());public double circumference()
10public double circumference() {11 return 2 * Math.PI * radius10.0;12}System.out.printf("Circumference: %.2f%n", c1.circumference());
49System.out.printf("Area: %.2f%n", c1.area());50System.out.printf("Circumference: %.2f%n", c1.circumference());51System.out.printf("Diameter: %.2f%n", c1.diameter());public double diameter()
14public double diameter() {15 return 2 * radius10.0;16}System.out.printf("Diameter: %.2f%n", c1.diameter());
50System.out.printf("Circumference: %.2f%n", c1.circumference());51System.out.printf("Diameter: %.2f%n", c1.diameter());525354// Use static factory55Circle c2 = Circle.fromDiameter(20);56System.out.println("\nFrom diameter 20: " + c2);public static Circle fromDiameter(double diameter)
18// Static factory method19public static Circle fromDiameter(double diameter20.0) {20 return new Circle(diameter / 2);21}c2 ← Circle[radius=10.0], price1 ← Money[amount=10.5, currency=USD]
54// Use static factory55Circle c2→ Circle[radius=10.0] = Circle.fromDiameter(20);56System.out.println("\nFrom diameter 20: " + c2Circle[radius=10.0]);57System.out.printf("Radius: %.1f%n", c2.radius());5859// Money operations60Money price1→ Money[amount=10.5, currency=USD] = new Money(10.50, "USD");61Money price2→ Money[amount=5.25, currency=USD] = new Money(5.25, "USD");6263System.out.println("\nPrice 1: " + price1.formatted());64System.out.println("Price 2: " + price2.formatted());output From diameter 20: Circle[radius=10.0]public String formatted()
pass 1 of 437public String formatted() {38 return String.format("%.2f %s", amount10.5, currencyUSD);39}All 4 passes — pass 1 is the card above pass amount1 10.5 2 5.25 3 15.75 4 21.0 System.out.println(" Price 1: " + price1.formatted());
63System.out.println("\nPrice 1: " + price1.formatted());64System.out.println("Price 2: " + price2.formatted());output Price 1: 10.50 USDMoney total = price1.add(price2);
63System.out.println("\nPrice 1: " + price1.formatted());64System.out.println("Price 2: " + price2.formatted());6566Money total = price1.add(price2Money[amount=5.25, currency=USD]);67System.out.println("Total: " + total.formatted());outputPrice 2: 5.25 USDpublic Money add(Money other)
pass 1 of 225// Methods with logic26public Money add(Money otherMoney[amount=5.25, currency=USD]) {27 if (!currency.equals(other.currency)) {28 throw new IllegalArgumentException("Currency mismatch");29 }30 return new Money(amount + other.amount, currency);31}total ← Money[amount=15.75, currency=USD]
66Money total→ Money[amount=15.75, currency=USD] = price1.add(price2Money[amount=5.25, currency=USD]);67System.out.println("Total: " + total.formatted());System.out.println("Total: " + total.formatted());
66Money total = price1.add(price2);67System.out.println("Total: " + total.formatted());6869Money doubled = price1.multiply(2);70System.out.println("Doubled: " + doubled.formatted());outputTotal: 15.75 USDpublic Money multiply(double factor)
33public Money multiply(double factor2.0) {34 return new Money(amount * factor, currency);35}doubled ← Money[amount=21.0, currency=USD]
69Money doubled→ Money[amount=21.0, currency=USD] = price1.multiply(2);70System.out.println("Doubled: " + doubled.formatted());System.out.println("Doubled: " + doubled.formatted());
69Money doubled = price1.multiply(2);70System.out.println("Doubled: " + doubled.formatted());outputDoubled: 21.00 USDeuros ← Money[amount=10.0, currency=EUR]
72// Currency mismatch73try {74 Money euros→ Money[amount=10.0, currency=EUR] = new Money(10, "EUR");75 Money combined = price1.add(eurosMoney[amount=10.0, currency=EUR]);76 System.out.println("Combined: " + combined);public Money add(Money other)
pass 2 of 225// Methods with logic26public Money add(Money otherMoney[amount=10.0, currency=EUR]) {27 if (!currency.equals(other.currency)) {if (!currency.equals(other.currency))
26public Money add(Money other) {27 if (!currency.equals(other.currencyEUR)) {28 throw new IllegalArgumentException("Currency mismatch");29 }catch (IllegalArgumentException e)
76 System.out.println("Combined: " + combined);77} catch (IllegalArgumentException ejava.lang.IllegalArgumentException: Currency mismatch) {78 System.out.println("\nError: " + e.getMessage());79}output Error: Currency mismatchrect ← Rectangle[width=10.0, height=5.0]
100Rectangle rect→ Rectangle[width=10.0, height=5.0] = new Rectangle(10, 5);101102System.out.println("\nRectangle: " + rectRectangle[width=10.0, height=5.0]);103System.out.printf("Area: %.1f%n", rect.area());104System.out.printf("Perimeter: %.1f%n", rect.perimeter());output Rectangle: Rectangle[width=10.0, height=5.0]public double area()
82record Rectangle(double width, double height) {83 public double area() {84 return width10.0 * height5.0;85 }System.out.printf("Area: %.1f%n", rect.area());
102System.out.println("\nRectangle: " + rect);103System.out.printf("Area: %.1f%n", rect.area());104System.out.printf("Perimeter: %.1f%n", rect.perimeter());105System.out.println("Is square: " + rect.isSquare());public double perimeter()
87public double perimeter() {88 return 2 * (width10.0 + height5.0);89}System.out.printf("Perimeter: %.1f%n", rect.perimeter());
103System.out.printf("Area: %.1f%n", rect.area());104System.out.printf("Perimeter: %.1f%n", rect.perimeter());105System.out.println("Is square: " + rect.isSquare());public boolean isSquare()
91public boolean isSquare() {92 return width10.0 == height5.0;93}System.out.println("Is square: " + rect.isSquare());
104System.out.printf("Perimeter: %.1f%n", rect.perimeter());105System.out.println("Is square: " + rect.isSquare());106107Rectangle scaled = rect.scale(2);108System.out.println("Scaled 2x: " + scaled);outputIs square: falsepublic Rectangle scale(double factor)
95public Rectangle scale(double factor2.0) {96 return new Rectangle(width * factor, height * factor);97}scaled ← Rectangle[width=20.0, height=10.0]
107Rectangle scaled→ Rectangle[width=20.0, height=10.0] = rect.scale(2);108System.out.println("Scaled 2x: " + scaledRectangle[width=20.0, height=10.0]);outputScaled 2x: Rectangle[width=20.0, height=10.0]
c1 ← Circle[radius=3.5]
42public class CustomMethods {43 public static void main(String[] args) {44 // Use custom methods45 Circle c1→ Circle[radius=3.5] = new Circle(3.5);46 47 System.out.println("Circle: " + c1Circle[radius=3.5]);48 System.out.println("Radius: " + c1.radius());49 System.out.printf("Area: %.2f%n", c1.area());50 System.out.printf("Circumference: %.2f%n", c1.circumference());outputCircle: Circle[radius=3.5] Radius: 3.5public double area()
5// Add custom methods6public double area() {7 return Math.PI * radius3.5 * radius;8}System.out.printf("Area: %.2f%n", c1.area());
48System.out.println("Radius: " + c1.radius());49System.out.printf("Area: %.2f%n", c1.area());50System.out.printf("Circumference: %.2f%n", c1.circumference());51System.out.printf("Diameter: %.2f%n", c1.diameter());public double circumference()
10public double circumference() {11 return 2 * Math.PI * radius3.5;12}System.out.printf("Circumference: %.2f%n", c1.circumference());
49System.out.printf("Area: %.2f%n", c1.area());50System.out.printf("Circumference: %.2f%n", c1.circumference());51System.out.printf("Diameter: %.2f%n", c1.diameter());public double diameter()
14public double diameter() {15 return 2 * radius3.5;16}System.out.printf("Diameter: %.2f%n", c1.diameter());
50System.out.printf("Circumference: %.2f%n", c1.circumference());51System.out.printf("Diameter: %.2f%n", c1.diameter());525354// Use static factory55Circle c2 = Circle.fromDiameter(20);56System.out.println("\nFrom diameter 20: " + c2);public static Circle fromDiameter(double diameter)
18// Static factory method19public static Circle fromDiameter(double diameter20.0) {20 return new Circle(diameter / 2);21}c2 ← Circle[radius=10.0], price1 ← Money[amount=10.5, currency=USD]
54// Use static factory55Circle c2→ Circle[radius=10.0] = Circle.fromDiameter(20);56System.out.println("\nFrom diameter 20: " + c2Circle[radius=10.0]);57System.out.printf("Radius: %.1f%n", c2.radius());5859// Money operations60Money price1→ Money[amount=10.5, currency=USD] = new Money(10.50, "USD");61Money price2→ Money[amount=5.25, currency=USD] = new Money(5.25, "USD");6263System.out.println("\nPrice 1: " + price1.formatted());64System.out.println("Price 2: " + price2.formatted());output From diameter 20: Circle[radius=10.0]public String formatted()
pass 1 of 437public String formatted() {38 return String.format("%.2f %s", amount10.5, currencyUSD);39}All 4 passes — pass 1 is the card above pass amount1 10.5 2 5.25 3 15.75 4 21.0 System.out.println(" Price 1: " + price1.formatted());
63System.out.println("\nPrice 1: " + price1.formatted());64System.out.println("Price 2: " + price2.formatted());output Price 1: 10.50 USDMoney total = price1.add(price2);
63System.out.println("\nPrice 1: " + price1.formatted());64System.out.println("Price 2: " + price2.formatted());6566Money total = price1.add(price2Money[amount=5.25, currency=USD]);67System.out.println("Total: " + total.formatted());outputPrice 2: 5.25 USDpublic Money add(Money other)
pass 1 of 225// Methods with logic26public Money add(Money otherMoney[amount=5.25, currency=USD]) {27 if (!currency.equals(other.currency)) {28 throw new IllegalArgumentException("Currency mismatch");29 }30 return new Money(amount + other.amount, currency);31}total ← Money[amount=15.75, currency=USD]
66Money total→ Money[amount=15.75, currency=USD] = price1.add(price2Money[amount=5.25, currency=USD]);67System.out.println("Total: " + total.formatted());System.out.println("Total: " + total.formatted());
66Money total = price1.add(price2);67System.out.println("Total: " + total.formatted());6869Money doubled = price1.multiply(2);70System.out.println("Doubled: " + doubled.formatted());outputTotal: 15.75 USDpublic Money multiply(double factor)
33public Money multiply(double factor2.0) {34 return new Money(amount * factor, currency);35}doubled ← Money[amount=21.0, currency=USD]
69Money doubled→ Money[amount=21.0, currency=USD] = price1.multiply(2);70System.out.println("Doubled: " + doubled.formatted());System.out.println("Doubled: " + doubled.formatted());
69Money doubled = price1.multiply(2);70System.out.println("Doubled: " + doubled.formatted());outputDoubled: 21.00 USDeuros ← Money[amount=10.0, currency=EUR]
72// Currency mismatch73try {74 Money euros→ Money[amount=10.0, currency=EUR] = new Money(10, "EUR");75 Money combined = price1.add(eurosMoney[amount=10.0, currency=EUR]);76 System.out.println("Combined: " + combined);public Money add(Money other)
pass 2 of 225// Methods with logic26public Money add(Money otherMoney[amount=10.0, currency=EUR]) {27 if (!currency.equals(other.currency)) {if (!currency.equals(other.currency))
26public Money add(Money other) {27 if (!currency.equals(other.currencyEUR)) {28 throw new IllegalArgumentException("Currency mismatch");29 }catch (IllegalArgumentException e)
76 System.out.println("Combined: " + combined);77} catch (IllegalArgumentException ejava.lang.IllegalArgumentException: Currency mismatch) {78 System.out.println("\nError: " + e.getMessage());79}output Error: Currency mismatchrect ← Rectangle[width=10.0, height=5.0]
100Rectangle rect→ Rectangle[width=10.0, height=5.0] = new Rectangle(10, 5);101102System.out.println("\nRectangle: " + rectRectangle[width=10.0, height=5.0]);103System.out.printf("Area: %.1f%n", rect.area());104System.out.printf("Perimeter: %.1f%n", rect.perimeter());output Rectangle: Rectangle[width=10.0, height=5.0]public double area()
82record Rectangle(double width, double height) {83 public double area() {84 return width10.0 * height5.0;85 }System.out.printf("Area: %.1f%n", rect.area());
102System.out.println("\nRectangle: " + rect);103System.out.printf("Area: %.1f%n", rect.area());104System.out.printf("Perimeter: %.1f%n", rect.perimeter());105System.out.println("Is square: " + rect.isSquare());public double perimeter()
87public double perimeter() {88 return 2 * (width10.0 + height5.0);89}System.out.printf("Perimeter: %.1f%n", rect.perimeter());
103System.out.printf("Area: %.1f%n", rect.area());104System.out.printf("Perimeter: %.1f%n", rect.perimeter());105System.out.println("Is square: " + rect.isSquare());public boolean isSquare()
91public boolean isSquare() {92 return width10.0 == height5.0;93}System.out.println("Is square: " + rect.isSquare());
104System.out.printf("Perimeter: %.1f%n", rect.perimeter());105System.out.println("Is square: " + rect.isSquare());106107Rectangle scaled = rect.scale(2);108System.out.println("Scaled 2x: " + scaled);outputIs square: falsepublic Rectangle scale(double factor)
95public Rectangle scale(double factor2.0) {96 return new Rectangle(width * factor, height * factor);97}scaled ← Rectangle[width=20.0, height=10.0]
107Rectangle scaled→ Rectangle[width=20.0, height=10.0] = rect.scale(2);108System.out.println("Scaled 2x: " + scaledRectangle[width=20.0, height=10.0]);outputScaled 2x: Rectangle[width=20.0, height=10.0]
Records can have static and instance methods. Fields stay immutable.
Record vs class
When to use each.
// Record vs class comparison
// Concept: record vs class - when to use each
// Traditional class
class MutablePoint {
private int x;
private int y;
public MutablePoint(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
public void setX(int x) { this.x = x; }
public void setY(int y) { this.y = y; }
public void move(int dx, int dy) {
x += dx;
y += dy;
}
}
// Record (immutable)
record ImmutablePoint(int x, int y) {
public ImmutablePoint move(int dx, int dy) {
return new ImmutablePoint(x + dx, y + dy);
}
}
// Class with inheritance
class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
public String getColor() {
return color;
}
}
class ColoredCircle extends Shape {
private double radius;
public ColoredCircle(String color, double radius) {
super(color);
this.radius = radius;
}
public double getRadius() {
return radius;
}
}
// Record implementing interface
interface Describable {
String describe();
}
record Product(String name, double price) implements Describable {
@Override
public String describe() {
return name + " ($" + price + ")";
}
}
public class RecordVsClass {
public static void main(String[] args) {
// Mutable class
MutablePoint mp = new MutablePoint(10, 20);
System.out.println("Mutable point: (" + mp.getX() + ", " + mp.getY() + ")");
mp.setX(15);
mp.move(5, 10);
System.out.println("After changes: (" + mp.getX() + ", " + mp.getY() + ")");
// Immutable record
ImmutablePoint ip = new ImmutablePoint(10, 20);
System.out.println("\nImmutable point: " + ip);
ImmutablePoint ip2 = ip.move(5, 10);
System.out.println("Original: " + ip);
System.out.println("After move: " + ip2);
// Inheritance example
ColoredCircle circle = new ColoredCircle("red", 5.0);
System.out.println("\nColored circle:");
System.out.println(" Color: " + circle.getColor());
System.out.println(" Radius: " + circle.getRadius());
// Records cannot extend classes (always final)
// record cannot be used here
// Record with interface
Product product = new Product("Laptop", 999.99);
System.out.println("\nProduct: " + product.describe());
// When to use records
System.out.println("\nUse records for:");
System.out.println(" ✓ DTOs (Data Transfer Objects)");
System.out.println(" ✓ Immutable data models");
System.out.println(" ✓ Return multiple values");
System.out.println(" ✓ Map keys, set elements");
System.out.println("\nUse classes for:");
System.out.println(" ✓ Mutable state");
System.out.println(" ✓ Inheritance hierarchies");
System.out.println(" ✓ Private fields with logic");
System.out.println(" ✓ Complex initialization");
// Practical examples
// Good use of record
record ApiResponse(int status, String message, Object data) {}
ApiResponse success = new ApiResponse(200, "OK", "Hello");
ApiResponse error = new ApiResponse(404, "Not Found", null);
System.out.println("\nAPI responses:");
System.out.println(" " + success);
System.out.println(" " + error);
// Good use of class
class Counter {
private int count = 0;
public void increment() { count++; }
public int getCount() { return count; }
}
Counter counter = new Counter();
counter.increment();
counter.increment();
System.out.println("\nCounter: " + counter.getCount());
}
}
public static void main(String[] args)
71public class RecordVsClass {72 public static void main(String[] args) {73 // Mutable class74 MutablePoint mp = new MutablePoint(10, 20);75 System.out.println("Mutable point: (" + mp.getX() + ", " + mp.getY() + ")");this.x ← 10, this.y ← 20
9public MutablePoint(int x10, int y20) {10 this.x→ 10 = x10;11 this.y→ 20 = y20;12}mp ← ⟨MutablePoint A⟩
73// Mutable class74MutablePoint mp→ ⟨MutablePoint A⟩ = new MutablePoint(10, 20);75System.out.println("Mutable point: (" + mp.getX() + ", " + mp.getY() + ")");public int getX()
pass 1 of 214public int getX() { return x10; }15public int getY() { return y; }public int getY()
pass 1 of 214public int getX() { return x; }15public int getY() { return y20; }System.out.println("Mutable point: (" + mp.getX() + ", " + mp.getY() +…
74MutablePoint mp = new MutablePoint(10, 20);75System.out.println("Mutable point: (" + mp.getX() + ", " + mp.getY() + ")");7677mp.setX(15);78mp.move(5, 10);outputMutable point: (10, 20)this.x ← 15
17public void setX(int x15) { this.x→ 15 = x; }18public void setY(int y) { this.y = y; }mp.setX(15);
77mp.setX(15);78mp.move(5, 10);79System.out.println("After changes: (" + mp.getX() + ", " + mp.getY() + ")");x ← 20, y ← 30
20public void move(int dx5, int dy10) {21 x→ 20 += dx5;22 y→ 30 += dy10;23}mp.move(5, 10);
77mp.setX(15);78mp.move(5, 10);79System.out.println("After changes: (" + mp.getX() + ", " + mp.getY() + ")");public int getX()
pass 2 of 214public int getX() { return x20; }15public int getY() { return y; }public int getY()
pass 2 of 214public int getX() { return x; }15public int getY() { return y30; }ip ← ImmutablePoint[x=10, y=20]
78mp.move(5, 10);79System.out.println("After changes: (" + mp.getX() + ", " + mp.getY() + ")");8081//@help h182// Class: Mutable, can have inheritance, more flexible83// Record: Immutable, no inheritance, less boilerplate84// Use records for simple data carriers85// Use classes when you need mutability or inheritance86//@end8788// Immutable record89ImmutablePoint ip→ ImmutablePoint[x=10, y=20] = new ImmutablePoint(10, 20);90System.out.println("\nImmutable point: " + ipImmutablePoint[x=10, y=20]);9192ImmutablePoint ip2 = ip.move(5, 10);93System.out.println("Original: " + ip);outputAfter changes: (20, 30) Immutable point: ImmutablePoint[x=10, y=20]public ImmutablePoint move(int dx, int dy)
27record ImmutablePoint(int x, int y) {28 public ImmutablePoint move(int dx5, int dy10) {29 return new ImmutablePoint(x + dx, y + dy);30 }ip2 ← ImmutablePoint[x=15, y=30]
92ImmutablePoint ip2→ ImmutablePoint[x=15, y=30] = ip.move(5, 10);93System.out.println("Original: " + ipImmutablePoint[x=10, y=20]);94System.out.println("After move: " + ip2ImmutablePoint[x=15, y=30]);9596// Inheritance example97ColoredCircle circle = new ColoredCircle("red", 5.0);98System.out.println("\nColored circle:");outputOriginal: ImmutablePoint[x=10, y=20] After move: ImmutablePoint[x=15, y=30]this.color ← red
37public Shape(String colorred) {38 this.color→ red = colorred;39}this.radius ← 5.0
49public ColoredCircle(String colorred, double radius5.0) {50 super(color);51 this.radius→ 5.0 = radius5.0;52}circle ← ⟨ColoredCircle B⟩
96// Inheritance example97ColoredCircle circle→ ⟨ColoredCircle B⟩ = new ColoredCircle("red", 5.0);98System.out.println("\nColored circle:");99System.out.println(" Color: " + circle.getColor());100System.out.println(" Radius: " + circle.getRadius());output Colored circle:public String getColor()
41public String getColor() {42 return colorred;43}System.out.println(" Color: " + circle.getColor());
98System.out.println("\nColored circle:");99System.out.println(" Color: " + circle.getColor());100System.out.println(" Radius: " + circle.getRadius());output Color: redpublic double getRadius()
54public double getRadius() {55 return radius5.0;56}product ← Product[name=Laptop, price=999.99]
99System.out.println(" Color: " + circle.getColor());100System.out.println(" Radius: " + circle.getRadius());101102// Records cannot extend classes (always final)103// record cannot be used here104105// Record with interface106Product product→ Product[name=Laptop, price=999.99] = new Product("Laptop", 999.99);107System.out.println("\nProduct: " + product.describe());output Radius: 5.0@Override public String describe()
64record Product(String name, double price) implements Describable {65 @Override66 public String describe() {67 return nameLaptop + " ($" + price999.99 + ")";68 }error ← ApiResponse[status=404, message=Not Found, data=null]
106Product product = new Product("Laptop", 999.99);107System.out.println("\nProduct: " + product.describe());108109// When to use records110System.out.println("\nUse records for:");111System.out.println(" ✓ DTOs (Data Transfer Objects)");112System.out.println(" ✓ Immutable data models");113System.out.println(" ✓ Return multiple values");114System.out.println(" ✓ Map keys, set elements");115116System.out.println("\nUse classes for:");117System.out.println(" ✓ Mutable state");118System.out.println(" ✓ Inheritance hierarchies");119System.out.println(" ✓ Private fields with logic");120System.out.println(" ✓ Complex initialization");121122// Practical examples123// Good use of record124record ApiResponse(int status, String message, Object data) {}125126ApiResponse success = new ApiResponse(200, "OK", "Hello");127ApiResponse error→ ApiResponse[status=404, message=Not Found, data=null] = new ApiResponse(404, "Not Found", null);128129System.out.println("\nAPI responses:");130System.out.println(" " + successApiResponse[status=200, message=OK, data=Hello]);131System.out.println(" " + errorApiResponse[status=404, message=Not Found, data=null]);132133// Good use of class134class Counter {135 private int count = 0;136 137 public void increment() { count++; }138 public int getCount() { return count; }139}140141Counter counter = new Counter();142counter.increment();143counter.increment();output Product: Laptop ($999.99) Use records for: ✓ DTOs (Data Transfer Objects) ✓ Immutable data models ✓ Return multiple values ✓ Map keys, set elements Use classes for: ✓ Mutable state ✓ Inheritance hierarchies ✓ Private fields with logic ✓ Complex initialization API responses: ApiResponse[status=200, message=OK, data=Hello] ApiResponse[status=404, message=Not Found, data=null]count ← 1
pass 1 of 2137public void increment() { count→ 1++; }138public int getCount() { return count; }counter.increment();
141Counter counter = new Counter();142counter.increment();143counter.increment();144System.out.println("\nCounter: " + counter.getCount());count ← 2
pass 2 of 2137public void increment() { count→ 2++; }138public int getCount() { return count; }counter.increment();
142 counter.increment();143 counter.increment();144 System.out.println("\nCounter: " + counter.getCount());145}public int getCount()
137 public void increment() { count++; }138 public int getCount() { return count2; }139}System.out.println(" Counter: " + counter.getCount());
143 counter.increment();144 System.out.println("\nCounter: " + counter.getCount());145}output Counter: 2
Record: pure data, immutable. Class: mutable state, complex behavior.
Exercise: Practical.java
Model API responses with records