web-dev-qa-db-fra.com

Java 8 - magasin lambdas dans la liste

Je me demande s'il est possible de stocker des lambdas dans un conteneur, par exemple. ArrayList ou HashMap ..__ Je veux changer ce code:

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);
    }
}

À quelque chose comme:

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

etc.

et l'utiliser comme ça:

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

C'est même possible?

16
Jump3r

Vous pouvez certainement créer une liste telle que:

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

Ou redresser la façon dont vous avez essayé d'initialiser la liste 

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

Dans l'excellente réponse de @ nullpointer supplémentaire, vous pouvez également envisager d'utiliser une clé Map pour conserver l'intention OPCODE d'origine des fonctions, qui serait lst dans le tableau, par exemple. en utilisant Enum comme clé:

public enum OPCODES {
    MOV, ADD, XOR
}

Qui peut être amorcé:

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);

Et utilisé:

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

Vous pourriez stocker des lambdas dans un conteneur, mais la vraie question est pourquoi voudriez-vous faire cela? Il est facile de les stocker dans une List. Qu'en est-il d'un Set/Map par exemple? Vous ne pouvez pas remplacer equals/hashcode pour lambdas? Vous ne pouvez donc pas savoir ce qui se produirait. 

Puisque vous avez déjà une Enum, pourquoi ne pas utiliser la méthode la plus simple:

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

Vous avez donc défini votre opérateur une fois que vous pouvez faire quelque chose comme ceci:

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

pour tester cela dans votre méthode principale:

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

Oui, vous pouvez mettre des lambdas dans une liste ou les valeurs d’une carte sans problème. Rappelez-vous que les lambdas ne sont qu’un moyen sophistiqué d’écrire des classes anonymes, qui ne sont qu’un cas particulier de l’opérateur new. En d'autres termes, operators.add((x, y) -> x + y) est simplement un raccourci pour

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

Dans la même logique, operatorMap.put("add", (x, y) -> x + y); ferait également exactement ce que vous attendez.

Cependant , le fait de placer les lambdas dans un ensemble - ce qui inclut leur utilisation en tant que clés de carte - risque de ne pas répondre à vos attentes. Généralement, le comportement d'un ensemble dépend de la définition de equals et hashCode par son type d'élément. Le langage ne donne aucune garantie pour ces méthodes au-delà de ce qui est requis par la définition de Object. Par conséquent, l'assertion suivante peut échouer:

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

De même les suivantes:

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

Veillez donc à placer les lambdas dans des conteneurs basés sur Set, y compris leur utilisation en tant que clés Map, mais ils peuvent être placés dans Lists et utilisés comme valeurs Map.

0
naomimyselfandi