通过直接评估lambda来初始化变量

时间:2017-12-22 14:28:05

标签: java lambda

我想知道是否有办法直接在定义的同一个表达式中调用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 ++中没有函数调用操作符,因此必须有一个可以调用的命名成员函数。

5 个答案:

答案 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();