web-dev-qa-db-de.com

Java 8 - Speichern Sie Lambdas in List

Ich frage mich, ob es möglich ist, Lambdas beispielsweise in einem Container zu lagern. ArrayList oder HashMap. Ich möchte diesen Code ändern:

public enum OPCODE implements BinaryOperator<Integer> {
    MOV((x, y) -> y),
    INC((x, y) -> ++x),
    DEC((x, y) -> --x),
    ADD((x, y) -> x + y),
    SUB((x, y) -> x - y);

    private final BinaryOperator<Integer> binaryOperator;

    OPCODE(BinaryOperator<Integer> binaryOperator) {
        this.binaryOperator = binaryOperator;
    }  

    @Override
    public Integer apply(Integer integer, Integer integer2) {
        return binaryOperator.apply(integer, integer2);
    }
}

Zu etwas wie:

List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>(){
    ((x, y) -> y),
    ((x, y) -> ++x)
};

usw.

und benutze es wie folgt:

opcodes[0].apply(a, b);

Es ist sogar möglich

16
Jump3r

Sie können sicherlich eine solche Liste erstellen als:

List<BinaryOperator<Integer>> opcodes = Arrays.asList((x, y) -> y, (x, y) -> ++x);

// sample
int a=14,b=16;
System.out.println(opcodes.get(0).apply(a, b)); // prints 16
System.out.println(opcodes.get(1).apply(a, b)); // prints 15

Oder die Art und Weise, wie Sie die Liste initialisieren wollten, korrigieren 

List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>() {{
    add((x, y) -> y);
    add((x, y) -> ++x);
    add((x, y) -> --x);
    add((x, y) -> x + y);
    add((x, y) -> x - y);
}};
12
nullpointer

In der großen Antwort von @ nullpointer können Sie auch die Verwendung einer Map-Taste in Betracht ziehen, um die ursprüngliche OPCODE-Intention der Funktionen beizubehalten, die sich als lst im Array befinden würde, z. mit einer Enum als Schlüssel:

public enum OPCODES {
    MOV, ADD, XOR
}

Welche können bootstrapped werden:

Map<OPCODES, BinaryOperator<Integer>> opcodeMap = 
  new EnumMap<OPCODES, BinaryOperator<Integer>>(OPCODES.class);
opcodeMap.put(OPCODES.ADD, (x, y)-> x + y);
opcodeMap.put(OPCODES.MOV, (x, y) -> y);
opcodeMap.put(OPCODES.XOR, (x, y) -> x ^ y);

Und verwendet:

System.out.println(opcodeMap.get(OPCODES.ADD).apply(1, 2));
System.out.println(opcodeMap.get(OPCODES.MOV).apply(1, 2));
System.out.println(opcodeMap.get(OPCODES.XOR).apply(1, 2));
9
StuartLC

Sie könnten Lambdas in einem Behälter aufbewahren, aber die eigentliche Frage ist, warum sollten Sie das tun? Das Speichern in einem List ist einfach. Wie wäre es beispielsweise mit einem Set/Map - Sie können equals/hashcode Für Lambdas nicht überschreiben - Sie können also nicht sagen, was passieren würde.

Da Sie dort bereits ein Enum haben, können Sie die einfachere Methode verwenden:

Set<OPCODE> set = EnumSet.allOf(OPCODE.class);
3
Eugene

Daher haben Sie Ihren Operator definiert, sobald Sie Folgendes tun können:

List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>() {{
    add(OPCODE.ADD);
    add(OPCODE.DEC);
}};

um das in deiner Hauptmethode zu testen:

opcodes.forEach(Elm -> System.out.println(Elm.apply(1,2)));

Ja, Sie können Lambdas in eine Liste oder in Werte einer Karte einfügen. Denken Sie daran, dass Lambdas nur eine ausgefallene Möglichkeit sind, anonyme Klassen zu schreiben, die wiederum nur ein Sonderfall des Operators new sind. Anders ausgedrückt, operators.add((x, y) -> x + y) ist nur eine Abkürzung für

final BinaryOperator<Integer> ADD = new BinaryOperator<Integer>() {
    @Override
    public Integer apply(final Integer x, final Integer y) {
        return x + y;
    }
};
operators.add(ADD);

Nach derselben Logik würde operatorMap.put("add", (x, y) -> x + y); auch genau das tun, was Sie erwarten.

Allerdings das Einfügen von Lambdas in einen Satz - was die Verwendung als Landkartenschlüssel beinhaltet - macht möglicherweise nicht das, was Sie erwarten. Im Allgemeinen hängt das Verhalten einer Menge von der Definition von equals und hashCode nach ihrem Elementtyp ab, und die Sprache übernimmt keine Garantie für diese Methoden, die über das hinausgehen, was durch die Definition von Object vorgeschrieben ist. Daher kann die folgende Zusicherung fehlschlagen:

final Function<Object, String> func1 = Object::toString;
final Function<Object, String> func2 = Object::toString;
assert func1.equals(func2);

Ebenso das Folgende:

final Function<Object, String> func = Object::toString;
final Set<Object> set = new HashSet<>();
set.add(func);
assert set.contains(Object::toString);

Seien Sie also vorsichtig, wenn Sie Lambdas in Set-basierte Container setzen, einschließlich der Verwendung als Map-Schlüssel. Sie können jedoch in Lists eingegeben und als Map-Werte verwendet werden.

0
naomimyselfandi