1
Jooooooooo 2021-01-25 15:01:32 +08:00
optional 强制判空, 还是有点用的
|
2
finab 2021-01-25 15:03:00 +08:00
习惯就还挺好的,optional 用习惯了后,发现挺舒服的,现在写没有 optional 特性的语言代码时都有点不习惯了
|
3
Jirajine 2021-01-25 15:05:26 +08:00 via Android 2
optional 存在的意义就是通过静态检查强制你处理为空时的情况。rust 也是这样做的。
|
4
fishCulturer 2021-01-25 15:05:38 +08:00
感觉判空这块还是工具包香
|
5
yuhuan66666 2021-01-25 15:06:46 +08:00
强制判空,怕你忘,对于多人协作开发,返回值加一个,挺好用的,我就喜欢用
|
6
sampeng 2021-01-25 15:12:05 +08:00 3
自己水平不够就认为没用?
感情你工作这么久从来没有或者没见过空指针? 现在从语言层面消灭空指针不都是 optional 的方式么? |
7
guyeu 2021-01-25 15:12:27 +08:00
问好语法糖和 Optional 又有什么本质区别呢?我觉得 Optional 最重要的意义是提高空返回值的成本,促使程序员使用有意义的返回值代替空,只有在空有意义的情况下才返回空,这样一来,现有的绝大多数的判空就不需要写了。
|
8
mxT52CRuqR6o5 2021-01-25 15:13:05 +08:00
你这不是 Optional 的问题,而是没有类似 Kotlin 中 Safe Calls 运算符的问题
|
9
sampeng 2021-01-25 15:14:13 +08:00
rust 哪门子的底层语言设计上做的改进。本质上 rust 的 Option 和 Optional 的实现有任何区别不成?只是 java 有历史包袱不能让你强制所有地方都用 optional 或者具体的值。rust 没这个负担,所以可以提供?的语法糖。在没有?语法糖的时候 rust 判断 option 也是写的很恶心的
|
10
huifer 2021-01-25 15:17:46 +08:00
private static Optional optional(){
return null; } public static void main(String[] args) { System.out.println(optional().isPresent()); } 使用的时候是否要对 `Optional` 判空呢? |
11
yuanxiaosong 2021-01-25 15:19:30 +08:00 6
随便百度了一个例子,可以试试改成不用 Optional 需要多少代码,少用 isPresent 和 get,多使用 map 、filter 、orElse,多使用 Function 、Supplier 和 Consumer 来解决问题:
Optional .ofNullable(someVariable) .map(this::findOtherObject) .filter(this::isThisOtherObjectStale) .map(this::convertToJson) .map(String::trim) .orElseThrow(() -> new RuntimeException("something went horribly wrong.")); 代码来源: https://www.jdon.com/52008 |
12
11wangyaoda 2021-01-25 15:24:32 +08:00 via Android 5
optional 最有意思的是 optional 自己有可能是 null
|
13
chendy 2021-01-25 15:28:36 +08:00
如果是接 orThrow 直接报错的情况还好
如果是接 orElse(null) 就显得很多余了 |
14
yazinnnn 2021-01-25 15:36:09 +08:00
Optional.ofNullable(T value)
用这个啊 如果你调用的 api 的编写人员不靠谱,那就让他别返回 Optional 了 |
15
tamer 2021-01-25 15:41:30 +08:00
@yuanxiaosong 这种例子其实很有误导性,
实际业务代码往往并不会简单的是连续的方法引用 |
16
LGA1150 2021-01-25 15:50:47 +08:00
@huifer @11wangyaoda 这样写 IDE 会有警告
|
17
arloor 2021-01-25 16:00:51 +08:00 via Android
给你,你说鸡肋
不给,你说缺失 仔细看看自己写的代码,照样都是 trade off (点开看,原来不只是黑大 java,还要吹 rust,应该是最喜欢的编程语言评选又开始评选了 |
18
xuanbg 2021-01-25 16:04:49 +08:00
很少用,一般都是直接判空。某些场景在实体类的 get 方法中处理值为空。
|
19
sakura1 2021-01-25 16:06:16 +08:00
这个问题感觉源自 null 的存在本身
|
20
Takamine 2021-01-25 16:07:00 +08:00 via Android
建议可以看看《 Java 核心技术卷 2 》 Optional 的部分,比结合 flatMap 使用的。
|
21
Takamine 2021-01-25 16:09:07 +08:00 via Android
比如*。
我觉得这个是函数式编程新进来的,不能拆开来看。 |
22
lemon94 2021-01-25 16:18:31 +08:00
swift 也有 optional,是繁琐了点,但解决 npe 问题还算有成效。
|
23
hantsy 2021-01-25 16:21:18 +08:00 3
Optional 太常用了。
思想固化,从来没用过 Java 8 的人才会去判断是不是 NULL,把好好的代码打回 Java 8 以前。 Optional 在 Java 8 改进了很多,和 Stream 一样,用于 Pipeline 类似操作,很方便。 https://github.com/hantsy/spring-webmvc-jwt-sample/blob/master/src/main/java/com/example/demo/DemoApplication.java#L34-L45 ```java @Bean public AuditorAware<User> auditor() { return () -> Optional.ofNullable(SecurityContextHolder.getContext()) .map(SecurityContext::getAuthentication) .filter(Authentication::isAuthenticated) .map(Authentication::getPrincipal) .map(User.class::cast); } ``` 再说了以 Spring 5 为基础,核心代码还有其 Spring 生态(比如 Spring Data ) API 都是对 Java 8 API 优化,Optional 在 Spring 中已经是随处可见,难道还没升级 Spring 5 ? |
24
assiadamo 2021-01-25 16:22:37 +08:00
jdk 的 Optional 无法序列化且对 GC 有压力,有个好用的库叫 vavr 可以替代
|
25
assiadamo 2021-01-25 16:23:21 +08:00 1
比如 netty 就不用 Optional
|
26
hantsy 2021-01-25 16:27:03 +08:00
如果用过 Spring WebFlux ( ReactiveStreams API )就更不用说了,流式操作是必须的。
https://github.com/hantsy/spring-reactive-jwt-sample/blob/master/src/main/java/com/example/demo/config/MongoConfig.java#L19-L28 ```java @Bean ReactiveAuditorAware<Username> reactiveAuditorAware() { return () -> ReactiveSecurityContextHolder.getContext() .map(SecurityContext::getAuthentication) .filter(Authentication::isAuthenticated) .map(Authentication::getPrincipal) .map(UserDetails.class::cast) .map(UserDetails::getUsername) .map(Username::new) .switchIfEmpty(Mono.empty()); } ``` |
28
Leviathann 2021-01-25 16:40:18 +08:00
有时候把它当成三目用,至少比裸写三目漂亮
|
29
chenfcheng 2021-01-25 17:38:35 +08:00 2
Optional.ofNullable(o1.getx().getxx().getXXX()).orElse() 这时候最有用 多层嵌套情况下 可直接设置默认值 多次判断是否为空
|
30
mightofcode OP @yuanxiaosong 这就是我说的 stream 的场景
|
31
mightofcode OP |
32
mightofcode OP |
33
zhuangzhuang1988 2021-01-25 17:47:14 +08:00 via Android 1
✓ 很多 fp 就是放屁
|
34
shyling 2021-01-25 17:47:28 +08:00
黑 java 可以,但 rust 不是一样的操作?
|
35
mightofcode OP @Jirajine optional 做不到强制检查 null,你一样可以选择直接调用 get,然后抛出 NoSuchElementException
|
36
mightofcode OP @shyling rust 不一样,rust 如果声明不返回 null,那就绝对不会返回 null
|
37
1011 2021-01-25 17:51:53 +08:00
@hantsy
@yuanxiaosong fp 这个东西怎么说呢,实际写起业务来也需要设计一番,难度不比设计类、接口这些低 如果自己设计、抽象的功底不够好还是简单 if else 走起吧,至少写出来的东西还能看懂 |
38
mightofcode OP @LGA1150 警告不是 error,就有可能被无视
|
39
mightofcode OP @sampeng optional 消灭不了空指针,你如果能用 optional 消灭空指针,发出来大家学习下
|
40
yazinnnn 2021-01-25 17:59:10 +08:00
不过说实话,单拿 optional 出来做 fp 确实没啥用,java 的函数式还是太弱了
|
41
LGA1150 2021-01-25 18:07:06 +08:00 via Android 1
#31 如果你依赖 isPresent 和 get 方法,那就和传统的 != null 没区别
真正有用的是 ifPresent, ifPresentOrElse, orElseGet 等的函数式方法 |
42
shyling 2021-01-25 18:10:01 +08:00
@mightofcode std::mem::transmute 有话说
|
43
Jirajine 2021-01-25 18:14:21 +08:00 via Android
@mightofcode 概念是一致的,给警告也算静态检查了,只要你不忽略警告,再就是它提供的那些 combinator 方法。
kotlin 也分 nullable type,概念也是一样的,可能语法上好一点。 |
44
hantsy 2021-01-25 18:18:27 +08:00 2
@yazinnnn 太弱?
不,大约 5,6 年前,开始试用 Java8 的时候, 发现 Scala 没那么吸引人了。 我在 Spring 项目中第一次大规模使用 Java 8 的 Function/Consumer/Supplier 是应用 Spring Integrations 4 的 Java 8 DSL,当时它是单独的模块,现在是 Spring Integration 5 核心的一部分了。 https://spring.io/blog/2014/11/25/spring-integration-java-dsl-line-by-line-tutorial |
46
otakustay 2021-01-25 18:49:30 +08:00
最根源的问题还是`null`是一个值而不是一个类型
|
47
KarmaWu 2021-01-25 18:56:31 +08:00
Optional 判空还是挺香的,你可以不用,但是它存在即是合理
|
48
mightofcode OP @KarmaWu 香在哪?既然合理,麻烦给一个合理分析
|
49
nthin0 2021-01-25 18:59:28 +08:00
@chenfcheng 这样不行吧,得用.map(xx::getXXX),否则其中一个为 null 的时候还是会抛空指针
|
50
bigbigeggs 2021-01-25 19:30:22 +08:00
主要是强制吧,和自己 xx == null 来进行判断。
直接抛异常,他不香么 |
51
ilumer 2021-01-25 19:38:24 +08:00
|
52
Vedar 2021-01-25 19:42:31 +08:00
确实挺蛋疼的 主要还是因为不是 zero cost 的 所以还是很少用 除了一些必须要用的地方比如和 stream 交互的地方
|
53
Vedar 2021-01-25 19:48:45 +08:00
另外 java 自带的 optional 不支持序列化 有时候也挺烦的
|
54
taojintianxia 2021-01-25 19:49:39 +08:00
就是因为大量人员不做判空导致大家都在写防御性代码。第三方或者前端的数据我们无法保证一定非空,但是内部接口调用,我们难道无法保证参数是否为空吗。
|
56
young1lin 2021-01-25 19:57:06 +08:00
怎么缩呢,这个其实有点用。Spring 源码就用到了这个,在 DefaultListableBeanFactory 这个类里面好像。可以进行流式判断,确实能省好多代码,就是没仔细学过 Java8 的容易懵逼。
|
57
Vedar 2021-01-25 19:58:13 +08:00
@LGA1150 这怎么优化? jit 会将热点代码编译成机器码来提高速度 但是内存的申请和释放还是一样的呀,optional 包了一层对象 增加了 gc 压力 这不是一定的么
|
58
cigarzh 2021-01-25 20:01:28 +08:00
> 给你,你说鸡肋
> 不给,你说缺失 我觉得还挺有道理的,不过我也反对降低代码可读性来做防御式编程 |
59
Aimers 2021-01-25 20:04:32 +08:00
kt 大法好
|
60
blackboom 2021-01-25 20:09:55 +08:00 via Android
个人感觉 Optional 非常普遍啊?🤔🤔 如果使用 Spring boot 的话,随便找一找都是 Optional 的影子。
如果某个接口返回 Optional 说明调用方需要判空,返回一定有值为什么要使用 Optional API ? 在 Java 中 Optional 绝对不是鸡肋,并且很好用。 |
61
LGA1150 2021-01-25 20:17:30 +08:00
@Vedar #57 new 操作也是可以被优化掉的,有个 JVM 开关是 EliminateAllocations (标量替换),默认打开的
|
62
namelosw 2021-01-25 20:21:54 +08:00
Java 的 Optional 和 Rust 的区别不大, 可读性下降是因为缺对应的 monadic 语法糖 . 能把?.之类的语法变换成 map 和 flatMap. 这个 Java 想加也能加, 其实就是 Scala 的 for 语法.
Rust 和 Java 不兼容的地方是 borrow checker, 但是和你说的这个问题没有关系. 同理还有 Stream / Future 之类的和 async await 的关系. |
63
hantsy 2021-01-25 20:35:12 +08:00
@cigarzh 可读性很多时候是个人问题习惯而已。Scala 的语法可读性好吗?不照样有一群忠实粉丝。
Optional/Stream/Function/Labmda,Future 等,正经项目用过一次就习惯了,你再也不想回去了。 至于讨论“XXX 是鸡肋”这个问题本身就是鸡肋。 如果对于一种语言新语法,讨论如果使用,与其他语言对应的语法缺少什么,有什么优点,那还算一个帖子有点正面意义。 国内所有论坛的帖子,最多的就是在一些扯蛋的问题上撕逼。 |
64
fpure 2021-01-25 20:38:58 +08:00
Java 的 Optional 最大的问题是即使有 Optional,你依然必须给对象判 null,因为 Java 允许空指针就已经给类型系统打了一个洞了,这时候是否使用 Optional 就意义不大了,确实算鸡肋
|
65
sampeng 2021-01-25 20:47:02 +08:00 via iPhone
@mightofcode 你这就属于抬杠了,上下文意思是空指针异常啊…
|
66
sampeng 2021-01-25 20:52:09 +08:00 via iPhone
@mightofcode 再说了,你认为警告没用,那是你们代码没有 review,没有静态代码检查,没有很多强制性的要求。放飞自我随便写那确实没啥区别。对于很多开发而言,在学习语言编程的一节课或者说被教育的第一件事:不要忽略警告提示。
编码调试阶段只有两个信息,错和没错。没有中间那档。 |
67
Vedar 2021-01-25 21:13:56 +08:00
@LGA1150 受教了 jit 还有这个功能 才知道 看了下 这个只能替换没有逃逸的对象吧,实际上 optiona 大多 l 作为函数返回值,还是优化不了的
|
68
AItsuki 2021-01-25 21:32:23 +08:00
还行吧,optional 通过链式调用的时候是能提升阅读性的,例如 a.b().c().d()任何一环都有可能是空的情况。这种时候使用 optional 就很优雅。其他就见仁见智了。
|
69
Kaiv2 2021-01-25 22:16:21 +08:00
@AItsuki
Optional.ofNullable(a) .map(type::b) .map(type::c) .map(type::d) .orElse((type)null); Optional 个人感觉很好用,刚开始可能不习惯,思维模式转变后发现真香 |
71
lululau 2021-01-25 22:25:21 +08:00
还有人说 Stream API 比 for (int i=0; i <n; i++) 可读性低呢
|
72
casillasyi 2021-01-25 23:04:19 +08:00
v 站人均 jdk 开发者水平了吗?难读了,你这个结论是来自你自己的感觉还是有数据支撑?
|
73
WispZhan 2021-01-25 23:06:08 +08:00
Optional 设计初衷是给 Lambda 和 Stream 用的,并不是单纯给你来判空与否的。
|
74
casillasyi 2021-01-25 23:08:42 +08:00
“如果真这么好用,那么入参也应该用用起来啊。” 这前后有因果关系吗?你认真看过原作者的建议吗?
“但是这个只是警告,是非强制的。” 我就非要用 new 一个空对象出来,然后让他在某个地方空指针,反正编译过了就行。是不是一个意思? 你这样的心态,建议不要写 Java 了,去写某一个什么都给你安排的好好的语言。 |
76
no1xsyzy 2021-01-26 00:24:56 +08:00
同理 Checked exceptions 也一样,Python 不也能正常错误处理吗?
但为什么还是推荐 Checked exceptions 呢? 这是协作的问题,不是业务逻辑的问题 但是,缺乏语法糖也是一个问题。 另外,入参的问题,Optional 是协变的,所以不会用于入参…… |
77
siweipancc 2021-01-26 09:10:40 +08:00 via iPhone
舌战群儒:D
|
78
passerbytiny 2021-01-26 09:15:37 +08:00 via Android
不想用 Stream 方式写代码,别说自己会 Java8 。
自己没见过就说没用,别说自己会 Java 。 |
79
cheng6563 2021-01-26 09:25:23 +08:00
Java 缺的是个 Notnull 标记而不是 Nullable 标记,这里看 Optional 挺鸡肋的,更不用说 Optional 自己还可能为 null
|
80
masterclock 2021-01-26 09:58:57 +08:00
在返回要求 Optional 的函数里返回 null 的程序员是不是应该开除?
|
81
PiersSoCool 2021-01-26 10:25:38 +08:00
如 a.b.c.d.e.f 的时候喜欢用 Optional
要是 a 我喜欢用 null == a 怎么方便怎么来 |
82
CosimoZi 2021-01-26 10:31:30 +08:00
球球你们学点 plt 吧
|
83
qiyuey 2021-01-26 10:59:52 +08:00
不如 Kotlin 彻底一些
|
84
casillasyi 2021-01-26 11:00:20 +08:00
@cheng6563 能让 optional 为 null 的,跟写 if (true) 也没区别
|
85
unco020511 2021-01-26 11:16:59 +08:00
kotlin 的好用
|
86
yl666 2021-01-26 11:32:01 +08:00
我有个 String 类型的数据,本来想通过用 Optional.ofNullable 来判断是否为空的,结果看了下源码发现它是用 xx == null 来判断的,最后还是用 if 判断吧,其实 Optional 挺好用的,只不过某些场景不太适合
|
87
zhuangzhuang1988 2021-01-26 11:35:58 +08:00
@lululau 可读性确实低
而且性能差, 而且可调试不好 |
88
hantsy 2021-01-26 11:53:15 +08:00
@casillasyi 写法差别很大。
Optional 流式操作都是假定它不是 Null,如果数据流遇到 Null 的情况走 Else 路线,这和 Scala 中 OPTION,SOME,NULL 类似,Java 8 中要处理 if a= null 情况使用 Optinal 非常容易,代码看起来舒服得多, 在实际项目非常实用。 下面 Spring 5.2 加入 MVC 加入 Funtional 编程的例子,传统的 Controller 一样可以用。 https://github.com/hantsy/spring-webmvc-functional-sample/blob/master/java/src/main/java/com/example/demo/DemoApplication.java#L77-L85 ```java public ServerResponse get(ServerRequest req) { return this.posts.findById(Long.valueOf(req.pathVariable("id"))) .map(post -> ok().body(post)) .orElse(notFound().build()); } ``` |
89
hantsy 2021-01-26 11:55:54 +08:00
@yl666 所有的判断 Null 的情况都是可以用 Optional, 更方便。 你觉得不方便或者不适合,只是思想上还没接受 Stream 方式,缺少 Stream API 使用实践。
|
90
casillasyi 2021-01-26 11:58:59 +08:00
@hantsy 我觉得他们认为的 optional 本身是 null 的情况是这个对象是 null,而不是 value 为 null
|
91
AxEqaq 2021-01-26 12:15:10 +08:00
用 guava 的 cache 还是需要用到 optional 判空的
|
92
hantsy 2021-01-26 12:19:25 +08:00
@casillasyi
API 设计本来就应该一层层约束的,如果调用别从的 API,返回 Optional,成为规约,而不应该返回是 Null 。 再说了,Spring 5 内部强制大量使用了 Asserts 工具类, Bean Validation (输入参数)和 JSR 305 (输入,结果等都可以约束) 来保证 API 稳定性。Spring Data 中 findByID 很早就改成返回 Optional, 用了几年,从来没见过返回此处 Optional==Null 的情况。如果有,请帖一些公开的开源的 API 看看。 |
93
casillasyi 2021-01-26 12:30:43 +08:00
@hantsy 问他们啊。。。
|
94
oneisall8955 2021-01-26 12:33:42 +08:00 via Android
一开始我觉得鸡肋,后来发现是自己姿势不对(=_=)
|
95
oneisall8955 2021-01-26 12:41:47 +08:00 via Android
@huifer 接口定义返回 Optional,默认就是不会返回 null,调用者不用判断是否是 null,如果返回 null,把锅甩给开发这个接口的辣鸡开发
|
96
oneisall8955 2021-01-26 12:43:45 +08:00 via Android
@hantsy 赞同,楼上说需要 optional == null 都是没理解透彻 optional 的精髓
|
97
hantsy 2021-01-26 13:14:56 +08:00
@oneisall8955 这个情况在国内可能太多了,因为之前我在上海两个创业项目的经历,现在的年轻开发人员基本敷衍做事的太多,很多基本的代码约束都做不到,要费很多唇舌去要求。
不知道国内有多少用过 Null Object 模式。但我觉得这应该是一个最基本的问题,可以回避很多 Null 代码检测问题。 另外,像 Collection 类的使用,从我开始工作时,就看到一些相关的模式(或者叫实践)使用,比如:一个类中有一个 Collection field,应该初始化为一个 EmptyList/Set 等,有方法返回 Collection,永远保证不会返回 Null (没有结果以 Empty List/Set 代替)。 |
98
nnnToTnnn 2021-01-26 13:18:06 +08:00
Java 基本上好几年没写了,我的 jdk 8 出来的时候, 我依稀记得 optional 是为了解决 a?.b() 的问题,但是由于 Java 是面向对象的语言,这个思想还没怎么转换过来。 所以目前的 optional 应该是为了解决 Stream API 中 a?.b() 的问题,而不是单纯的空指针。
|
99
nnnToTnnn 2021-01-26 13:20:56 +08:00
例子 这是一个 List 结构
``` { user: { name: { name: { name: { key: '1' } } } } } ``` 以上每一个字段都有可能是空,那么你会先 5 个 if 语句来进行判断,optional 估计是解决这个问题的。 |
100
jewer3330 2021-01-26 13:31:54 +08:00
吃瓜群众
|