ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
### [Optional 对象操作](https://lingcoder.gitee.io/onjava8/#/book/14-Streams?id=optional-%e5%af%b9%e8%b1%a1%e6%93%8d%e4%bd%9c) 当我们的流管道生成了**Optional**对象,下面 3 个方法可使得**Optional**的后续能做更多的操作: * `filter(Predicate)`:对**Optional**中的内容应用**Predicate**并将结果返回。如果**Optional**不满足**Predicate**,将**Optional**转化为空**Optional**。如果**Optional**已经为空,则直接返回空**Optional**。 * `map(Function)`:如果**Optional**不为空,应用**Function**于**Optional**中的内容,并返回结果。否则直接返回**Optional.empty**。 * `flatMap(Function)`:同`map()`,但是提供的映射函数将结果包装在**Optional**对象中,因此`flatMap()`不会在最后进行任何包装。 以上方法都不适用于数值型**Optional**。一般来说,流的`filter()`会在**Predicate**返回`false`时移除流元素。而`Optional.filter()`在失败时不会删除**Optional**,而是将其保留下来,并转化为空。下面请看代码示例: ~~~ // streams/OptionalFilter.java import java.util.*; import java.util.stream.*; import java.util.function.*; class OptionalFilter { static String[] elements = { "Foo", "", "Bar", "Baz", "Bingo" }; static Stream<String> testStream() { return Arrays.stream(elements); } static void test(String descr, Predicate<String> pred) { System.out.println(" ---( " + descr + " )---"); for(int i = 0; i <= elements.length; i++) { System.out.println( testStream() .skip(i) .findFirst() .filter(pred)); } } public static void main(String[] args) { test("true", str -> true); test("false", str -> false); test("str != \"\"", str -> str != ""); test("str.length() == 3", str -> str.length() == 3); test("startsWith(\"B\")", str -> str.startsWith("B")); } } ~~~ 输出结果: ~~~ ---( true )--- Optional[Foo] Optional[] Optional[Bar] Optional[Baz] Optional[Bingo] Optional.empty ---( false )--- Optional.empty Optional.empty Optional.empty Optional.empty Optional.empty Optional.empty ---( str != "" )--- Optional[Foo] Optional.empty Optional[Bar] Optional[Baz] Optional[Bingo] Optional.empty ---( str.length() == 3 )--- Optional[Foo] Optional.empty Optional[Bar] Optional[Baz] Optional.empty Optional.empty ---( startsWith("B") )--- Optional.empty Optional.empty Optional[Bar] Optional[Baz] Optional[Bingo] Optional.empty ~~~ 即使输出看起来像流,要特别注意`test()`中的 for 循环。每一次的for循环都重新启动流,然后跳过for循环索引指定的数量的元素,这就是流只剩后续元素的原因。然后调用`findFirst()`获取剩余元素中的第一个元素,并包装在一个`Optional`对象中。 **注意**,不同于普通 for 循环,这里的索引值范围并不是`i < elements.length`, 而是`i <= elements.length`。所以最后一个元素实际上超出了流。方便的是,这将自动成为**Optional.empty**,你可以在每一个测试的结尾中看到。 同`map()`一样 ,`Optional.map()`执行一个函数。它仅在**Optional**不为空时才执行这个映射函数。并将**Optional**的内容提取出来,传递给映射函数。代码示例: ~~~ // streams/OptionalMap.java import java.util.Arrays; import java.util.function.Function; import java.util.stream.Stream; class OptionalMap { static String[] elements = {"12", "", "23", "45"}; static Stream<String> testStream() { return Arrays.stream(elements); } static void test(String descr, Function<String, String> func) { System.out.println(" ---( " + descr + " )---"); for (int i = 0; i <= elements.length; i++) { System.out.println( testStream() .skip(i) .findFirst() // Produces an Optional .map(func)); } } public static void main(String[] args) { // If Optional is not empty, map() first extracts // the contents which it then passes // to the function: test("Add brackets", s -> "[" + s + "]"); test("Increment", s -> { try { return Integer.parseInt(s) + 1 + ""; } catch (NumberFormatException e) { return s; } }); test("Replace", s -> s.replace("2", "9")); test("Take last digit", s -> s.length() > 0 ? s.charAt(s.length() - 1) + "" : s); } // After the function is finished, map() wraps the // result in an Optional before returning it: } ~~~ 输出结果: ~~~ ---( Add brackets )--- Optional[[12]] Optional[[]] Optional[[23]] Optional[[45]] Optional.empty ---( Increment )--- Optional[13] Optional[] Optional[24] Optional[46] Optional.empty ---( Replace )--- Optional[19] Optional[] Optional[93] Optional[45] Optional.empty ---( Take last digit )--- Optional[2] Optional[] Optional[3] Optional[5] Optional.empty ~~~ 映射函数的返回结果会自动包装成为**Optional**。**Optional.empty**会被直接跳过。 **Optional**的`flatMap()`应用于已生成**Optional**的映射函数,所以`flatMap()`不会像`map()`那样将结果封装在**Optional**中。代码示例: ~~~ // streams/OptionalFlatMap.java import java.util.Arrays; import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; class OptionalFlatMap { static String[] elements = {"12", "", "23", "45"}; static Stream<String> testStream() { return Arrays.stream(elements); } static void test(String descr, Function<String, Optional<String>> func) { System.out.println(" ---( " + descr + " )---"); for (int i = 0; i <= elements.length; i++) { System.out.println( testStream() .skip(i) .findFirst() .flatMap(func)); } } public static void main(String[] args) { test("Add brackets", s -> Optional.of("[" + s + "]")); test("Increment", s -> { try { return Optional.of( Integer.parseInt(s) + 1 + ""); } catch (NumberFormatException e) { return Optional.of(s); } }); test("Replace", s -> Optional.of(s.replace("2", "9"))); test("Take last digit", s -> Optional.of(s.length() > 0 ? s.charAt(s.length() - 1) + "" : s)); } } ~~~ 输出结果: ~~~ ---( Add brackets )--- Optional[[12]] Optional[[]] Optional[[23]] Optional[[45]] Optional.empty ---( Increment )--- Optional[13] Optional[] Optional[24] Optional[46] Optional.empty ---( Replace )--- Optional[19] Optional[] Optional[93] Optional[45] Optional.empty ---( Take last digit )--- Optional[2] Optional[] Optional[3] Optional[5] Optional.empty ~~~ 同`map()`,`flatMap()`将提取非空**Optional**的内容并将其应用在映射函数。唯一的区别就是`flatMap()`不会把结果包装在**Optional**中,因为映射函数已经被包装过了。在如上示例中,我们已经在每一个映射函数中显式地完成了包装,但是很显然`Optional.flatMap()`是为那些自己已经生成**Optional**的函数而设计的。