Anonyme klasser og lambda-uttrykk
$ java -version
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
public class SimpleProgram {
public static void main(String[] args) {
HelloPrinter printer = new HelloPrinter();
printer.run();
}
}
Vanlige klasser
public class HelloPrinter implements Runnable {
@Override
public void run() {
System.out.println("Hello");
}
}
Disse kjenner vi jo godt.
public class SimpleProgram {
public static void main(String[] args) {
HelloPrinter printer = new HelloPrinter();
printer.run();
}
public static class HelloPrinter implements Runnable {
@Override
public void run() {
System.out.println("Hello");
}
}
}
Statiske indre klasser
Akkurat som vanlige klasser, bare at de har tilgang på statiske variabler inne i klassen.
Vanligvis bare en måte å si at en klasse "hører til" en annen.
public class SimpleProgram {
private String message = "Hello";
public static void main(String[] args) {
SimpleProgram program = new SimpleProgram();
HelloPrinter printer = program.new HelloPrinter();
program.message = "Tada!";
printer.run();
}
public class HelloPrinter implements Runnable {
@Override
public void run() {
System.out.println(message);
}
}
}
"Ekte" indre klasser
Hører til et objekt av klassen den er inne i, og har tilgang til alt annet inne i objektet (nyttig for iteratorer o.l.).
public class SimpleProgram {
public static void main(String[] args) {
String message = "Hello";
class HelloPrinter implements Runnable {
@Override
public void run() {
System.out.println(message);
}
}
HelloPrinter printer = new HelloPrinter();
// message = "Tada!"; <--- Ikke lov
printer.run();
}
}
Lokale klasser
Definert kun i en metode, og kan bruke alle variabler som er "effectively final" (altså ikke endres etter den er satt første gang).
public class SimpleProgram {
public static void main(String[] args) {
String message = "Hello";
Runnable printer = new Runnable() {
@Override
public void run() {
System.out.println(message);
}
};
//message = "Tada!"; <--- Fortsatt ikke lov
printer.run();
}
}
Anonyme klasser
Lokale klasser uten navn. Å lage en anonym klasse er et helt vanlig uttrykk.
Vi kan lage anonyme klasser av alt vi kan implementere eller arve.
public class SimpleProgram {
public static void main(String[] args) {
String message = "Hello";
Runnable printer = () -> {
System.out.println(message);
};
//message = "Tada!"; <--- Fortsatt ikke lov
printer.run();
}
}
Lambda-uttrykk
En ny måte (i Java 8) å lage anonyme klasser for grensesnitt som bare har én abstrakt metode.
List<String> names = new ArrayList<>();
names.add("Althalus");
names.add("Zaphod");
names.add("Kari");
names.add("Knut");
class ReverseComparator implements Comparator<String> {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
}
names.sort(new ReverseComparator());
System.out.println(names);
//[Zaphod, Knut, Kari, Althalus]
Eksempel - Sortering
Lokal klasse:
class ReverseComparator implements Comparator<String> {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
}
names.sort(new ReverseComparator());
Eksempel - Sortering
Lokal klasse:
names.sort(new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
Anonym klasse:
Eksempel - Sortering
names.sort(new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
Anonym klasse:
names.sort((String a, String b) -> {
return b.compareTo(a);
});
Lambda-uttrykk:
names.sort((a, b) -> b.compareTo(a));
eller...
Funksjonell programmering?
Strategy Pattern?
På tide å prøve selv
git clone https://github.com/evestera/inf1010v16
cd inf1010v16/Lambda/07_oppgaver
Startkode:
Alle eksemplene vist så langt ligger i mappene 01_... til 06_...
git checkout [filen du vil nullstille]
Tips, hvis du vil tilbakestille en fil til startkoden kan du bruke følgende kommando:
java.util.function
Function<T,R> : R apply(T t)
Supplier<T> : T get()
Consumer<T> : void accept(T t)
Predicate<T> : boolean test(T t)
BiFunction<T,U,R> : R apply(T t, U u)
BinaryOperator<T> : BiFunction<T,T,T>
UnaryOperator<T> : Function<T,T>
Metode-referanser
list.forEach(x -> System.out.println(x));
// er det samme som:
list.forEach(System.out::println);
Hvis det eneste du gjør i et lambda-uttrykk er å sende argumentene til en funksjon kan du bruke en metode-referanse.
Du bytter altså bare ut siste . i metode-adressen med ::
Eksempel med tråd
class ThreadExample {
public static void main(String[] args) {
Thread thread = new Thread(ThreadExample::doWork);
thread.start();
}
public static void doWork() {
System.out.println("Work");
System.out.println("Workwork");
}
}
- new Thread(...) tar imot en Runnable
- Runnable har én metode; run
- run-metoden er "void" og tar ingen argumenter
- doWork stemmer overens med denne "typen".
// i Thread
Thread(Runnable target)
// Runnable
void run()
Eksempel med EventHandler
public void start(Stage stage) {
Button button = new Button("Click me!");
button.setOnAction(this::handleButtonClick);
//...
}
public void handleButtonClick(ActionEvent event) {
System.out.println("You clicked the button!");
}
// i Button
public final void setOnAction(EventHandler<ActionEvent> value)
// EventHandler<T>
void handle(T event)
Referanser til ikke-statiske metoder
List<String> list = new ArrayList<>();
Files.lines(Paths.get("myFile.txt")).forEach(list::add);
list.replaceAll(String::trim);
list.removeIf(String::isEmpty);
LinkedList<String>::new
Streams
ArrayList<String> numbers = new ArrayList<>();
new Scanner(new File("input.txt"))
.useDelimiter("\\D+")
.forEachRemaining(numbers::add);
int sumOfOddSquares = numbers.stream()
.mapToInt(Integer::parseInt)
.filter(x -> x % 2 != 0)
.map(x -> x * x)
.sum();
System.out.println(sumOfOddSquares);
Anonyme klasser og lambda-uttrykk
By Erik Vesteraas
Anonyme klasser og lambda-uttrykk
- 1,617