ChatGPT解决这个技术问题 Extra ChatGPT

用于可选

现在已经使用 Java 8 6 个多月了,我对新的 API 更改非常满意。我仍然不确定的一个领域是何时使用 Optional。我似乎在想要在任何可能是 null 的地方使用它之间摇摆不定,而在任何地方都没有。

似乎在很多情况下我都可以使用它,但我不确定它是否会增加好处(可读性/空安全性)或只会导致额外的开销。

所以,我有几个例子,我很想知道社区对 Optional 是否有益的想法。

- 当方法可以返回 null 时作为公共方法返回类型:

public Optional<Foo> findFoo(String id);

2 - 当参数可能是 null 时作为方法参数:

public Foo doSomething(String id, Optional<Bar> barOptional);

3 - 作为 bean 的可选成员:

public class Book {

  private List<Pages> pages;
  private Optional<Index> index;

}

4 - 在 Collections 中:

一般来说,我不认为:

List<Optional<Foo>>

添加任何东西 - 特别是因为可以使用 filter() 删除 null 值等,但是 Optional 在集合中有什么好的用途吗?

有什么我错过的案例吗?

我觉得有用的一种情况是,例如,如果你有一个替换映射。例如 Map<Character, String>。如果没有替换,我可以使用:Optional.ofNullable(map.get(c)).orElse(String.valueOf(c))。另请注意,Optional 是从 Guava 中窃取的,它的语法要好得多:Optional.fromNullable(map.get(c)).or(String.valueOf(c));
此外,在集合中,有些集合不允许空值!可选适合这里的账单。你可以.filter(Optional::absent)“空值”出来
@fge 平心而论,我认为 Optional 的概念实际上源于 FP。
@fge 用 getOrDefault() 表达不是更好吗?

R
Raedwald

Optional 的主要设计目标是为函数返回值提供一种方法,以指示没有返回值。请参阅this discussion这允许调用者继续一系列流畅的方法调用。

这与 OP 问题中的用例 #1 最接近。虽然,absence of a value 是比 null 更精确的表述,因为像 IntStream.findFirst 这样的东西永远不会返回 null。

对于用例 #2,将可选参数传递给方法,这可以使其工作,但它相当笨拙。假设您有一个方法,该方法接受一个字符串,后跟一个可选的第二个字符串。接受 Optional 作为第二个参数将产生如下代码:

foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());

即使接受 null 也更好:

foo("bar", "baz");
foo("bar", null);

可能最好的方法是拥有一个接受单个字符串参数并为第二个提供默认值的重载方法:

foo("bar", "baz");
foo("bar");

这确实有局限性,但它比上述任何一个都好得多。

用例 #3#4 在类字段或数据结构中包含 Optional 被视为对 API 的滥用。首先,它违背了顶部所述的 Optional 的主要设计目标。其次,它没有增加任何价值。

处理 Optional 中缺少值的方法有以下三种:提供替代值、调用函数以提供替代值或引发异常。如果要存储到字段中,则应在初始化或分配时执行此操作。如果您将值添加到列表中,正如 OP 所提到的,您可以选择简单地不添加值,从而“拉平”不存在的值。

我敢肯定,有人可能会想出一些人为的情况,他们真的想将 Optional 存储在字段或集合中,但总的来说,最好避免这样做。


我不同意#3。在存在或不存在值时要完成或不完成的事情时,将 Optional 作为字段会很有用。
我不明白为什么在内部执行 if(foo == null) 会比将字段存储为 optional 更好。而且我不明白为什么在内部显式调用 getOptionalFoo() 比将字段存储为 Optional 更好。此外,如果一个字段可以是 null 而一个字段不能是 null,为什么不通过将它们设为 Optional 或不设为 Optional 来与编译器进行沟通。
@StuartMarks,当我从所有 Optional<> 专家那里听到这句话时,这就是让我感到困惑的事情之一:“不要将 Optional<> 存储在字段中”。我真的很想理解这个建议的意义。考虑一个 DOM 树,其中一个节点可能有父节点,也可能没有父节点。在用例中,Node.getParent() 似乎会返回 Optional<Node>。我真的希望每次都存储一个 null 并包装结果吗?为什么?除了让我的代码看起来难看之外,这种额外的低效率给我带来了什么?
@GarretWilson 另一方面,假设您有 Optional<Node> getParent() { return Optional.ofNullable(parent); }。这看起来很昂贵,因为它每次都分配一个 Optional!但是如果调用者立即解包,对象的生命周期非常短,并且永远不会被提升出伊甸园空间。它甚至可能被 JIT 的逃逸分析消除。最重要的答案是“它取决于”一如既往,但在字段中使用 Optional 可能会增加内存使用并减慢数据结构的遍历速度。最后,我认为它会使代码混乱,但这是一个品味问题。
@GarretWilson 那么您为此写了博客吗?我会对此感兴趣:)
D
David Aldana

我玩游戏迟到了,但为了它的价值,我想加我的 2 美分。它们与 Stuart Marks's answer 很好地总结的 design goal of Optional 背道而驰,但我仍然相信它们的有效性(显然)。

随处使用可选

一般来说

我写了一个完整的 blog post about using Optional 但它基本上归结为:

尽可能设计你的课程以避免可选性

在所有剩余的情况下,默认应该是使用 Optional 而不是 null

可能会例外:局部变量返回值和私有方法的参数性能关键代码块(不要猜测,使用分析器)

局部变量

将值和参数返回给私有方法

性能关键代码块(不要猜测,使用分析器)

前两个异常可以减少 Optional 中包装和展开引用的感知开销。它们的选择使得 null 永远不能合法地将边界从一个实例传递到另一个实例。

请注意,这几乎不会允许集合中的 Optional 几乎与 null 一样糟糕。只是不要这样做。 ;)

关于你的问题

是的。如果重载不是选项,是的。如果没有其他方法(子类化、装饰......),是的。请不!

优点

这样做会减少代码库中 null 的存在,尽管它不会消除它们。但这甚至不是重点。还有其他重要的优点:

阐明意图

使用 Optional 清楚地表明该变量是可选的。任何阅读您的代码或使用您的 API 的人都会因为那里可能什么都没有,并且在访问该值之前需要进行检查这一事实而感到头疼。

消除不确定性

如果没有 Optionalnull 事件的含义就不清楚了。它可能是状态的合法表示(请参阅 Map.get)或实现错误,例如初始化丢失或失败。

随着 Optional 的持续使用,这种情况发生了巨大变化。在这里,null 的出现已经表明存在错误。 (因为如果允许缺少该值,则会使用 Optional。)这使得调试空指针异常变得更加容易,因为该 null 的含义问题已经得到解答。

更多空检查

现在没有任何东西可以是 null,这可以在任何地方强制执行。无论是使用注释、断言还是普通检查,您都不必考虑这个参数或那个返回类型是否可以为空。不能!

缺点

当然,没有灵丹妙药……

表现

将值(尤其是原语)包装到额外的实例中会降低性能。在紧密的循环中,这可能会变得明显甚至更糟。

请注意,编译器可能能够绕过 Optional 的短暂生命周期的额外引用。在 Java 10 中,value types 可能会进一步减少或消除惩罚。

序列化

Optional is not serializableworkaround 并不过分复杂。

不变性

由于 Java 中泛型类型的不变性,当将实际值类型推入泛型类型参数时,某些操作会变得很麻烦。 here (see "Parametric polymorphism") 给出了一个示例。


另一个缺点(或限制)是您无法对 Optional(xxx) 实例进行排序,尽管 Oracle 明确故意施加了该限制。我怀疑只有在特定情况下才应该使用这些类,并假设开发人员会做正确的事情。解决一个问题可能会导致另一个问题。如果以“不希望的”方式(例如,作为方法参数、集合、构造函数等)使用 Optional(xxx) 类时,也许应该有编译器警告来帮助开发人员,如果这真的不是预期用途?
关于 4、集合中的可选项:实际上有时将可选项存储在 List 中很有用。当某个元素位于某个索引处很重要,但该元素可以存在或不存在时,就是这种情况。 List<Optional<T>> 类型清楚地传达了这一点。另一方面,如果仅重要的是哪些对象是某个集合的成员,那么就没有意义了。
我认为用例 #2 仍然非常值得怀疑。传递给方法的 Optional 可以是 null。那么你得到了什么?现在你有两个检查要做。请参阅stackoverflow.com/a/31923042/650176
@DavidV 看看我给出的优势列表——它们也都适用于这种情况。此外,如果您全押 Optional(如果您愿意将其作为参数传递,则应该是这种情况)null 绝不是合法值。所以调用带有显式参数 null 的方法显然是一个错误。
“包装值(尤其是原始值)……”——例如 OptionalInt 呢?我不认为这比将 int 包装在(可为空的)Integer 中更糟糕。
C
Community

就个人而言,我更喜欢使用 IntelliJ's Code Inspection Tool 来使用 @NotNull@Nullable 检查,因为它们主要是编译时间(可以进行一些运行时检查),这在代码可读性和运行时性能方面具有较低的开销。它不像使用 Optional 那样严格,但是这种缺乏严谨性应该得到体面的单元测试的支持。

public @Nullable Foo findFoo(@NotNull String id);

public @NotNull Foo doSomething(@NotNull String id, @Nullable Bar barOptional);

public class Book {

  private List<Pages> pages;
  private @Nullable Index index;

}

List<@Nullable Foo> list = ..

这适用于 Java 5,无需包装和解包值。 (或创建包装对象)


嗯,这些是 IDEA 注释吗?我个人更喜欢 JSR 305 的 @Nonnull —— 与 FindBugs 一起使用;)
@fge 在这方面缺乏标准,但我相信这些工具通常是可配置的,您不必最终得到 @Nonnull @NotNull etc
是的,这是真的; IDEA (13.x) 提供了三种不同的选择......嗯,无论如何我总是最终使用 JSR 305
我知道这是旧的,但是关于注释和的讨论tools 值得一个指向 stackoverflow.com/questions/35892063/… 的链接——顺便说一句,它专门针对 Java 8 的情况。
…截至 2021 年 1 月 29 日,这应该被再次投票 192 次。
C
Community

我认为 Guava Optional 和他们的 wiki 页面说得很好:

除了通过给 null 命名来增加可读性之外,Optional 的最大优势是它的白痴性。如果您希望程序完全编译,它会迫使您积极考虑缺席的情况,因为您必须主动解开 Optional 并解决这种情况。 Null 使简单地忘记事情变得非常容易,虽然 FindBugs 有帮助,但我们认为它几乎不能解决这个问题。当您返回可能存在或不存在的值时,这一点尤其重要。您(和其他人)更有可能忘记 other.method(a, b) 可能返回 null 值,而不是您在实现 other.method 时可能忘记 a 可能为 null。返回 Optional 使调用者不可能忘记这种情况,因为他们必须自己解包对象才能编译他们的代码。 --(来源:Guava Wiki - 使用和避免 null - 有什么意义?)

Optional 增加了一些开销,但我认为它的明显优势是明确 表明对象可能不存在,并强制程序员处理这种情况。它可以防止有人忘记了心爱的 != null 检查。

2 为例,我认为要编写更明确的代码:

if(soundcard.isPresent()){
  System.out.println(soundcard.get());
}

if(soundcard != null){
  System.out.println(soundcard);
}

对我来说,Optional 更好地捕捉到了不存在声卡的事实。

我的 2¢ 关于您的积分:

public Optional findFoo(String id); - 我不确定。也许我会返回一个可能为空或包含 Foo 的 Result。这是一个类似的概念,但不是真正的 Optional。 public Foo doSomething(String id, Optional barOptional); - 我更喜欢@Nullable 和 findbugs 检查,如 Peter Lawrey 的回答 - 另见此讨论。您的书示例-我不确定是否会在内部使用 Optional ,这可能取决于复杂性。对于一本书的“API”,我会使用 Optional getIndex() 来明确指出这本书可能没有索引。我不会在集合中使用它,而不是在集合中允许空值

一般来说,我会尽量减少绕过 null 的次数。 (一旦被烧毁......)我认为值得找到适当的抽象并向其他程序员指出某个返回值实际代表什么。


你会写 soundcard.ifPresent(System.out::println)。调用 isPresent 在语义上与检查 null 相同。
对我来说问题是可选类型的东西仍然可以为空。因此,要真正做到完全安全,您必须执行 if(soundcard != null && soundcard.isPresent()) 之类的操作。虽然制作一个返回 Optional 并且也可以返回 null 的 api 是我希望没有人做过的事情。
“如果你想让你的程序完全编译,它会迫使你积极考虑缺席的情况,因为你必须积极地解开 Optional 并解决这种情况。”我不太确定它是如何强制执行此操作的,尽管我并不经常使用 Java。你能解释一下 Java 做了什么来强迫你打开并检查 !isPresent 案例只是为了编译吗?
我从来不明白:我们应该忘记 !=null,但我们永远不会忘记 .isPresent?
c
ctomek

Oracle tutorial

Optional 的目的不是替换代码库中的每个空引用,而是帮助设计更好的 API,在这些 API 中——只需读取方法的签名——用户就可以判断是否期望一个可选值。另外,Optional 强制你主动解包 Optional 来处理值的缺失;因此,您可以保护您的代码免受意外空指针异常的影响。


API 仅用于方法的返回部分,对吗?由于类型擦除,不应将选项用作参数?有时我在方法内部使用 Optional,从可空参数转换或作为从空构造函数参数初始化的字段......仍然试图弄清楚这是否比将其保留为空更有用 - 有人有什么想法吗?
@ycomp 您可以在 thisthat 问题中找到有关这些案例的大量信息。这些问题的答案比所问的要多得多,而且涵盖了其他案例。有关更多信息,请浏览更多或提出您自己的问题,因为您可能不会在这里得到太多关注。 ; )
u
user2023577

在 java 中,除非你沉迷于函数式编程,否则不要使用它们。

它们没有作为方法参数的地方(我保证有一天有人会给你一个空选项,而不仅仅是一个空的选项)。

它们对返回值有意义,但它们会邀请客户端类继续扩展行为构建链。

FP 和链在像 java 这样的命令式语言中几乎没有位置,因为它很难调试,而不仅仅是阅读。当你踩到线路时,你无法知道程序的状态和意图;您必须深入了解它(进入通常不属于您的代码,并且尽管有步骤过滤器,但仍有许多堆栈帧深)并且您必须向下添加大量断点以确保它可以在您添加的代码/lambda 中停止,而不是简单地走 if/else/call 琐碎的行。

如果您想要函数式编程,请选择除 java 之外的其他东西,并希望您有调试工具。


D
Dmitry Ginzburg

1 - 当方法可以返回 null 时作为公共方法返回类型:

这是一个 good article,它显示了用例 #1 的有用性。有这个代码

...
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            isocode = isocode.toUpperCase();
        }
    }
}
...

变成了这个

String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");

通过使用 Optional 作为相应 getter 方法的返回值。


在我看来,第一个示例比转换后的示例更具可读性。此外,第一个示例可能只有一个 if 语句而不是 3 个。
f
fge

这是一个有趣的用法(我相信)... 测试。

我打算对我的一个项目进行大量测试,因此我建立了断言;只有有些事情我必须验证,而有些事情我不需要。

因此,我构建了一些东西来断言并使用断言来验证它们,如下所示:

public final class NodeDescriptor<V>
{
    private final Optional<String> label;
    private final List<NodeDescriptor<V>> children;

    private NodeDescriptor(final Builder<V> builder)
    {
        label = Optional.fromNullable(builder.label);
        final ImmutableList.Builder<NodeDescriptor<V>> listBuilder
            = ImmutableList.builder();
        for (final Builder<V> element: builder.children)
            listBuilder.add(element.build());
        children = listBuilder.build();
    }

    public static <E> Builder<E> newBuilder()
    {
        return new Builder<E>();
    }

    public void verify(@Nonnull final Node<V> node)
    {
        final NodeAssert<V> nodeAssert = new NodeAssert<V>(node);
        nodeAssert.hasLabel(label);
    }

    public static final class Builder<V>
    {
        private String label;
        private final List<Builder<V>> children = Lists.newArrayList();

        private Builder()
        {
        }

        public Builder<V> withLabel(@Nonnull final String label)
        {
            this.label = Preconditions.checkNotNull(label);
            return this;
        }

        public Builder<V> withChildNode(@Nonnull final Builder<V> child)
        {
            Preconditions.checkNotNull(child);
            children.add(child);
            return this;
        }

        public NodeDescriptor<V> build()
        {
            return new NodeDescriptor<V>(this);
        }
    }
}

在 NodeAssert 类中,我这样做:

public final class NodeAssert<V>
    extends AbstractAssert<NodeAssert<V>, Node<V>>
{
    NodeAssert(final Node<V> actual)
    {
        super(Preconditions.checkNotNull(actual), NodeAssert.class);
    }

    private NodeAssert<V> hasLabel(final String label)
    {
        final String thisLabel = actual.getLabel();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is null! I didn't expect it to be"
        ).isNotNull();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is not what was expected!\n"
            + "Expected: '%s'\nActual  : '%s'\n", label, thisLabel
        ).isEqualTo(label);
        return this;
    }

    NodeAssert<V> hasLabel(@Nonnull final Optional<String> label)
    {
        return label.isPresent() ? hasLabel(label.get()) : this;
    }
}

这意味着断言真的只有在我想检查标签时才会触发!


佚名

Optional 类可让您避免使用 null 并提供更好的替代方案:

这鼓励开发人员检查是否存在以避免未捕获的 NullPointerException。

API 变得更好地记录,因为它可以看到,在哪里可以预期可能不存在的值。

Optional 为进一步处理对象提供方便的 API:isPresent()get(); orElse(); orElseGet(); orElseThrow(); map()filter(); flatmap()

此外,许多框架积极使用这种数据类型并从其 API 中返回它。


R
Raedwald

Optional has similar semantics to an unmodifiable instance of the Iterator design pattern

它可能引用也可能不引用对象(由 isPresent() 给出)

如果它确实引用了一个对象,则可以取消引用(使用 get())

但它不能前进到序列中的下一个位置(它没有 next() 方法)。

因此,请考虑在您之前可能考虑使用 Java Iterator 的上下文中返回或传递 Optional


G
Guildenstern

以下是您可以对 Optional<T> 的实例执行的一些方法:

地图

平面图

要不然

orElseThrow

ifPresentOrElse

得到

以下是您可以在 null 上执行的所有方法:

(没有了)

这实际上是一个苹果与橘子的比较:Optional<T> 是一个对象的实际实例(除非它是 null……但这可能是一个错误),而 null 是一个中止的对象。你可以用 null 做的就是检查它是否真的是 null。因此,如果您喜欢在对象上使用方法,Optional<T> 适合您;如果您想在特殊文字上进行分支,null 适合您。

null 不作曲。您根本无法编写只能分支的值。但 Optional<T> 确实作曲。

例如,您可以使用 map 创建任意长链“如果非空则应用此函数”。或者,您可以通过使用 ifPresent 有效地创建一个命令式代码块,如果它是非空的,则使用可选项。或者您可以使用 ifPresentOrElse 创建一个“if/else”,如果它是非空的,它会使用非空的可选项,否则会执行一些其他代码。

…在我看来,正是在这一点上,我们遇到了该语言的真正局限性:对于非常命令式的代码,您必须将它们包装在 lambda 中并将它们传递给方法:

    opt.ifPresentOrElse(
            string -> { // if present...
                // ...
            }, () -> { // or else...
                // ...
            }
    );

从风格上讲,这对某些人来说可能还不够好。

如果 Optional<T> 是我们可以进行模式匹配的代数数据类型,那将更加无缝(这显然是伪代码:

    match (opt) {
        Present(str) => {
            // ...
        }
        Empty =>{
            // ...
        }
    }

但无论如何,总而言之:Optional<T> 是一个非常健壮的空或当前对象。 null 只是一个标记值。

主观忽视的原因

似乎有一些人有效地认为效率应该决定一个人应该使用 Optional<T> 还是在 null 哨兵值上进行分支。这似乎有点像在一般情况下制定关于何时制作对象而不是原语的硬性规则。我认为使用 that 作为本次讨论的起点有点荒谬,因为您已经在使用一种语言,习惯上将对象从左到右,从上到下,所有时间(在我看来)。


o
oopexpert

我不认为 Optional 是可能返回空值的方法的一般替代品。

基本思想是:没有值并不意味着它在未来可能可用。这是 findById(-1) 和 findById(67) 之间的区别。

调用者的 Optionals 的主要信息是他可能不依赖给定的值,但它可能在某些时候可用。也许它会再次消失,然后再回来一次。这就像一个开/关开关。你有“选项”来打开或关闭灯。但是,如果您没有可以打开的灯,您将别无选择。

所以我发现在任何可能返回 null 的地方引入 Optionals 太麻烦了。我仍将使用 null,但仅限于受限制的区域,例如树的根、延迟初始化和显式查找方法。


L
Luiggi Mendoza

似乎 Optional 仅在 Optional 中的类型 T 是基本类型(如 intlongchar 等)时才有用。对于“真实”类,它对我来说没有意义,因为您可以使用null 值。

我认为它取自这里(或其他类似的语言概念)。

Nullable<T>

在 C# 中,这个 Nullable<T> 是很久以前引入的,用于包装值类型。


它实际上是对 Guava 的 Optional 的抄袭
@fge 好的,但是当它出现在 C#(2005,MS.NET 2.0)中时,我认为没有番石榴。而且......谁知道 C# 是从哪里得到的。
@fge “Ripoff of Guava's Optional”是一种有趣的说法,因为 Guava 人参与了讨论,提供了他们的经验,并且普遍支持 java.util.Optional
@fge 毫无疑问,Java 的 API 深受 Guava 的影响。我对听起来像是偷窃的“敲竹杠”提出了质疑。 Guava 人为 Java 8 贡献了很多有价值的想法。
你没有抓住重点。将使用可选而不是返回 null。它比可能抛出 NullPointerException 更安全。请参阅:oracle.com/technetwork/articles/java/…
T
Tom Gregory

1 - 当方法可以返回 null 时作为公共方法返回类型:

这是 Optional 的预期用例,如 JDK API docs 所示:

Optional 主要用作方法返回类型,其中明确需要表示“无结果”,并且使用 null 可能会导致错误。

Optional 代表以下两种状态之一:

它有值(isPresent 返回 true) 它没有值(isEmpty 返回 true)

因此,如果您有一个返回某事或不返回任何内容的方法,这就是 Optional 的理想用例。

这是一个例子:

Optional<Guitarist> findByLastName(String lastName);

此方法采用用于在数据库中搜索实体的参数。可能不存在这样的实体,因此使用 Optional 返回类型是一个好主意,因为它会强制调用该方法的任何人考虑空场景。这减少了 NullPointerException 的机会。

2 - 当参数可能为空时作为方法参数:

尽管技术上可行,但这不是 Optional 的预期用例。

让我们考虑您提出的方法签名:

public Foo doSomething(String id, Optional<Bar> barOptional);

主要问题是我们可以调用 doSomething,其中 barOptional 具有以下三种状态之一:

一个带有值的 Optional 例如 doSomething("123", Optional.of(new Bar()) 一个空 Optional 例如 doSomething("123", Optional.empty()) null 例如 doSomething("123", null)

这 3 个状态需要在方法实现中适当处理。

更好的解决方案是实现重载方法。

public Foo doSomething(String id);

public Foo doSomething(String id, Bar bar);

这使得 API 的使用者非常清楚要调用哪个方法,并且不需要传递 null

3 - 作为 bean 的可选成员:

给定您的示例 Book 类:

public class Book {
  private List<Pages> pages;
  private Optional<Index> index;
}

Optional 类变量与上面讨论的 Optional 方法参数存在相同的问题。它可以具有 3 种状态之一:存在、空或 null

其他可能的问题包括:

序列化:如果您实现 Serializable 并尝试序列化此类的对象,您将遇到 java.io.NotSerializableException,因为 Optional 不是为此用例设计的

转换为 JSON:当序列化为 JSON 时,可选字段可能会以不希望的方式映射,例如 {"empty":false,"present":true}。尽管如果您使用流行的 Jackson 库,它确实为这个问题提供了解决方案。

尽管存在这些问题,Oracle 自己还是在 2014 年发布 Java 8 Optional 时发布了 this blog post。它包含使用 Optional 作为类变量的代码示例。

public class Computer {
  private Optional<Soundcard> soundcard;  
  public Optional<Soundcard> getSoundcard() { ... }
  ...
}

但在接下来的几年中,开发人员找到了更好的替代方案,例如实现 getter 方法来创建 Optional 对象。

public class Book {
    private List<Pages> pages;
    private Index index;
    public Optional<Index> getIndex() {
        return Optional.ofNullable(index);
    }
}

这里我们使用 ofNullable 方法返回一个 Optional,如果 index 不为空,则返回一个值,否则为空 Optional

4 - 在集合中:

我同意创建 OptionalList(例如 List<Optional<Foo>>)不会添加任何内容。相反,如果该项目不存在,则不要将其包含在 List 中。


q
quantum

Java SE 8 引入了一个名为 java.util.Optional 的新类,

您可以创建一个空的 Optional 或具有 null 值的 Optional。

Optional<String> emptyOptional = Optional.empty(); 

这是一个具有非空值的 Optional:

String valueString = new String("TEST");
Optional<String> optinalValueString = Optional.of(valueString );

如果存在值,则做某事

现在您有了一个 Optional 对象,您可以访问可用的方法来显式处理值的存在或不存在。不必记住进行空检查,如下所示:

String nullString = null;
if (nullString != null) {
    System.out.println(nullString);
}

您可以使用 ifPresent() 方法,如下所示:

Optional<String> optinalString= null;
optinalString.ifPresent(System.out::println);

package optinalTest;

import java.util.Optional;

public class OptionalTest {
    public Optional<String> getOptionalNullString() {
        return null;
//      return Optional.of("TESt");
    }

    public static void main(String[] args) {

        OptionalTest optionalTest = new OptionalTest();

        Optional<Optional<String>> optionalNullString = Optional.ofNullable(optionalTest.getOptionalNullString());

        if (optionalNullString.isPresent()) {
            System.out.println(optionalNullString.get());
        }
    }
}

此复制粘贴旨在获得廉价声誉,但与OP的问题无关