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,506