gpt4 book ai didi

java - 是否可以在运行时获取 lambda 参数的类型?

转载 作者:行者123 更新时间:2023-12-01 19:32:59 24 4
gpt4 key购买 nike

我在应用 Mockito 的参数匹配器时遇到了类型安全问题。

给定以下界面:

interface SomeInterface {

int method(Object x);

}

我试图模拟它唯一的方法并使用与匹配器类型不同的参数调用它:

SomeInterface someInterface = mock(SomeInterface.class);
when(someInterface.method(argThat((ArgumentMatcher<Integer>) integer -> integer == 42))).thenReturn(42);
someInterface.method("X"); // Throws ClassCastException

但是方法调用 someInterface.method("X") 会产生异常,即:

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

但是,当我将 lambda 扩展为匿名类时,一切正常:

 SomeInterface someInterface = mock(SomeInterface.class);
when(someInterface.method(argThat(new ArgumentMatcher<Integer>() {
@Override
public boolean matches(Integer integer) {
return integer == 42;
}
}))).thenReturn(42);
someInterface.method("X"); // OK, method invokes normally

正如我从 Mockito 源代码中看到的,匹配器参数的类型与实际调用参数的类型进行比较。如果实际参数不是匹配器方法参数类型的子类(因此不能分配给它),则不执行匹配:

private static boolean isCompatible(ArgumentMatcher<?> argumentMatcher, Object argument) {
if (argument == null) {
return true;
} else {
Class<?> expectedArgumentType = getArgumentType(argumentMatcher);
return expectedArgumentType.isInstance(argument);
}
}

但是,对于 lambda 来说,此检查似乎未通过,显然是因为无法在运行时检索 lambda 参数的实际类型(它始终只是一个 Object 类型)。我的说法对吗?

我使用mockito-core 3.0.3

我的Java配置:

java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

最佳答案

我的第一 react 是“只需使用intThat(i -> i == 42)” ”,但显然,该实现正在丢弃它具有 ArgumentMatcher<Integer> 的信息。后来依赖相同的反射方法,但不起作用。

您无法反射性地获取 lambda 参数类型,并且现有的问答解释了为什么这是不可能的,甚至不是有意的。请注意,这甚至不是 lambda 特定的。在某些情况下,普通类的类型也不可用。

最后,当它需要在使用端进行额外的声明(例如显式类型转换 (ArgumentMatcher<Integer>))时,尝试使这种自动化工作是没有意义的。 。例如。而不是

argThat((ArgumentMatcher<Integer>) integer -> integer == 42)

你也可以使用

argThat(obj -> obj instanceof Integer && (Integer)obj == 42)

甚至

argThat(Integer.valueOf(42)::equals)

不过,当我们面对这些琐碎的例子时,eq(42)也可以,甚至 when(someInterface.method(42)).thenReturn(42) .

但是,当您经常需要在此类上下文中将复杂的整数表达式与更广泛的参数类型进行匹配时,接近您最初尝试的解决方案是声明一个可重用的固定类型匹配器接口(interface)

interface IntArgMatcher extends ArgumentMatcher<Integer> {
@Override boolean matches(Integer arg0);
}

并使用

when(someInterface.method(argThat((IntArgMatcher)i -> i == 42))).thenReturn(42);

i == 42作为更复杂表达式的占位符

关于java - 是否可以在运行时获取 lambda 参数的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58991885/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com