Modern / useful Java
Object-Oriented Programming (OOP)
1
Modern / useful Java features
• var
• enum
• switch expression
• record
• Sealed (& final)
• Comparable
4
VAR
5
Annoyances with declaring variables
This takes a lot of typing:
ArrayList<String> list = new
ArrayList<String>();
and this too:
Optional<Car> car = person.getCar();
What if Java could just infer the types for you?
6
The var keyword (since Java 10)
You can now write:
var list = new ArrayList<String>();
and also:
var car = person.getCar();
7
var vs. the type system
• The types are still static.
• If Java cannot figure out the type, it will tell
you (and your program will not compile).
var number = 3;
number = "hello"; Compiler error: “Cannot
convert from String to int”
Compiler error:
var even = x -> x % 2 == 0; “Lambda expression
needs an explicit
It could be: target-type”
Function<Integer, Integer> even
8
var in an IDE
In an IDE (such as IntelliJ), you can find out the type by
hovering over the var keyword or over the variable name.
9
When can you use var?
• Only when declaring local variables.
• Only when immediately initialising the variable with a
value. So this is not possible:
var x;
10
Should you use var?
• It depends on whom you ask, and when you ask.
• Easier to write? Harder to read? Easier to refactor?
• Be consistent! (Agree with your team.)
11
ENUM(ERATION)
12
Enum(eration)
• Sometimes you have an attribute, that can only have
a few predefined values.
– Wind directions (north, south, east, west)
– Months (January, February, ...)
• An enum can be a better alternative to saving things
in a String.
13
Defining an enum
public enum CardType {
NORMAL,
RARE,
EPIC,
LEGENDARY;
}
14
Using an enum
public class Card {
public enum CardType {
private String name;
NORMAL,
private CardType cardType;
RARE,
public Card(String name, CardType cardType) {
EPIC,
this.name = name;
this.cardType = cardType;
} LEGENDARY;
} public static void main(String[] args) {
Card card = new Card("Mage", CardType.EPIC);
}
}
15
Adding more functionality
public enum CardType {
NORMAL("A normal card with a white outline"),
RARE("A rare card with a blue outline"),
EPIC("An epic card with a purple outline"),
LEGENDARY("A legendary card with a golden outline");
private String description;
CardType(String description) {
this.description = description;
}
//getter
}
16
SWITCH EXPRESSIONS
17
What if we want to do something based on
the card type?
String message; • Classic switch case
switch (card.getCardType()) {
– Works for primitive types, String
case NORMAL, RARE, EPIC:
and enum
message = "nothing special.";
break; – Requires break in between cases
case LEGENDARY:
message = "a legendary!";
break;
default:
message = "unknown card type!";
}
18
What if we want to do something based on
the card type?
• Switch expression
String m = switch (card.getCardType()) {
case NORMAL, RARE, EPIC -> – Works on the same types
"nothing special."; – Each input evaluates to a single
case LEGENDARY -> value
"a legendary!"; – Eliminates the need for break, as
}; there is no “falling trough”
– No need for default when all
cases are covered
19
SEALED (& FINAL)
20
What is sealed?
• You can use final to ensure a class
does not get any children.
• With sealed you can define which
classes are allowed to extend your class.
– Also works for interfaces
21
Using sealed
public sealed class Person permits Student {
...
}
public final class Student extends Person {
...
}
22
RECORDS
23
What is a record?
• A record is a special type of class that
simplifies implementing a class that only
stores immutable data.
• You can implement additional methods.
• You can add static methods or attributes.
24
import java.util.Objects;
public final class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String name(){
return name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true; public record Person(String name) {}
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public String toString() {
return “Person[" + "name='" + name + ']';
}
} 25
Limitations of a record?
• A record cannot extend other classes.
• Classes cannot extend from a record.
• You can never change an attribute in a
record after initialising it.
– The record and all its fields are implicitly
final.
26
COMPARATORS
27
What if you want to order a List?
List<Integer> numbers = new ArrayList<>();
numbers.add(2);
numbers.add(1);
List<String> words = new ArrayList<>();
words.add("Banana");
words.add("Apple");
List<Person> people = new ArrayList<>();
people.add(new Person("Thomas"));
people.add(new Person("Andy"));
Collections.sort(numbers); // [1, 2]
Collections.sort(words); // ["Apple", "Banana"]
Collections.sort(people); // ??? 28
Comparing custom types
• We need to implement the interface Comparable<T>
public record Person(String name) implements Comparable<Person> {
@Override
public int compareTo(Person o) {
return 0;
}
}
• Currently we never alter the order of elements
29
How should compareTo work?
• compareTo(Object o) returns an int
– The result is positive (typically 1) if this is
considered greater than o.
– The result is negative (typically -1) if this is
considered to be smaller than o.
– The result is 0 if this is considered to be equal to o
in terms of ordering.
30
How should compareTo work?
• compareTo(Object o) returns an int
– The result is positive (typically 1) if this is
considered greater than o.
– The result is negative (typically -1) if this is
considered to be smaller than o.
– The result is 0 if this is considered to be equal to o
in terms of ordering.
31
Ordering people
• Let’s order people by their name and rely on the
implementation of compareTo for String!
@Override
public int compareTo(Person o) {
return this.name.compareTo(o.name);
}
32
What if you want to order a List?
List<Integer> numbers = new ArrayList<>();
numbers.add(2);
numbers.add(1);
List<String> words = new ArrayList<>();
words.add("Banana");
words.add("Apple");
List<Person> people = new ArrayList<>();
people.add(new Person("Thomas"));
people.add(new Person("Andy"));
Collections.sort(numbers); // [1, 2]
Collections.sort(words); // [Apple, Banana]
Collections.sort(people); // [Person[name=Andy], Person[name=Thomas]] 33
INTELLIJ TIPS
34
Some useful shortcuts
• Generate code (ALT + INS)
• Autoformat code (CTRL + ALT + L)
• Search (SHIFT, SHIFT)
• Jump to method (CRTL + CLICK)
• Main Method (“psvm” + TAB)
• Println (“sout” + TAB)
35