V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
w741069229
V2EX  ›  Java

Java 项目该不该用 stream 流来编写代码?考虑 code viewer

  •  
  •   w741069229 · 2022-03-30 18:11:49 +08:00 via iPhone · 8381 次点击
    这是一个创建于 1002 天前的主题,其中的信息可能已经有所发展或是发生改变。
    95 条回复    2022-04-09 21:53:55 +08:00
    vate32
        1
    vate32  
       2022-03-30 18:15:38 +08:00   ❤️ 2
    为什么不用,用来处理集合效率多高。“考虑 code viewe”,不会有人看不懂吧
    golangLover
        2
    golangLover  
       2022-03-30 18:17:30 +08:00 via Android
    用 foor loop 的可读性太差了
    LeonL1
        3
    LeonL1  
       2022-03-30 18:17:32 +08:00
    虽然可读性确实不太好,但是写起来确实爽啊
    chendy
        4
    chendy  
       2022-03-30 18:21:31 +08:00
    具体情况具体分析,没有固定标准
    有的地方直接循环更清晰,有些地方 stream 更简洁
    fengpan567
        5
    fengpan567  
       2022-03-30 18:23:51 +08:00
    stream 就是简洁明了啊
    xianzhe
        6
    xianzhe  
       2022-03-30 18:25:16 +08:00 via Android
    离了 stream 不会写了
    lostpg
        7
    lostpg  
       2022-03-30 18:27:13 +08:00 via Android   ❤️ 1
    我觉得使用 stream 是更明晰的
    SurfaceView
        8
    SurfaceView  
       2022-03-30 18:27:42 +08:00
    never use.
    xuanbg
        9
    xuanbg  
       2022-03-30 18:28:57 +08:00
    我觉得更清晰
    keshawnvan
        10
    keshawnvan  
       2022-03-30 18:30:15 +08:00
    可读性提高了,code review 不应该更简单吗?
    eb0c6551
        11
    eb0c6551  
       2022-03-30 18:31:08 +08:00   ❤️ 3
    请看《 Effective Java 》 Item 45 : Use streams judiciously
    kingfalse
        12
    kingfalse  
       2022-03-30 18:31:12 +08:00 via Android
    review 的人不是得起码能看得懂 stream.....
    kingfalse
        13
    kingfalse  
       2022-03-30 18:31:51 +08:00 via Android   ❤️ 1
    或许该考虑换人 review 了?
    pengtdyd
        14
    pengtdyd  
       2022-03-30 18:33:39 +08:00   ❤️ 8
    人写出来的代码是给人看的,不是给某些蠢货看的
    Samuelcc
        15
    Samuelcc  
       2022-03-30 18:48:45 +08:00
    合理地使用 Stream 只会让可读性更好。
    只会不合理使用的人换别的写法可读性也不会高到哪里去。。
    w741069229
        16
    w741069229  
    OP
       2022-03-30 18:49:05 +08:00 via iPhone
    @pengtdyd 但是公司的大佬不让用 stream 和 optional 这些用法
    luckyrayyy
        17
    luckyrayyy  
       2022-03-30 18:51:19 +08:00
    stream 也不是所有情况下都可读性更好的....不是非常复杂的 stream ,我觉得都可以用
    MakHoCheung
        18
    MakHoCheung  
       2022-03-30 18:52:40 +08:00
    @w741069229 听大佬的,如果你想用就用一遍然后删了改回 foreach
    TWorldIsNButThis
        19
    TWorldIsNButThis  
       2022-03-30 18:55:46 +08:00 via iPhone
    idea 可以一键把 stream 转成 for
    gabon
        20
    gabon  
       2022-03-30 18:57:24 +08:00
    @MakHoCheung intellij idea 可以自动把简单的 stream 转换为 for loop 。
    TWorldIsNButThis
        21
    TWorldIsNButThis  
       2022-03-30 18:57:48 +08:00 via iPhone
    @w741069229 那建议他们转 go 永远不升 1.18 的那种
    adoal
        22
    adoal  
       2022-03-30 19:50:32 +08:00 via iPhone
    @w741069229 换个新大佬
    interim
        23
    interim  
       2022-03-30 20:17:17 +08:00
    离了 stream 不会写了 +1
    gam2046
        24
    gam2046  
       2022-03-30 20:18:23 +08:00
    @w741069229 #16 有没有一种可能,大佬对项目不够熟悉,目测,看不出类型推导的具体结果,就导致大佬不知道你在干啥。
    w741069229
        25
    w741069229  
    OP
       2022-03-30 20:35:58 +08:00
    @gam2046 我是新接的,我之前都是梭哈 stream 流,通篇的那种,但是新公司入职后,就不让用了
    w741069229
        26
    w741069229  
    OP
       2022-03-30 20:36:12 +08:00
    pofycn
        27
    pofycn  
       2022-03-30 22:21:28 +08:00
    能用 steam 梭的统统用 stream 梭 管他呢 [狗头]
    zmal
        28
    zmal  
       2022-03-30 22:41:33 +08:00
    你司大佬排斥 stream 的原因无非这么几条:
    1. 可读性差。理论上 lambda 范式的代码可读性会更好。如果可读性变差了,说明姿势不太对,业务逻辑和控制逻辑没有分离。
    2. 性能损耗。据说相比 for loop 大约 15%的性能损失。但对业务代码来说是可接受的。
    3. 不便调试。这个要看具体案例,个人认为不是问题。
    4. 老派守旧。无解,建议换公司。
    searene
        29
    searene  
       2022-03-30 23:02:31 +08:00
    Stream 出来都多少年了,这都看不懂就不要 review 代码了吧
    Vegetable
        30
    Vegetable  
       2022-03-30 23:05:08 +08:00
    笑死,这么多人不明白什么叫可读性是吧。
    Stream 确实不错,但是最好少用 lambda ,把代码写短不是本事,写清楚才是。
    Vegetable
        31
    Vegetable  
       2022-03-30 23:06:23 +08:00   ❤️ 1
    Reviewer 欠你的,在网页上一行一行给你走读代码?
    tohuer00
        32
    tohuer00  
       2022-03-30 23:06:54 +08:00
    得考虑团队整体水平,防止水平差的同事瞎用,干脆一刀切禁掉省事。比如楼上很多一把梭的我看就很危险。
    EscYezi
        33
    EscYezi  
       2022-03-30 23:09:55 +08:00 via iPhone   ❤️ 3
    steam filter map 等 api 语义不比 for 来 for 去清晰多了
    顺便推荐 vavr 库,更简洁更清晰
    v2eb
        34
    v2eb  
       2022-03-30 23:13:26 +08:00 via Android
    想看下可读性差的 stream 流形式代码是怎么写的。
    gtx990
        35
    gtx990  
       2022-03-30 23:22:24 +08:00 via Android   ❤️ 2
    Java 的完全没问题,Scala 的吐了
    lux182
        36
    lux182  
       2022-03-30 23:33:36 +08:00
    想知道不用等理由
    Rocketer
        37
    Rocketer  
       2022-03-30 23:35:16 +08:00 via iPhone
    这是要照顾纯 Java 6 程序员么?哪怕是写过 JS 的也能看懂 stream 吧?
    yazinnnn
        38
    yazinnnn  
       2022-03-30 23:47:11 +08:00
    你们前端也禁用 lambda 吗?
    RobberPhex
        39
    RobberPhex  
       2022-03-31 00:02:16 +08:00
    用 stream (甚至用函数式编程)都会遇到一个问题,就是堆栈不可回溯了。你只能看到这个 stream 的栈,再往上就看不到上一个 stream/lambda 了,只能看到 stream 库的栈了。
    所以我个人觉得,单个语句中,stream 可以用一次,不能再多。

    当然,回到问题,公司项目,怎么约定就怎么来,协作重要。
    Jooooooooo
        40
    Jooooooooo  
       2022-03-31 00:35:55 +08:00   ❤️ 1
    里面抛个空指针不好查.
    echo1937
        41
    echo1937  
       2022-03-31 00:55:17 +08:00 via iPhone
    @v2eb 我见过把整个业务逻辑写在一个 map()里面的
    WebKit
        42
    WebKit  
       2022-03-31 01:03:10 +08:00 via Android
    stream 不止简洁,的性能更好
    Hider5
        43
    Hider5  
       2022-03-31 01:17:33 +08:00 via iPhone
    Stream 可读性好,但空指针问题不好排查
    w741069229
        44
    w741069229  
    OP
       2022-03-31 06:52:04 +08:00 via iPhone
    @EscYezi 哈哈哈哈哈。我一直在用
    wxyrrcj
        45
    wxyrrcj  
       2022-03-31 07:32:16 +08:00 via Android
    多好用 为啥不用
    dreamramon
        46
    dreamramon  
       2022-03-31 07:49:47 +08:00   ❤️ 1
    出了空指针,堆栈不好查。
    aptupdate
        47
    aptupdate  
       2022-03-31 08:03:55 +08:00 via iPhone
    前段时间有个奇葩需求要对集合各种过滤、排序、分组,当时就感叹要是没有 stream 我得累个半死。
    所以这种省时省力的方法为什么不用呢? NPE 问题确实麻烦,不过新版 idea 里有个流调试器,直接可视化处理过程。
    micean
        48
    micean  
       2022-03-31 08:33:05 +08:00
    stream 的 lambda 里面要精炼、简洁到不可能出现 NPE 问题
    cweijan
        49
    cweijan  
       2022-03-31 08:47:25 +08:00
    stream 还是要用的, 但是有的程序员水平低, 用 stream 写的代码可读性极差.
    neptuno
        50
    neptuno  
       2022-03-31 09:13:46 +08:00
    看不懂 stream ,这个水平 review 了有啥用吗
    ychost
        51
    ychost  
       2022-03-31 09:28:52 +08:00
    stream 结合 Optional 用起来美滋滋,C# 的 Linq 更加的纯粹舒服
    arthas2234
        52
    arthas2234  
       2022-03-31 09:53:54 +08:00
    stream 挺好用的,用来处理集合再适合不过啦。说看不懂的,可读性差的,是没用过的吧
    nothingistrue
        53
    nothingistrue  
       2022-03-31 09:55:18 +08:00
    Stream 及 Lambda 表达式的第一优点就是代码简洁,这跟 code review 是正相关,不是互斥的。

    不过 Lambda 表达式能无缝转接,Stream 不能。Stream 使用的是数据流逻辑,跟传统的“判断、循环……”逻辑有区别,转换过去需要学习。但是这个学习成本不大,而且如果是数据结构 /算法已经很溜的,早就回了压根不用学。大佬刚开始不让用,可能还是要考虑团队管理,大佬要是一直不让用,那他 100%是假大佬。
    Huelse
        54
    Huelse  
       2022-03-31 10:02:48 +08:00
    哪来那么多可读性问题?是你自己“懒”吧?
    yor1g
        55
    yor1g  
       2022-03-31 10:09:38 +08:00
    java 8 都多少年了 还抱着 java6 么
    superchijinpeng
        56
    superchijinpeng  
       2022-03-31 10:11:32 +08:00
    Why not ?
    Loku
        57
    Loku  
       2022-03-31 10:15:12 +08:00
    stream 都 jdk1.8 的东西了。 现在 jdk1.18 了。
    loryyang
        58
    loryyang  
       2022-03-31 10:16:17 +08:00   ❤️ 1
    可以,但,注意别过于复杂
    我对代码的认知就是,这代码写完,过段时间,你自己能不能很快地看懂,看不懂就说明写得不好。要不改逻辑,要不写注释

    最后,stream 也有上面提到的堆栈问题,一般不建议做非常复杂的操作
    xwayway
        59
    xwayway  
       2022-03-31 10:18:31 +08:00
    可以,但是不要过长,一句话完成一个目的,需要写得太长了,那样就成裹脚布了。
    Torpedo
        60
    Torpedo  
       2022-03-31 10:20:20 +08:00
    @pengtdyd 好像两方都认为自己才是人,对方是蠢货
    bertonzh
        61
    bertonzh  
       2022-03-31 10:26:58 +08:00
    22 年了大概只有 Java 圈才会出现这种问题...
    byte10
        62
    byte10  
       2022-03-31 10:27:37 +08:00
    @RobberPhex 这个是核心问题,一直觉得 stream 有哪里不对,原来在你这里。😄
    intmax2147483647
        63
    intmax2147483647  
       2022-03-31 10:29:28 +08:00
    说抛空指针不好查的的🤣你不知道在流中对空的处理吗
    dayudayupao
        64
    dayudayupao  
       2022-03-31 10:35:06 +08:00
    Stream 需要什么可读性,跟业务逻辑代码比起来,这几个集合操作的复杂度有啥,还是把重心放在业务逻辑代码的清晰上来吧,这种语法糖怎么可能承载太多逻辑
    Magentaize
        65
    Magentaize  
       2022-03-31 10:48:16 +08:00 via iPhone   ❤️ 2
    在 stream 里说 NPE ,栈的怕是不会正确使用 stream ?
    anzu
        66
    anzu  
       2022-03-31 10:57:13 +08:00
    看情况,禁止在调用链中写一堆代码,类似 .filter(d -> { /*这里有 10 行代码*/ })
    clf
        67
    clf  
       2022-03-31 10:57:17 +08:00
    stream 除了一些小坑( localthread 相关)外,都挺好的。对于可读性的提升也是很大的,相对来说,可以很清晰的知道这份 stream 输出的数据经过了哪些流程。
    nulIptr
        68
    nulIptr  
       2022-03-31 11:23:17 +08:00   ❤️ 3
    2022 年是 linq 发布的第 14 年,stream api 发布的第 8 年。居然还有人讨论这个问题。
    fewok
        69
    fewok  
       2022-03-31 11:47:07 +08:00
    2022 年了,其实可提出,该不该用 java 了,毕竟其他编程语言也是不错的
    WispZhan
        70
    WispZhan  
       2022-03-31 12:25:40 +08:00 via Android
    你们是不是都不屑写 ut ,单元测试?
    selca
        71
    selca  
       2022-03-31 12:52:38 +08:00
    读个 lambda 都读不明白,啥 reviewer ,水准这么低
    uSy62nMkdH
        72
    uSy62nMkdH  
       2022-03-31 13:06:37 +08:00
    建议上一段你们产生争议的代码看看。
    zbatman
        73
    zbatman  
       2022-03-31 13:22:34 +08:00
    @fewok 我觉得所有公司应该立马把 Java 写的业务系统全撤了,换成其他不错的编程语言,直接让 Java 进垃圾堆
    mauve
        74
    mauve  
       2022-03-31 13:46:46 +08:00
    程序员就该写程序员该写的东西!
    zw1one
        75
    zw1one  
       2022-03-31 13:52:51 +08:00
    没必要一刀切,写 for 也有写得恶心的,不是 stream 的问题,是写的人有没有维护代码可读性意识的问题。
    siweipancc
        76
    siweipancc  
       2022-03-31 14:01:11 +08:00 via iPhone
    不应该用范型,注解也不该用,毕竟大佬可以不学,你不可以不听他的话
    NoKey
        77
    NoKey  
       2022-03-31 14:13:08 +08:00
    @vate32 先不说能不能用;处理集合效率高,这个值得讨论讨论。。。
    NoKey
        78
    NoKey  
       2022-03-31 14:14:13 +08:00
    @WebKit 性能更好从何说起?
    NoKey
        79
    NoKey  
       2022-03-31 14:20:17 +08:00
    太多一刀切的说法,还有说因为不让用 stream 直接换公司的。。。
    学 java 的同时,学习一下其他语言
    各种语言提供的语法糖不同
    如楼上有人说的,如果没有 stream ,各种分组,过滤,排序就不会写了
    这实际上是有问题的
    当然,要觉得自己这辈子在程序员这路上,只用 java ,且都在 1.8 版本以上,那也没啥问题
    TWorldIsNButThis
        80
    TWorldIsNButThis  
       2022-03-31 14:33:10 +08:00 via iPhone
    @EscYezi 还有 eclipse collections
    Java 官方视频拿 java17 的 stream 跟它对比,说难道更好的抽象(指 eclipse collections )一定会有更差的性能吗?结论为不是,因为 eclipse collections 在他们给出的几个用例下抽象更好且速度也更快 XD
    Leviathann
        81
    Leviathann  
       2022-03-31 14:49:33 +08:00
    @NoKey 如果用上了比 java8 表达力还烂的语言且收入不是明显高出其他的话,那真的要反省一下自己了
    HanMeiM
        82
    HanMeiM  
       2022-03-31 15:13:59 +08:00
    @w741069229 为啥不让用 optional ?我不是很明白,更喜欢不确定的空指针返回值吗? optional 在某些情况下更能表达返还值的稳定性。
    uleh
        83
    uleh  
       2022-03-31 16:11:33 +08:00
    对于工程化比较成熟的团队,只要你的局部小组里能维护好,用什么黑魔法其实都无所谓
    但是如果是工程化比较弱的团队,请记住:安全第一! 😄
    wupher
        84
    wupher  
       2022-03-31 17:26:59 +08:00
    stream 绝对应该用。

    ReactiveX 倒是可以考虑场景,值得商榷。
    FrankHB
        85
    FrankHB  
       2022-03-31 18:49:04 +08:00
    @RobberPhex @dreamramon @loryyang @byte10

    提到的一些通病比这里说的原始问题更有毛病得多。

    栈作为活动记录的一种实现,本来就用于隐藏过程运行时状态的实现细节。只有直接能在程序中显式访问活动记录的语言(比如至少得有 first-class one-shot continuation ),这种东西才配被要求是和程序员交互的标配。
    说白了,在抽象能力弱鸡的语言里没事依赖栈帧是一种习惯性纵容实现泄露抽象的病。
    特别是要知道 Java 不光不支持 continuation capture ,甚至连 proper tail call 都没有……设计 JVM 的丈育还用 stack inspection 当挡箭牌,结果差不多被正面打脸: https://stackoverflow.com/a/5097402
    退一步讲,真是想要照顾调试体验,又不是 C 这种滥依赖 ABI 兼容的历史包袱,这么多年了连个 shadow stack 都不会实现的弟弟怎么好意思变成工业主流的?

    算了,还是先停止把 stack 叫做什么劳什子“堆栈”开始吧。

    (反思为什么 NPE PTSD 以及 optional 实质套娃的问题就不提了,本质算不上 Java 特色,虽然这年头也快成了 Java 特供问题了。)
    hervey0424
        86
    hervey0424  
       2022-03-31 20:58:11 +08:00
    C# 十年前都没有这种问题
    lmshl
        87
    lmshl  
       2022-03-31 21:13:44 +08:00
    你们还在争论该不该用的时候,我的 5 个 Akka Stream 已经上线生产了。
    ZStream / fs2 混着用表示看 Stream API 毫无压力😏
    leeg810312
        88
    leeg810312  
       2022-04-01 08:34:11 +08:00 via Android
    用循环写代码逻辑不清晰的人,用 stream 写一样不清晰,连 stream 都看不明白的没资格做代码审核
    codeant
        89
    codeant  
       2022-04-01 08:38:01 +08:00 via iPhone
    @w741069229 提这种要求的人也配叫大佬
    Breadykid
        90
    Breadykid  
       2022-04-01 10:25:59 +08:00
    @eb0c6551 你看的哪一版?
    w741069229
        91
    w741069229  
    OP
       2022-04-02 07:37:17 +08:00 via iPhone
    @anzu 非常同意,但是这样做的结果就是,要么要写一个 predicate,把所有的判断逻辑放进去,这种会增加一定的理解度,但是我认为会有一定的效率提升;要么就要不停的.flilter ,这种得对原生的 api 有一定的了解,我认为好处就是代码比较清晰明了吧。那么这就引申了一个问题,哪种写法更好?
    w741069229
        92
    w741069229  
    OP
       2022-04-02 07:40:14 +08:00 via iPhone
    @HanMeiM 理解难度吧,别人拿到代码不能直观的看出来,就比如 optional·ofNullbale 这个算子
    TWorldIsNButThis
        93
    TWorldIsNButThis  
       2022-04-06 23:20:43 +08:00
    @w741069229 stream 的 map 跟 filter 都是无状态操作,所以串 n 个 filter 它也是遍历一遍
    w741069229
        94
    w741069229  
    OP
       2022-04-08 09:28:20 +08:00
    感谢各位大佬的回复,我们就基于这个问题,站在`code review`的角度,和`debug`的角度,看下下面这段,

    1. @TWorldIsNButThis 大佬说,`stream`的`filter`算子都是无状态的,这一点我同意,本质如下面这段代码,其实只有`map`和`flatmap`会引入时间的复杂度
    2. 站在`review`的角度,如果我们要兼容向下的同学,那么这段代码是否存在复杂性的难度?
    3. 站在`debug`的角度,我们是否引入了新的**断点**(就是`stream`是无状态的,导致断点其实有时候不太好懂)问题呢?譬如,`idea`可以使用`debug`中的计算器模式进行
    4. 站在代码整个的观感角度,下面这段代码是否可以理解不具备代码简洁特性以及代码的整体都美感上
    5. 站在代码的复用性上,我认为`steam`的代码其实是对业务有更高的要求,因为我觉得`stream`的复用性其实蛮低的,如果要改的话,就会牵一发而动全身.
    6. 站在异常的处理上,我认为`stream`其实是在更严谨的要求一个编程人员对一段结果中产生异常的一个预判,我认为更能锻炼编码人员的功底吧

    ```java
    Optional.ofNullable(search)
    .map(SearchResponse::getHits)
    .ifPresent(hits -> StreamSupport
    .stream(hits.spliterator(), false)
    .filter(Objects::nonNull)
    .filter(SearchHit::hasSource)
    .filter(this::filter)
    .......会是 filter
    .map(SearchHit::getSourceAsMap)
    .filter(Objects::nonNull)
    .map(Map::entrySet)
    .flatMap(Collection::stream)
    .filter(Objects::nonNull)
    .map(this::map)
    .forEach(.....)
    );
    ```
    以上是小弟对`stream`一点见解,希望大家能对我的看法进行批判和讨论吧
    yoloMiss
        95
    yoloMiss  
       2022-04-09 21:53:55 +08:00
    这种情况建议抓紧润啊。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4754 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 05:38 · PVG 13:38 · LAX 21:38 · JFK 00:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.