我想知道是否有办法直接在定义的同一个表达式中调用lambda函数上的.apply()
或.get()
。当我想初始化一个可能是私有的变量时,我想到了这个问题,但我无法将其声明为final,因为该值是可以抛出异常的函数的返回值。例如,请考虑Files.size(path)
:
final s = Files.size(path);
// code that uses s
现在,如果我想使用s
的默认值,如果有异常,我必须添加try/catch
,但这是一个语句而不是表达式:
s = 0;
try {
s = Files.size();
}
catch (IOException e) {}
// code that uses s
显而易见的解决方案是声明一个包装try / catch的小辅助函数,例如: getFileSizeOrZero
。我也可以编写一个通用函数来包装它作为一般情况。这很好并且具有描述性,但更局部的函数方法会更好。
在C ++中,我使用了lambdas:
const s = []() {
try {
return Files.size(path);
} catch (...) {
return 0;
}
}();
所以我想知道这是否可以用Java完成。我能想到的最好的是
final int s = new IntSupplier() {
@Override
public int getAsInt() {
try {
return Files.size(path);
}
catch (IOException e) {
return 0;
}
}
}.getAsInt();
这似乎很有表现力,所以我希望有一些我不知道的语法
final int s = () -> {
try {
return Files.size(path);
}
catch (IOException e) {
return 0;
}
}.apply();
似乎问题是在C ++中没有函数调用操作符,因此必须有一个可以调用的命名成员函数。
答案 0 :(得分:5)
您可以执行此操作,但需要将匿名lambda显式转换为正确的类型。那是因为你需要将lambda的类型强制转换为特定的功能接口,Java无法猜测最终的类型,例如:
final int x = ((IntSupplier)() -> 5).getAsInt();
如果您不喜欢它,则需要将其存储在变量中:
final IntSupplier xx = () -> 5;
final int x = xx.getAsInt();
答案 1 :(得分:3)
我无法将其声明为final,因为该值是可以抛出异常的函数的返回值
为什么这会阻止你最终成功?只需在try / catch之外声明变量。
final long s;
{
long ss;
try {
ss = Files.size(path);
} catch (IOException e) {
ss = 0;
}
s = ss;
}
请注意,您不能简单地使用s
代替ss
int try / catch,因为明确赋值的规则specifically:
如果满足以下所有条件,则在catch块之前肯定是未分配的:
- 在try块之后肯定是未分配的。
- ...
第一个条件不正确,所以其余条件都无关紧要。
答案 2 :(得分:3)
您的一个问题是Files.size(path)
实际上会返回long
,因此您需要将其分配给一个。
允许你这样做:
long size = ((LongSupplier) () -> {
try
{
return Files.size(path);
}
catch (IOException e)
{
return 0;
}
}).getAsLong();
所以你只需要转换lambda并使用一个逻辑行表达式。
我还要说一般功能应该按顺序
public long defaultOnException(LongSupplier s, long defaultValue) {
try {
return s.getAsLong();
} catch (Exception e) {
return defaultValue;
}
}
这将使您的客户端代码
long size = defaultOnException(() -> Files.size(path), 0);
答案 3 :(得分:1)
还有其他选择:
final int s = (IntSupplier) () -> {
try {
return Files.size(path);
} catch (IOException e) {
return 0;
}
}.getAsInt();
答案 4 :(得分:1)
使用泛型的另一种选择:
final long size = ((Supplier<Long>)(() -> {
try {
return Files.size(path);
} catch (IOException e) {
return 0L;
}
})).get();