如何将Optional转换为OptionalInt?

时间:2016-01-11 03:54:40

标签: java java-8 optional

我有Optional我希望“转换”为OptionalInt,但似乎没有一种简单的方法可以做到这一点。

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

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

但是,mapToInt()没有Optional方法。

我能想到的最好的是:

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

但这似乎不够优雅。

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

5 个答案:

答案 0 :(得分:5)

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

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。

答案 1 :(得分:2)

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

我:

  

提供一种方式并不是一个好主意   在Optional类型之间转移,例如mapToIntmapToObj等,   喜欢在Stream API中完成吗?

保罗:

  

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

所以你可能会有Java-9:

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

但仅此而已。

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

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

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

我假设您要从方法中返回OptionalInt。否则,为什么你需要它会更加值得怀疑。

答案 2 :(得分:1)

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

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

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

如果您需要实用程序方法,您可能更喜欢使用以下内容:

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

答案 3 :(得分:0)

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

private static final Predicate<String> 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);
}

答案 4 :(得分:0)

这就是我将Optional<String>转换为OptionalInt

的方式
OptionalInt lastSeenId = Optional.of("123").map(Integer::parseInt).map(OptionalInt::of).orElseGet(OptionalInt::empty);