如何在Java中迭代lambda函数

12

我能用Python做到这一点,我的Python代码如下:

signs = {"+" : lambda a, b : a + b, "-" : lambda a, b : a - b}

a = 5
b = 3
for i in signs.keys():
    print(signs[i](a,b))

输出结果为:

8
2

我该如何通过HashMap在Java中实现相同的操作?


Java 只是稍微冗长了一点点。 - Walter Tross
除了在Python中,据我所知lambda仅限于单个语句,对吧? - Eugene
2
@Eugene 其实,在 Python 中,lambda 函数被限制为不允许任何语句。只允许表达式。 - wizzwizz4
@WalterTross 哎呀,这些值都是字面量,不是吗? :-/ - wizzwizz4
字面量是值,但反之不成立。 - mid
2个回答

22

在这种情况下,您可以像这样使用BinaryOperator<Integer>

BinaryOperator<Integer> add = (a, b) -> a + b;//lambda a, b : a + b
BinaryOperator<Integer> sub = (a, b) -> a - b;//lambda a, b : a - b

// Then create a new Map which take the sign and the corresponding BinaryOperator
// equivalent to signs = {"+" : lambda a, b : a + b, "-" : lambda a, b : a - b}
Map<String, BinaryOperator<Integer>> signs = Map.of("+", add, "-", sub);

int a = 5; // a = 5
int b = 3; // b = 3

// Loop over the sings map and apply the operation
signs.values().forEach(v -> System.out.println(v.apply(a, b)));

输出

8
2

注意:Map.of("+", add, "-", sub); 这段代码是在Java 10中使用的,如果你并没有使用Java 9+版本,那么你可以像下面这样向你的map中添加内容:
Map<String, BinaryOperator<Integer>> signs = new HashMap<>();
signs.put("+", add);
signs.put("-", sub);

Ideone演示


良好实践

正如@Boris the Spider@Holger在评论中所述,最好使用IntBinaryOperator来避免装箱,这样你的代码最终可以看起来像这样:

// signs = {"+" : lambda a, b : a + b, "-" : lambda a, b : a - b}
Map<String, IntBinaryOperator> signs = Map.of("+", (a, b) -> a + b, "-", (a, b) -> a - b);
int a = 5; // a = 5
int b = 3; // b = 3
// for i in signs.keys(): print(signs[i](a,b))
signs.values().forEach(v -> System.out.println(v.applyAsInt(a, b)));

2
谢谢@BoristheSpider,我以前没有使用过IntBinaryOperator,我会学习一下。我看到了你的答案并发现你已经在使用它了,+1。 - Youcef LAIDANI
3
这个函数的输入是(int, int)并返回一个int类型的值,而不是Integer类型的 - 所以避免了装箱操作。你的回答很好,加一分! - Boris the Spider
1
如果您正在使用Java 10,则可以将Map定义为var signs = Map.of("+", add, "-", sub); - fps
这是正确的@FedericoPeraltaSchaffner,去掉var可以使它更易读给OP :) - Youcef LAIDANI
2
即使是对于盒装值,您也可以在此处使用“BinaryOperator<Integer>”,它是“BiFunction<Integer,Integer,Integer>”的子类型。另外,您无需详细声明函数的本地变量:Map<String, BinaryOperator<Integer>> signs = Map.of("+", (a, b) -> a + b, "-", (a, b) -> a - b);;这更接近于 OP 的 Python 代码。当然,每当使用案例允许使用“IntBinaryOperator”时,最好使用它,因为它避免了装箱开销(并且比“BinaryOperator<Integer>”甚至更短)... - Holger
感谢@Holger,我总是从你那里学到东西。我已经用你提供的信息编辑了我的答案,非常感谢。 - Youcef LAIDANI

14

创建一个漂亮的、类型安全的enum

enum Operator implements IntBinaryOperator {
    PLUS("+", Integer::sum),
    MINUS("-", (a, b) -> a - b);

    private final String symbol;
    private final IntBinaryOperator op;

    Operator(final String symbol, final IntBinaryOperator op) {
        this.symbol = symbol;
        this.op = op;
    }

    public String symbol() {
        return symbol;
    }

    @Override
    public int applyAsInt(final int left, final int right) {
        return op.applyAsInt(left, right);
    }
}

对于其他运算符,您可能希望使用返回 double 而不是 int 的 lambda。

现在,只需将其放入 Map 中:

final var operators = Arrays.stream(Operator.values())
        .collect(toMap(Operator::symbol, identity()));

不过针对你的例子,你根本不需要使用 Map

Arrays.stream(Operator.values())
        .mapToInt(op -> op.applyAsInt(a,b))
        .forEach(System.out::println);

使用:

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接