JAVA8系列教程-Optionals
我们所有人都必须NullPointerException
在我们的应用程序中遇到过。当您尝试利用尚未初始化的对象引用,使用null初始化或根本不指向任何实例的对象引用时,会发生此异常。NULL仅表示“不存在值”。罗马人很可能只是一个人,没有遇到这个空洞的问题,而是从I,II,III开始计数(不为零)。也许,他们无法模拟市场上苹果的缺乏。[:-)]
“我称之为我十亿美元的错误。” – CAR Hoare爵士,关于他的无效参考文献的发明
在本文中,我将讨论此特定用例的Java 8功能之一,即Optional
。为了清楚和区分多个概念,本文分为多个部分。
讨论要点1)什么是空值?
2)仅返回null有什么问题?
3)Java 8 Optionals如何提供解决方案?
a)创建可选对象
b)如果存在
值,则执行
某些
操作c)默认值/ 不存在值和操作d)拒绝某些值使用过滤器方法4)可选里面的东西使其起作用?
5)可选试图解决什么?
6)Optional不尝试解决的问题是什么?
7)应该如何使用可选的?
8)结论
1)什么是空值?
在Java中,我们使用引用类型来访问对象,并且当我们没有特定的对象来指向我们的引用时,则将此类引用设置为null表示不存在值。对?
null的使用是如此普遍,以至于我们很少对此多加思考。例如,对象的字段成员会自动初始化为null,程序员通常在没有初始值可给它们的情况下将引用类型初始化为null,并且通常,每次我们不知道或不知道时,都会使用null没有参考价值。
2)仅返回null有什么问题?
通常,API设计人员将描述性的Java文档放入API中,并在其中提到API可以返回空值,在这种情况下可以返回null。现在,问题在于API的调用者可能由于某种原因而错过了阅读javadoc的时间,而忘记了处理null的情况。将来肯定会是一个错误。
并且相信我,这经常发生,并且是空指针异常的主要原因之一,尽管不是唯一的原因。因此,在这里上一课,当您第一次使用它时,请务必先阅读它的Java dcos(…至少是[[-]])。
现在我们知道在大多数情况下null是一个问题,什么是最好的处理方式?
一个好的解决方案是始终使用一些value初始化对象引用,而永远不要使用null 初始化。这样,您将永远不会遇到NullPointerException
。很公平。但实际上,我们始终没有默认值作为参考。那么,这些案件应该如何处理?
上述问题在许多方面都是正确的。好吧,Java 8Optionals
是这里的答案。
3)Java 8 Optionals如何提供解决方案?
可选的是用非空值替换可空T引用的方法。Optional可以包含非空T引用(在这种情况下,我们称该引用为“存在”),也可以不包含任何内容(在这种情况下,我们称该引用为“不存在”)。
请记住,从来没有说过可选的“ contain null”。
Optional<Integer> canBeEmpty1 = Optional.of( 5 ); canBeEmpty1.isPresent(); // returns true canBeEmpty1.get(); // returns 5 Optional<Integer> canBeEmpty2 = Optional.empty(); canBeEmpty2.isPresent(); // returns false |
您还可以将Optional视为包含值或不包含值的单值容器。
重要的是要注意,Optional类的目的不是替换每个单个空引用。相反,它的目的是帮助设计更易于理解的API,以便仅通过读取方法的签名即可知道是否可以期望一个可选值。这迫使您从Optional中获取值并对其进行处理,同时处理Optional为空的情况。好吧,这正是空引用/返回值的解决方案,最终导致NullPointerException
。
以下是一些示例,以了解有关应如何在应用程序代码中创建和使用Optional的更多信息。
a)创建可选对象
创建Optional的主要方法有3种。
i)使用Optional.empty()创建空的可选。
Optional<Integer> possible = Optional.empty(); |
ii)使用Optional.of()创建具有默认非空值的可选项。如果在of()中传递null,则立即引发NullPointerException。
Optional<Integer> possible = Optional.of( 5 ); |
iii)使用Optional.ofNullable()创建一个可选对象,该对象可以包含空值。如果parameter为null,则生成的Optional对象将为空(请记住,该值不存在;请勿将其读取为null)。
Optional<Integer> possible = Optional.ofNullable( null ); //or Optional<Integer> possible = Optional.ofNullable( 5 ); |
b)如果存在可选值,则执行某些操作
您得到的Optional
对象是第一步。现在让我们在检查其内部是否包含任何值之后使用它。
Optional<Integer> possible = Optional.of( 5 ); possible.ifPresent(System.out::println); |
您也可以将以下代码重写为上面的代码。但是,这不是推荐的用法,Optional
因为它与嵌套null检查相比没有太大的改进。它们看起来确实完全相似。
if (possible.isPresent()){ System.out.println(possible.get()); } |
如果Optional
对象为空,则不会打印任何内容。
c)默认/不存在的值和动作
如果确定操作结果为空,则编程中的典型模式是返回默认值。通常,您可以使用三元运算符。但是使用Optionals,您可以编写如下代码:
//Assume this value has returned from a method Optional<Company> companyOptional = Optional.empty(); //Now check optional; if value is present then return it, //else create a new Company object and retur it Company company = companyOptional.orElse( new Company()); //OR you can throw an exception as well Company company = companyOptional.orElseThrow(IllegalStateException:: new ); |
d)使用过滤方法拒绝某些值
通常,您需要在对象上调用方法并检查一些属性。例如,在下面的示例代码中,检查公司是否设有“财务”部门;如果有,请打印出来。
Optional<Company> companyOptional = Optional.empty(); companyOptional.filter(department -> "Finance" .equals(department.getName()) .ifPresent(() -> System.out.println( "Finance is present" )); |
所述过滤器的方法需要一个谓词作为参数。如果Optional
对象中存在一个值并且该值与谓词匹配,则filter方法将返回该值;否则,该方法将返回该值。否则,它返回一个空Optional
对象。如果在Stream
接口上使用了filter方法,则可能已经看到了类似的模式。
很好,这段代码看起来更接近问题陈述,并且没有妨碍我们进行冗长的null检查!
哇!!从编写痛苦的嵌套null检查到编写可组合,可读且可更好地免受null指针异常保护的声明性代码,我们已经走了很长一段路。
4)Optional内部有什么使它起作用?
如果打开Optional.java的源代码,则会发现Optional持有的值定义为:
/** * If non-null, the value; if null, indicates no value is present */ private final T value; |
并且,如果您定义一个空的Optional,则它声明如下。static关键字可确保每个VM通常仅存在一个空实例。
/** * Common instance for {@code empty()}. */ private static final Optional<?> EMPTY = new Optional<>(); |
默认的no-args构造函数是define private,因此您不能创建Optional的实例,除了上面给出的3种方法。
当创建一个Optional时,下面的调用将在末尾发生,并将传递的值分配给'value'属性。
this .value = Objects.requireNonNull(value); |
当您尝试从Optional获取值时,如果NoSuchElementException
引发了其他情况,则将获取值:
public T get() { if (value == null ) { throw new NoSuchElementException( "No value present" ); } return value; } |
同样,在Optional类中定义的其他函数仅在'value'属性周围运行。浏览Optional.java的源代码以获取更多信息。
5)可选试图解决什么?
Optional
通过增加考虑到有时缺少返回值来构建更具表现力的API的可能性,尝试减少Java系统中空指针异常的数量。如果Optional
从一开始就存在,那么今天大多数库和应用程序可能会更好地处理缺少的返回值,从而减少了空指针异常的数量以及总体上的错误总数。
通过使用Optional
,用户不得不考虑特殊情况。除了为null命名而提高了可读性之外,Optional的最大优点是它的防白痴能力。如果您要完全编译程序,它会迫使您积极考虑不存在的情况,因为您必须积极展开Optional并解决该失败情况。
6)Optional不尝试解决的问题是什么?
可选并不是避免所有类型的空指针的机制。例如,仍然必须测试方法和构造函数的强制输入参数。
像使用null时一样,Optional不能帮助传达缺失值的含义。因此,该方法的调用者仍然必须检查API的javadoc以了解缺少Optional的含义,以便正确处理它。
请注意,这Optional
并不是要在以下情况下使用,因为它可能不会给我们带来任何好处:
- 在域模型层中(不可序列化)
- 在DTO中(不可序列化)
- 在方法的输入参数中
- 在构造函数参数中
7)应该如何使用可选的?
几乎所有时候都应该使用Optional 作为可能不返回值的函数的返回类型。
这是来自OpenJDK邮件列表的报价:
JSR-335 EG非常强烈地认为Optional不应仅用于支持option-return成语。
有人建议甚至将其重命名为“ OptionalReturn ”。
从本质上讲,这意味着Optional
仅当它们确实达到目的时才应将其用作某些服务,存储库或实用程序方法的返回类型。
8)结论
在本文中,我们了解了如何采用新的Java SE 8java.util.Optional
。Optional的目的不是替换代码库中的每个单个null引用,而是帮助您设计更好的API,在这些API中,仅通过读取方法的签名,用户就可以知道是否期望可选值并适当地对其进行处理。 。
这就是这个很棒的功能。在评论部分让我知道您的想法。
- 本文标签: 其他
- 本文链接: https://www.v8en.com/article/246
- 版权声明: 本文由SIMON原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权