好的,在我开始解释我的问题之前,我想让你知道我知道null
背后的设计理念,并且不打算在字段或集合中使用,但我编写了很多Kotlin目前非常不喜欢使用ConnectionBox
。
所以我在虚幻引擎中有一个基于节点的编辑器,每个节点都有Connection
个es,它们可以是空闲的,也可以被ConnectionBox
占用。
因此,有不同的方法可以表达这一点,即使用将每个Connection
映射到Map<ConnectionBox, Connection> connectionEndPoints;
的地图,例如:
Connection
如果null
是免费的,则和ConnectionBox
可以是null
。我不喜欢这样,因为其他开发人员不知道此Map的功能,并且它可能会返回现有ConnectionBox
的{{1}}。
所以我很想使用:
Map<ConnectionBox, Optional<Connection>> connectionEndPoints;
显示更好的打算,你甚至可以读出它:
“此ConnectionBox
可能附加了Connection
。”
我的问题是:为什么我不应该这样做,即使它更清楚地表明意图并阻止NPE
。每个SO帖子和每个博客文章都说这是糟糕的风格,甚至编译器都说我不应该发出警告。
根据要求,这里有一个SO线程,不鼓励使用Optional
作为字段或集合值:Uses for Optional
这是警告(因为事实证明它是来自IntelliJ的警告):
警告:可选用作字段{fieldName}的类型
好的,建议Connection
引用应该在ConnectioBox
内,问题只是转移。
为什么:
class ConnectionBox {
Optional<Connection> connection;
...
比
更糟糕class ConnectionBox {
Connection connection; //may be null
...
除非我发表评论,否则您无法看到自己可能会遇到NPE
并且我不喜欢解释可以解释自己的代码的评论。
答案 0 :(得分:2)
在观看了Stuart Marks(他在Oracle的JDK小组的核心图书馆团队工作)与Devoxx 2016讨论"Optional – The Mother of All Bikesheds"之后,你应该跳到54:04:
为什么不在字段中使用可选项?
- 更多的是样式问题,而不是正确性问题
- 通常有更好的方法来模拟缺席值
- 在字段中使用Optional通常源于消除可空字段的盲目愿望
- 请记住,消除空值不是Optional
的目标- 在字段中使用可选...
- 为每个字段创建另一个对象
- 在每个字段读取
时从内存中引入依赖负载- 使您的代码混乱
- 有什么好处?链方法的能力?
根据IntelliJ的检查员(首选项&gt;编辑器&gt;检查&gt;'可选'用作字段或参数类型):
可选项旨在为库方法返回类型提供有限的机制,其中需要一种明确的方式来表示“无结果”。如果类需要
java.util.Optional
,而Serializable
不是java.util.Optional
,则使用类型为@Nullable
的字段也会出现问题。
如果您必须serialize,这也适用于集合。此外,看看这些链接:
Java 8 Optional: What's the Point?
所以回顾一下 - 为了摆脱NullPointerExceptions,我们有一个新的类:
- 抛出NullPointerExceptions
- 本身可以为null,导致NullPointerException
- 增加堆大小
- 使调试更加困难
- 使序列化对象(比如外部客户端的XML或JSON)更加困难
Why java.util.Optional is broken
最后的讽刺是,通过试图阻止无效,这个类的作者实际上鼓励使用它。我确信有一些人会试图简单地从函数中返回null,以“避免创建一个不必要且昂贵的可选引用”,而不是使用正确的类型和组合器。
如果您关心可读性,还可以使用class ConnectionBox {
@Nullable
Connection connection;
// ...
}
(Eclipse以及IntelliJ中提供):
class ConnectionBox {
Connection connection;
// ...
Optional<Connection> getConnection() {
return Optional.ofNullable(connection);
}
}
或者,您可以创建一个可选的getter:
static void Main(string[] args)
{
bool bMethod1 = Metthod1();
bool bMethod2 = Metthod2();
bool bMethod3 = Metthod3();
if (!bMethod1 || !bMethod2 || !bMethod3)
{
//RollBack
}
}