草庐IT

java - 我应该对每个可能返回 null 的方法使用 Java8/Guava Optional 吗?

coder 2023-05-12 原文

Optional 用于表示可为空的对象,该类的一些用途包括

  • 作为方法返回类型,作为返回 null 的替代方法
    表示没有可用的值
  • 区分“未知”(例如,不存在于 map 中)
    和“已知没有值(value)”(存在于 map 中,具有值(value)
    Optional.absent())
  • 将可空引用包装在一个集合中以供存储
    支持 null(尽管还有其他几种方法可以做到这一点)
    应该先考虑)

  • 对于第一种情况,我是否需要在所有可为空的返回方法中返回 Optional?

    最佳答案

    那么 Optional 有什么问题呢?

    我们面临的问题是:JDK 8 Optional 对象会摆脱空引用吗?答案是否定的!因此,批评者立即质疑它的值(value):那么我们无法通过其他方式做到的有什么好处?

    不像像 SML 或 Haskell 这样的函数式语言从来没有空引用的概念,在 Java 中我们不能简单地摆脱历史上存在的空引用。这将继续存在,并且可以说它们有其适当的用途(仅举一个例子: three-valued logic )。

    我怀疑 Optional 类的意图是替换每一个可为空的引用,而是帮助创建更健壮的 API,其中只需读取方法的签名,我们就可以判断我们是否可以期待 optional 值,以及强制程序员相应地使用这个值。但最终,Optional 将只是另一个引用,并且受到语言中所有其他引用的相同弱点的影响(例如,您可以返回 null Optional)。很明显,Optional 不会挽救这一天。

    应该如何使用这些 optional 对象或它们在 Java 中是否有值(value)一直是 heated debate 的问题。在项目 lambda 邮件列表中。我们从批评者那里听到有趣的论点,例如:

  • 存在其他替代方案的事实(例如,像 IntelliJ 和 Eclipse IDE 这样的 IDES 支持一组 proprietary annotations 用于可空性的静态分析,JSR-305 带有@Nullable 和 @NonNull 等注释)。
  • 有些人希望它能像 functional world 一样可用,这在 Java 中并不完全可行,因为该语言缺少 SML 或 Haskell 等函数式编程语言中存在的许多特性(例如模式匹配)。
  • 其他人争论如何不可能retrofit preexisting code使用这个习语(例如 List.get(Object) 它将继续返回 null)。
  • 并且有些人提示缺乏对 optional 值的语言支持会产生一个潜在的场景,其中 Optional 可能是 used inconsistently在 API 中,这会造成不兼容性,这很像我们将与 Java API 的其余部分所具有的不兼容性,这些 Java API 无法 retrofit 以使用新的 Optional 类。这几乎是你的问题。在支持 optional 类型的语言中 like in Ceylonlike in Kotlin ,你甚至不会质疑这一点。
  • 一个令人信服的论点是,如果程序员在一个 optional 对象中调用 get 方法,如果它是空的,它将引发一个 NoSuchElementException,这与我们在使用 null 时遇到的问题几乎相同,只是有一个不同的异常。

  • 因此,似乎 Optional 的好处确实值得怀疑,并且可能仅限于提高可读性和强制执行公共(public)接口(interface)契约(Contract)。

    我确实相信采用这种 Optional 函数式惯用语可能会使我们的代码更安全,减少空引用问题的提示,从而更健壮,更不容易出错。当然,这不是一个完美的解决方案,因为毕竟 Optional 引用也可能被错误地设置为 null 引用,但我希望程序员坚持不传递 null 引用的约定,在期望 optional 对象的地方,几乎就像我们今天认为一个好的做法是不要在需要集合或数组的地方传递空引用,在这些情况下,正确的做法是传递空数组或集合。这里的重点是,现在我们在 API 中有一个机制,我们可以使用它来明确表示对于给定的引用,我们可能没有分配给它的值,并且用户被 API 强制验证。

    报价Google Guava's article关于 optional 对象的使用:

    “Besides the increase in readability that comes from giving null a name, the biggest advantage of Optional is its idiot-proof-ness. It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case”.



    所以,我想每个 API 设计者都可以选择他们想要在使用 Optional 方面走多远。

    一些有影响力的开发人员如 Stephen Colebourne 和 Brian Goetz 最近发表了一些关于正确使用 optional 的有趣文章。我特别发现以下有用:
  • Should Java Getters Return Optional
  • Java SE 8 Optional, a pragmatic approach
  • 关于java - 我应该对每个可能返回 null 的方法使用 Java8/Guava Optional 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18681243/

    有关java - 我应该对每个可能返回 null 的方法使用 Java8/Guava Optional 吗?的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

      总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

    3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

      我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

    4. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    5. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    6. ruby - 在 Ruby 中使用匿名模块 - 2

      假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

    7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

      我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

    8. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

      我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

    9. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    10. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

      我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

    随机推荐