Java 8 lambdas上的类型推断

Java 8 lambdas上的类型推断,java-8,Java 8,我一直在转换一些代码以使用Java8特性。在下面这个人为的例子中 Arrays.asList("1", "2", "3", "cheese", "5").stream().map(line -> { try { return Optional.of(Integer.parseInt(line)); } catch (NumberFormatException xep) { return Optional

我一直在转换一些代码以使用Java8特性。在下面这个人为的例子中

    Arrays.asList("1", "2", "3", "cheese", "5").stream().map(line -> {
        try {
            return Optional.of(Integer.parseInt(line));
        } catch (NumberFormatException xep) {
            return Optional.empty();
        }
    }).forEach( v -> 
        System.out.println(v.orElse(999))
    );
(目的是将某些字符串解析为int,并用999替换任何不可解析的值)

编译器报告

error: incompatible types: int cannot be converted to CAP#1
System.out.println(v.orElse(999))
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ? extends Object"
我尝试将999强制转换为整数或对象,但没有成功

看起来真正的问题是第一个lambda的推断返回类型是
可选的
,而不是
可选的

如果我这样做

    Arrays.asList("1", "2", "3", "cheese", "5").stream().map(line -> {
        Optional<Integer> ans;
        try {
            ans = Optional.of(Integer.parseInt(line));
        } catch (NumberFormatException xep) {
            ans = Optional.empty();
        }
        return ans;
    }).forEach( v -> 
        System.out.println(v.orElse(999))
    );
Arrays.asList(“1”、“2”、“3”、“cheese”、“5”).stream().map(行->{
可选ans;
试一试{
ans=可选的.of(整型.parseInt(行));
}捕获(NumberFormatException xep){
ans=可选的.empty();
}
返回ans;
}).forEach(v->
系统输出打印LN(v.orElse(999))
);

它工作得很完美,但没有那么优雅。有没有更好的方法将编译器“引导”到我想要的返回类型?

一个简单的修复方法是使用目标类型:

return Optional.<Integer> empty();

如果不需要成员变量ans,可以这样做:

try {
    return Optional.<Integer>of(Integer.parseInt(line));
} catch (NumberFormatException xep) {
    return Optional.<Integer>empty();
}
试试看{
返回可选的.of(Integer.parseInt(line));
}捕获(NumberFormatException xep){
返回可选的.empty();
}
类型推断是复杂的,而且有局限性,如果你真的想知道为什么在这种情况下会发生这种情况,你必须研究@Assilyas是正确的。我想根据番石榴效用提出一个替代方案:

与此不同,如果解析失败,此方法将返回null而不是引发异常

有了它和新的,你可以写:

Arrays.asList("1", "2", "3", "cheese", "5")
        .stream()
        .map(Ints::tryParse)
        .map(Optional::ofNullable)
        .forEach(v -> System.out.println(v.orElse(999)));
如前所述,您可以使用
return-Optional来修复它。空()

然而,最大的问题是,为什么在这里使用
可选

Stream.of("1", "2", "3", "cheese", "5").mapToInt(line -> {
    try {
        return Integer.parseInt(line);
    } catch (NumberFormatException xep) {
        return 999;
    }
}).forEach(System.out::println);
如果仍然要替换该值,则该工作是否会简单得多

如果您想对有效值执行一个操作(等效于<代码>可选.IFONE(消费者))< /C> >,您可以考虑当您期望无效值时,应优先检查捕获异常:

Stream.of("1", "2", "3", "cheese", "5")
      .filter(Pattern.compile("^[+-]?[0-9]{1,9}$").asPredicate())
      .mapToInt(Integer::parseInt)
      .forEach(System.out::println);

(我简化了正则表达式;它不接受所有可能的
int
值,但会拒绝所有无效值)

您是否尝试过使用
Optional.empty()
?在尝试中不需要目标类型block@assylias我刚试过,你说得对。奇怪的是,这里没有必要这样做……我想是因为(someInteger)
Optional.of显然是一个
Optional
,而编译器在没有更多上下文的情况下无法确定
Optional.empty()
的泛型。re:
OptionalInt
-这一点不错,尽管我只是使用了“int”作为一个简单的例子。我真正的问题是我根本记不住点后面的参数化类型-我尝试了
Optional.empty()
然后放弃了这种方法!“int”只是一个简单的例子,我的实际代码涉及在一个复杂的类似地图的对象中查找东西。但是,我不知道这个函数。很明显,它只是一个简单的例子,但是模式仍然适用:如果你在同一个流操作中使用<代码> ORSE/<代码>,你不需要一个<代码>可选的<代码>,你可以考虑对捕获进行预检查。就像一些值得思考的东西…
Stream.of("1", "2", "3", "cheese", "5")
      .filter(Pattern.compile("^[+-]?[0-9]{1,9}$").asPredicate())
      .mapToInt(Integer::parseInt)
      .forEach(System.out::println);