如何将Optional转换为OptionalInt?

我有一个可Optional ,我想“转换”为OptionalInt ,但似乎没有一个简单的方法来做到这一点。

这就是我想要做的(人为的例子):

 public OptionalInt getInt() { return Optional.ofNullable(someString).filter(s -> s.matches("\\d+")).mapToInt(Integer::parseInt); } 

但是, mapToInt()方法没有。

我能想到的最好的是:

 return Optional.ofNullable(someString) .filter(s -> s.matches("\\d+")) .map(s -> OptionalInt.of(Integer.parseInt(s))) .orElse(OptionalInt.empty()); 

但这似乎不够优雅。

我是否遗漏了JDK中可以使转换更优雅的东西?

虽然代码不比普通的条件表达式更具可读性,但有一个简单的解决方案:

 public OptionalInt getInt() { return Stream.of(someString).filter(s -> s != null && s.matches("\\d+")) .mapToInt(Integer::parseInt).findAny(); } 

使用Java 9,您可以使用

 public OptionalInt getInt() { return Stream.ofNullable(someString).filter(s -> s.matches("\\d+")) .mapToInt(Integer::parseInt).findAny(); } 

如上所述,它既不比普通的条件表达式更具可读性,但我认为,它看起来仍然比使用mapOrElseGet更好(并且第一个变体不需要Java 9。

不,使用标准Java API无法以更优雅的方式实现它。 据我所知,没有计划在JDK-9中添加这样的方法。 我问Paul Sandoz关于添加mapToInt等等, 这是他的回答:

我:

提供一种在诸如mapToIntmapToObjOptional类型之间进行转换的方式不是一个好主意,就像在Stream API中完成一样吗?

保罗:

我不想去那里,我的回答是将Optional*转换为*Stream 。 添加mapOrElseGet的参数(注意原始变体返回U )是可以从中组合其他function。

所以你可能会有Java-9:

 return Optional.of(someString).filter(s -> s.matches("\\d+")) .mapOrElseGet(s -> OptionalInt.of(Integer.parseInt(s)), OptionalInt::empty); 

但仅此而已。

那是因为JDK作者坚持认为Optional类及其原始朋友(特别是原始朋友)不应该被广泛使用,它只是对方法的返回值执行一组有限操作的便捷方式,这可能会返回“缺少值”。 原始选项也是为了提高性能而设计的,但实际上它比使用流的重要性要低得多,因此使用Optional也很好。 使用Valhalla项目(希望能够到达Java-10),您将能够使用Optional并且OptionalInt将变得不必要。

在您的特定情况下,更好的方法是使用三元运算符:

 return someString != null && someString.matches("\\d+") ? OptionalInt.of(Integer.parseInt(someString)) : OptionalInt.empty(); 

我假设您要从方法返回OptionalInt 。 否则,为什么你需要它更令人质疑。

如果你有任何对象而不仅仅是一个String ,你可以暂时通过一个Stream

 public static  OptionalInt toOptionalInt(Optional optional, ToIntFunction func) { return optional.map(Stream::of).orElseGet(Stream::empty) .mapToInt(func) .findFirst(); } 

这个解决方案的优点是可以成为单行,这意味着您可以复制/粘贴方法的内容,只需将func更改为您想要的任何内容。 缺点是通过Stream来实现你想要的。 但如果你想要一个通用的单行,那就是它。

如果您想要一个实用工具方法,您可能更喜欢使用以下方法:

 public static  OptionalInt toOptionalInt(Optional optional, ToIntFunction func) { if (optional.isPresent()) { return OptionalInt.of(func.applyAsInt(optional.get())); } else { return OptionalInt.empty(); } } 

这是另一个不需要使用Stream的选项,并且每次都避免编译正则表达式:

 private static final Predicate IS_DIGITS = Pattern.compile("^\\d+$") .asPredicate(); public OptionalInt getInt() { return Optional.ofNullable(someString) .filter(IS_DIGITS) .map(Integer::valueOf) .map(OptionalInt::of) .orElseGet(OptionalInt::empty); } 

请注意,您需要锚定正则表达式,因为asPredicate()使用find()而不是matches()。

或者如果你正在使用Guava,你可以完全消除正则表达式并使用它们的Ints类:

 public OptionalInt getInt() { return Optional.ofNullable(someString) .map(Ints::tryParse) .map(OptionalInt::of) .orElseGet(OptionalInt::empty); }