为什么不将可选变量用于实例变量?

时间:2019-06-05 08:56:02

标签: java scala optional

我已经阅读了很多有关应该使用Optional的情况的信息。

我读过的很多页面都说Optional不应用于私有实例变量,而应由getter返回。

我本以为将私有实例变量作为可选变量仍然有用。如果有人查看我的代码,他们可以看到值可以为空,而不必检查文档以查看是否可以返回null。

在Scala中,从不使用null,只有在与Java互操作的情况下才使用null。如果值可以为null,建议始终使用可选值。这种方法对我来说更有意义。

这是一个提及它的页面:

https://blog.joda.org/2015/08/java-se-8-optional-pragmatic-approach.html

这是示例代码。

private final String addressLine;  // never null
private final String city;         // never null
private final String postcode;     // optional, thus may be null

// normal getters
public String getAddressLine() { return addressLine; }
public String getCity() { return city; }

// special getter for optional field
public Optional<String> getPostcode() {
  return Optional.ofNullable(postcode);
}

我唯一看到的优点是,如果您要序列化对象,则现在可以了,因为它没有在变量中存储可选内容。

缺点是,在检查getter的返回类型之前,您不知道邮政编码可以为null。如果您不熟悉该代码,则可能会错过此添加操作,从而扩展了类,从而导致空指针异常。

这是一个有关Scala的Option的问题。

When to use Option

为什么Java和Scala在可选选项如何使用方面有区别?

4 个答案:

答案 0 :(得分:9)

并非所有Java开发人员都同意您所描述的方法。请检查龙目岛的创建者post

我猜想在Java中使用Optional的另一种方法的原因是Java社区直到Java 8都没有它,因此大多数人习惯了 null 。一方面,许多新的API(例如findAny中的Stream)返回Optional,但仍有许多标准库方法仅返回 null ,因此您始终必须记住用Optional.ofNullable包装函数调用,或者检查值是否不为空。

Optional已添加到Java 8,但不鼓励将其用作类字段,因为Optional未实现Serializable(许多人将Java的序列化用作默认序列化引擎)框架或系统(如Akka,Spark,Kafka等)。

另一方面,Option与Scala标准库紧密绑定。 据我所知,没有Scala的标准库API返回 null ,但是返回Option,不建议在您的Scala代码中完全使用 null 。您甚至可以将您的项目配置为如果 null used,则编译失败。

Option也是Serializable,其通常的做法是将其用作可以为空的值的类字段。

如果您想在Java代码中使用类似的方法,请检查 Vavr 中的Option。它是可序列化的,因此可以安全地用作字段,并且还具有两个子类NoneSome(类似于Scala的Option),因此可以在Vavr的模式匹配中使用:< / p>

Match(option).of(
    Case($Some($()), "defined"),
    Case($None(), "empty")
);

答案 1 :(得分:5)

在Scala中,Option已紧密集成到该语言的API中。

  

代表可选值。 Option的实例是scala的实例。Some或对象None。   使用scala.Option实例的最惯用方式是将其视为集合或monad,并使用map,flatMap,filter或foreach。

从上面的引用中可以看到,这里没有null的解释,因为它应该用作mondad或集合。

在Java中,Optional用于将NullPointerException情况用于以下情况,从而使我们免于崩溃:

  

可能包含也可能不包含非null值的容器对象。如果存在值,则isPresent()将返回true,而get()将返回该值。

一种编程语言,它通过使用Kotlin来非常清楚地向用户显示变量是否可以为null,并且显示出编译错误:

var a: String = "abc"
a = null // compilation error

var b: String? = "abc"
b = null // ok
print(b)

答案 2 :(得分:3)

与Stream类似,Optional是一个迭代的«event»类,不适合用作“真实”对象中的字段。

然后就是无法序列化的缺点(可能会解决)。

但是我认为基数0和1的某些变量可能是可选。 就像 list 一样有效。使用List字段的趋势是(恕我直言),它最初不允许为空,而是始终具有(空​​)列表。

在相同的编码样式中,Optional确保仅使用安全访问,尤其是可以以链接样式进行映射:

Optional<TextField> t = ...

String s = t.map(t::getText).orElse("N/A");
Optional<String> u = t.map(t::getText);
t.ifPresent(s -> { ... });

特别是ifPresent确保不会意外地使用null。

可选是有价值的规范。

答案 3 :(得分:-1)

不对实例变量使用Optional的一个原因是Optional引用本身很容易成为null。这违反了Optional周围的隐含合同,即您永远都不应创建或遇到nullOptional的引用。

class Foo {
    Optional<Bar> bar;
}

Foo f = new Foo();
if (f.bar.isPresent()) { // NullPointerException
    ...
}

这是在Java中使用Optional字段创建类的最简单方法。从某种意义上说,这种语言鼓励您编写这样的代码。

另一方面,在Scala中,定义Foo的最简单方法是

case class Foo(bar: Option[Bar])

这很容易

case class Foo(bar: Option[Bar] = None)

两者都避免使用NPE。