我一直在转换一些代码以使用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))
);
它完美无缺,但并不那么优雅。有没有更好的方法将编译器“引导”到我想要的返回类型?
答案 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)));