在lambdas上输入推断

时间:2014-10-15 09:48:41

标签: java-8

我一直在转换一些代码以使用Java 8功能。在以下人为的例子中

    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))
    );

(目的是将一些字符串解析为整数并用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转换为Integer或Object但没有成功。

似乎真正的问题是第一个lambda的推断返回类型是Optional<Object>而不是Optional<Integer>

如果我这样做

    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))
    );

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

4 个答案:

答案 0 :(得分:5)

一个简单的解决方法是使用目标类型:

return Optional.<Integer> empty();

另外我注意到您使用Integer.parseInt返回int,因此您还可以使用OptionalInt来解决您的问题并保存装箱操作:

try {
  return OptionalInt.of(Integer.parseInt(line));
} catch (NumberFormatException xep) {
  return OptionalInt.empty();
}

答案 1 :(得分:3)

作为said by assylias,您可以使用return Optional.<Integer> empty();修复此问题。

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

Stream.of("1", "2", "3", "cheese", "5").mapToInt(line -> {
    try {
        return Integer.parseInt(line);
    } catch (NumberFormatException xep) {
        return 999;
    }
}).forEach(System.out::println);

当您想要替换值时,工作会更简单。

如果您只想对有效值执行操作(相当于Optional.ifPresent(Consumer)),您可能会考虑在期望无效值时应首先检查捕获异常的规则:

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

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

答案 2 :(得分:1)

如果您不想要成员变量ans

,则可以执行此操作
try {
    return Optional.<Integer>of(Integer.parseInt(line));
} catch (NumberFormatException xep) {
    return Optional.<Integer>empty();
}

类型推断很复杂且有局限性,如果您真的想知道为什么会发生这种情况,那么您必须研究Java Language Specification

答案 3 :(得分:1)

@Assilyas answer是正确的。我想提出一个基于番石榴实用程序Ints::tryParse的替代方案:

  

Integer.parseInt(String)不同,如果解析失败,此方法将返回null而不是抛出异常

使用它和新的method references,你可以写:

Arrays.asList("1", "2", "3", "cheese", "5")
        .stream()
        .map(Ints::tryParse)
        .map(Optional::ofNullable)
        .forEach(v -> System.out.println(v.orElse(999)));