上下文:
我在我正在处理的 selenium 框架中发现了一个错误,其中 Web 浏览器(至少是 Chrome)意外崩溃,没有通知.
作为补丁,我正在重新初始化 WebDriver 以便它继续工作,但现在我正在创建一个新的 EdgeDriver,我想创建一个与之前相同类型的新 WebDriver(崩溃的那个)。
我想出了这种方法:
driver = Map.of(
ChromeDriver.class, getFunction(ChromeDriver.class),
EdgeDriver.class, getFunction(EdgeDriver.class),
FirefoxDriver.class, getFunction(FirefoxDriver.class),
OperaDriver.class, getFunction(OperaDriver.class)
).entrySet().stream().filter((e) -> e.getKey().isInstance(driver))
.map((e)->e.getValue().identity()).findFirst().orElseThrow(() -> new RuntimeException("WebDriver not detected"));
。
@SneakyThrows
static Function<Class<? extends RemoteWebDriver>, RemoteWebDriver> getFunction(Class<? extends RemoteWebDriver> driverClass){
return c -> {
try {
return c.getConstructor().newInstance();
} catch (IllegalAccessException | InstantiationException e) {
throw new RuntimeException(e);
}
};
}
问题是我不能使用这种类型的呼叫
e.getValue().identity()
你知道我怎样才能做到这一点吗?
我正在使用Map方法,所以我不必指定一堆包含所有代码的if
.
而且我正在使用一个单独的方法返回一个函数,所以我不必在需要之前(以及如果它们)花费资源来创建实例。
我以前遇到过这个问题,我很确定我会继续面对它,我几乎不知道我在函数式编程部分写了什么,因为我对它很陌生。我希望我走在正确的轨道上,但老实说,我对此表示怀疑。
作为一个额外的提示,如果你能提供一种成为Java函数式编程专家的方法,那就太好了,因为我一直在寻找一门课程或任何足够深入的资源,但到目前为止我还没有找到任何东西。不仅可以解决这个问题,还可以帮助我解决将来任何类似的问题。
由于getFunction(Class)
返回一个Function<Class<? extends RemoteWebDriver>, RemoteWebDriver>
因此您需要像e.getValue().apply(driver.getClass())
一样称呼它。但是,Supplier<RemoteWebDriver>
似乎更合适:
@SneakyThrows
static Supplier<RemoteWebDriver> getSupplier(Class<? extends RemoteWebDriver> driverClass){
return () -> {
try {
return driverClass.getConstructor().newInstance();
} catch (IllegalAccessException | InstantiationException e) {
throw new RuntimeException(e);
}
};
}
然后像....map((e)->e.getValue().get())
一样使用它.
我从方法名称中更改了什么?
- 返回一个
Supplier<RemoveWebDriver>
,该具有执行它的get()
方法并返回结果 - 由于供应商不接受争论,因此 lambda 从
c -> { ... }
变为() -> { ... }
。 c
不再可用,但无论如何您都希望将参数"绑定"到 lambdagetSupplier()
,这是可能的,因为它是"有效的最终"。这意味着您可以使用driverClass.getConstructor()
而不是c.getConstructor()
但是,不需要所有这些复杂性 - 您只需将供应商直接放入地图中:
//the <Class<? extends RemoteWebDriver>, Supplier<? extends RemoteWebDriver>> is needed to help the compiler infer the generic types
Map.<Class<? extends RemoteWebDriver>, Supplier<? extends RemoteWebDriver>>of(ChromeDriver.class, ChromeDriver::new,
EdgeDriver.class, EdgeDriver::new,
FirefoxDriver.class, FirefoxDriver::new,
OperaDriver.class, OperaDriver::new)
...
如果你不喜欢这个<Class<? extends RemoteWebDriver>, Supplier<? extends RemoteWebDriver>>
你可以用一个类型为"baked in"的小方法来帮助编译器:
static Supplier<? extends RemoteWebDriver> supply(Supplier<? extends I> s) { return s ; }
Map.of(ChromeDriver.class, supply(ChromeDriver::new),
EdgeDriver.class, supply(EdgeDriver::new),
FirefoxDriver.class, supply(FirefoxDriver::new),
OperaDriver.class, supply(OperaDriver::new))
...
您可以使用方法引用访问存储为值Map.Entry::getValue
但它不适用。
因为在map()
中,您需要一个可以使用Map.Entry
拨号的函数,但您的函数期望Class
实例作为参数作为参数(即预期的参数不匹配)。
因此,正确的函数可以编写为以下lambda表达式:
e -> e.getValue().apply(e.getKey())
例:
RemoteWebDriver target = // initializing the target driver
RemoteWebDriver driver = Map.of(
ChromeDriver.class, getFunction(ChromeDriver.class),
EdgeDriver.class, getFunction(EdgeDriver.class),
FirefoxDriver.class, getFunction(FirefoxDriver.class),
OperaDriver.class, getFunction(OperaDriver.class)
)
.entrySet().stream()
.filter(e -> e.getKey().isInstance(target))
.map(e -> e.getValue().apply(e.getKey()))
.findFirst()
.orElseThrow(() -> new RuntimeException("WebDriver not detected"));