如何将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
等等, 这是他的回答:
我:
提供一种在诸如
mapToInt
,mapToObj
等Optional
类型之间进行转换的方式不是一个好主意,就像在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 super T> func) { return optional.map(Stream::of).orElseGet(Stream::empty) .mapToInt(func) .findFirst(); }
这个解决方案的优点是可以成为单行,这意味着您可以复制/粘贴方法的内容,只需将func
更改为您想要的任何内容。 缺点是通过Stream来实现你想要的。 但如果你想要一个通用的单行,那就是它。
如果您想要一个实用工具方法,您可能更喜欢使用以下方法:
public static OptionalInt toOptionalInt(Optional optional, ToIntFunction super T> 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); }