Chapter 4 · Robust, modern Java
Enums, records and switch
Step 1 of 22 · Concept
Short forms for small classes
Many classes only hold a few values. Java has short forms for them.
In this lesson you will:
- name a fixed set of values with an enum,
- pick between them with a
switch, - hold plain data in a record,
- write less with
varand text blocks.
Step 2 of 22 · Concept
A type with a fixed list of values
A coffee comes in three sizes, no more. The numbers 1, 2 and 3 would work, but nothing stops a program from passing 7.
An enum lists every value its type may hold. It starts with enum where a class says class:
public enum Size {
SMALL, MEDIUM, LARGE
}
- A
Sizevariable holdsSize.SMALL,Size.MEDIUMorSize.LARGE. No otherSizeexists. Size.values()gives every value, in order.- Printing a value prints its name:
LARGE.
Step 3 of 22 · Quiz
Which values fit?
Size s = …; Which of these may stand after the =?
Step 4 of 22 · Concept
Each value is one object
Size a = Size.LARGE;
Size b = Size.LARGE;
Java makes one object per value, once. Every Size.LARGE is an arrow to that same object.
So == compares two enum values safely: a == b asks whether the arrows point to the same object.
Step 5 of 22 · Concept
Two ways to switch
A switch picks what to do for each value.
- The switch statement,
case SMALL:, jumps to the matching case. Without abreakorreturn, it runs on into the next case.default:takes every value with no case. - The switch expression,
case SMALL ->, gives a value. An arrow case never runs on into the next. On an enum, javac checks that every value has a case.
Step 6 of 22 · Quiz
One arrow, two values
What is cup when size is Size.LARGE?
String cup = switch (size) {
case SMALL -> "a short cup";
case MEDIUM, LARGE -> "a tall cup";
};
Step 7 of 22 · Demo
An enum and two switches
price uses the switch statement, cup the switch expression. Inside a switch on a Size, a case names the
bare value: SMALL. Run it.
Step 8 of 22 · Try it
Try it: a missing break
The case for SMALL has no break. Run it: after small: 2 it runs on into the case for MEDIUM. Add break;
after the first println, so that the program prints:
small: 2
medium: 3
large: 4
break; ends the whole switch. Each case that should stop needs one before the next case.
Step 9 of 22 · Exercise
Your turn: traffic lights
Write the two methods with switch expressions.
nextreturns the light after this one: red, then green, then yellow, then red again.secondsreturns how long it stays on: 30 for red, 25 for green, 5 for yellow.
The program must print:
RED for 30 s
GREEN for 25 s
YELLOW for 5 s
RED for 30 s
cup in the step An enum and two switches has the shape you need: return switch (light) { … };.
One case per light. In next, each case gives a Light: case RED -> Light.GREEN;.
return switch (light) {
case RED -> 30;
case GREEN -> 25;
case YELLOW -> 5;
};
Step 10 of 22 · Concept
A record holds data
Many classes only carry a few values. A record writes all of their code for you from one line.
new Point(1, 2)makes one, andp.x()readsx.- Printing it gives
Point[x=1, y=2]. - Two records with the same values are
equals.
Step 11 of 22 · Quiz
What does it print?
record Point(int x, int y) has no toString of its own. What does this print?
System.out.println(new Point(3, 4));
Step 12 of 22 · Demo
A record
A record may have methods of its own, as move here. Run it.
Step 13 of 22 · Concept
A record never changes
A record's fields are final: the constructor sets them, and then they never change. So move cannot move p.
It makes a new Point on the heap and returns an arrow to it. p still points to the old one.
Step 14 of 22 · Quiz
After the move
p is new Point(1, 2), and Point q = p.move(3, 4); runs. Then what does System.out.println(p); print?
public record Point(int x, int y) {
Point move(int dx, int dy) {
return new Point(x + dx, y + dy);
}
}Step 15 of 22 · Exercise
Your turn: a rectangle record
Rect.java is empty. Write the record Rect with two int values, width and height.
Give it a method int area() and a method boolean isSquare(), true when the two sides are equal. The program
must print:
Rect[width=3, height=4] area 12, square false
Rect[width=5, height=5] area 25, square true
Point.java in the step A record is a record with a method of its own.
The header is public record Rect(int width, int height) {. Inside the record, width and height are its values.
int area() {
return width * height;
}
Step 16 of 22 · Concept
var: javac finds the type
var declares a local variable whose type javac works out from its value.
| you write | javac reads |
|---|---|
var name = "Ada"; | String name = "Ada"; |
var year = 1843; | int year = 1843; |
var list = new ArrayList<String>(); | an ArrayList<String> |
The type is still fixed: after var name = "Ada";, the line name = 5; does not compile.
Step 17 of 22 · Concept
Text over several lines
A text block is a String over several lines, between """ and """.
- The opening
"""ends its own line. - The indentation that all lines share is removed. Extra spaces stay.
- Each line ends in a newline. With the closing
"""on a line of its own, the last line does too.
.formatted(…) fills in %s and %d, as printf does.
Step 18 of 22 · Quiz
Predict the letter
Type exactly what this prints. Spaces count.
var name = "Ada";
var year = 1843;
var letter = """
Dear %s,
your program of %d
still runs.
""".formatted(name, year);
System.out.print(letter);
Step 19 of 22 · Demo
var and a text block
Run it and compare with your answer.
Step 20 of 22 · Check yourself
Check yourself: a coffee order
Write the enum Size (SMALL, MEDIUM, LARGE). Write the record Order with a String drink, a Size size
and a method int price(): 2, 3 or 4 by size.
Then complete main. The program must print:
Coffee Corner
-------------
tea SMALL 2
latte LARGE 4
mocha MEDIUM 3
total: 9
Three files: the enum, the record with its price switch, and a loop in main that also adds up the total.
Step 21 of 22 · Challenge · optional
Challenge: a price inside the enum
Optional. It earns the lesson's third star.
main asks each size for its price: s.price(). Give every value of Size its own price, stored in the enum
itself. The program must print:
SMALL costs 2
MEDIUM costs 3
LARGE costs 4
Each value is an object, so it can have a field, as an object of a class can. An enum may have fields, a constructor and methods.
Write each value with its price: SMALL(2), MEDIUM(3), LARGE(4); (now with a ;). The constructor
Size(int price) stores it in a field.
private final int price;
Size(int price) {
this.price = price;
}
Step 22 of 22 · Recap
Recap
- An enum lists every value its type may hold. Each value is one object.
case X:runs on into the next case withoutbreak. A switch expression,case X ->, never does, and gives a value.- A record writes its
finalfields, the constructor,x(),toStringandequalsfor you. varlets javac find a variable's type. A text block is aStringover several lines.
Next: lesson 17 writes classes and methods that work for any type, with generics.
Review
5 questions from this lesson, in a new order each time. Answer from memory: 3 of 5 right on the first try passes. On a day after you finish the lesson, a pass earns 15 XP.
The review needs JavaScript.
public class Main {
static int price(Size size) {
switch (size) {
case SMALL:
return 2;
case MEDIUM:
return 3;
default:
return 4;
}
}
static String cup(Size size) {
return switch (size) {
case SMALL -> "a short cup";
case MEDIUM -> "a tall cup";
case LARGE -> "a big cup";
};
}
public static void main(String[] args) {
for (Size s : Size.values()) {
System.out.println(s + " costs " + price(s)
+ ", " + cup(s));
}
}
}
public class Main {
static void describe(Size size) {
switch (size) {
case SMALL:
System.out.println("small: 2");
case MEDIUM:
System.out.println("medium: 3");
break;
case LARGE:
System.out.println("large: 4");
break;
}
}
public static void main(String[] args) {
for (Size s : Size.values()) {
describe(s);
}
}
}
public class Main {
static Light next(Light light) {
return light;
}
static int seconds(Light light) {
return 0;
}
public static void main(String[] args) {
Light light = Light.RED;
for (int i = 0; i < 4; i++) {
int s = seconds(light);
System.out.println(light + " for " + s + " s");
light = next(light);
}
}
}
public class Main {
public static void main(String[] args) {
Point p = new Point(1, 2);
Point q = p.move(3, 4);
System.out.println(p);
System.out.println(q.x() + " " + q.y());
System.out.println(p.equals(new Point(1, 2)));
}
}
public class Main {
public static void main(String[] args) {
Rect a = new Rect(3, 4);
Rect b = new Rect(5, 5);
System.out.println(a + " area " + a.area()
+ ", square " + a.isSquare());
System.out.println(b + " area " + b.area()
+ ", square " + b.isSquare());
}
}
public class Main {
public static void main(String[] args) {
var name = "Ada";
var year = 1843;
var letter = """
Dear %s,
your program of %d
still runs.
""".formatted(name, year);
System.out.print(letter);
}
}
import java.util.List;
public class Main {
public static void main(String[] args) {
var orders = List.of(
new Order("tea", Size.SMALL),
new Order("latte", Size.LARGE),
new Order("mocha", Size.MEDIUM));
// print the two header lines with a text block,
// then one line per order, then the total
}
}
public class Main {
public static void main(String[] args) {
for (Size s : Size.values()) {
System.out.println(s + " costs " + s.price());
}
}
}