Java8 的函数式编程支持,我学习后觉得很沮丧和鸡肋 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zazalu
V2EX    Java

Java8 的函数式编程支持,我学习后觉得很沮丧和鸡肋

  •  
  •   zazalu 2019-10-10 19:16:07 +08:00 11896 次点击
    这是一个创建于 2261 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不知道是我问题还是什么,就感觉怪怪的

    72 条回复    2019-10-12 15:56:47 +08:00
    akiakiseofficial
        1
    akiakiseofficial  
       2019-10-10 19:33:38 +08:00
    您好,是你的问题,看一看没有函数式支持之前的代码就知道这东西解决了什么了。
    itechify
        2
    itechify  
    PRO
       2019-10-10 20:11:18 +08:00 via Android   1
    function 包用起来还是美滋滋的,将方法封装成对象,支持 lambda 表达式,用习惯了就改不回来了
    qping
        3
    qping  
       2019-10-10 20:20:46 +08:00   2
    给你举个应用场景:
    有个 list 想提取一部分字段转成一个 List<String>
    ```
    List<TableInfo> tables = ...;
    List<String> tableNames = ...;
    for(TableInfo table : tables){
    String tableName = table.getName().toUpperCase();
    tableNames.add(tableName);
    }
    ```

    使用 lamda,只要一行:
    ```
    List<String> tableNames = tables.stream().map(v -> v.getTableName().toUpperCase()).collect(Collectors.toList());
    ```

    香不香
    fuyufjh
        4
    fuyufjh  
       2019-10-10 20:20:47 +08:00
    要么___,要么___,scala 欢迎你
    fuyufjh
        5
    fuyufjh  
       2019-10-10 20:21:42 +08:00
    @qping 这明明是使用了 stream api
    godlovesxcjtest
        6
    godlovesxcjtest  
       2019-10-10 20:23:24 +08:00
    @fuyufjh 但是这也是函数式编程啊
    fuyufjh
        7
    fuyufjh  
       2019-10-10 20:27:45 +08:00
    @godlovesxcjtest 您对 FP 可能有误解
    zhuangzhuang1988
        8
    zhuangzhuang1988  
       2019-10-10 20:43:27 +08:00   3
    @qping 不香, 代码没减多少, 而且更难看懂了,调试也不好,性能还不咋的.
    hbsfxlz
        9
    hbsfxlz  
       2019-10-10 23:02:13 +08:00
    @zhuangzhuang1988 难看懂的说明没有认真去了解过,stream 的可读性比 for 循环可读性强了一百倍
    chendy
        10
    chendy  
       2019-10-10 23:20:04 +08:00
    最常用的场景可能就是 StreamAPI 了
    还好 idea 已经有 stream debugger 了,否则 debug 真的痛苦…
    godlovesxcjtest
        11
    godlovesxcjtest  
       2019-10-10 23:57:23 +08:00 via Android
    @fuyufjh 求指教。
    taotaodaddy
        12
    taotaodaddy  
       2019-10-11 00:01:52 +08:00 via Android
    java 的 fp 实现堪称是见过的颇不优雅
    FireFoxAhri
        13
    FireFoxAhri  
       2019-10-11 00:35:56 +08:00 via Android
    你需要 scala
    Senventise
        14
    Senventise  
       2019-10-11 05:58:58 +08:00 via Android
    @taotaodaddy 你这句子有语病啊
    coldear
        15
    coldear  
       2019-10-11 06:26:32 +08:00
    kotlin 吧
    zazalu
        16
    zazalu  
    OP
       2019-10-11 08:30:37 +08:00
    @qping 这些简单的还能接受,确实简化了,主要是受不了那个 andThen()函数里产生函数的写法,觉得不是很直观
    zazalu
        17
    zazalu  
    OP
       2019-10-11 08:32:09 +08:00
    ```java
    import java.util.function.*;

    class I {
    @Override
    public String toString() { return "I"; }
    }

    class O {
    @Override
    public String toString() { return "O"; }
    }

    public class TransformFunction {
    static Function<I,O> transform(Function<I,O> in) {
    return in.andThen(o -> {
    System.out.println(o);
    return o;
    });
    }
    public static void main(String[] args) {
    Function<I,O> f2 = transform(i -> {
    System.out.println(i);
    return new O();
    });
    O o = f2.apply(new I());
    }
    }
    ```

    这个既有趣又感觉我玩的是 java 吗?
    araaaa
        18
    araaaa  
       2019-10-11 08:52:46 +08:00
    去用异步框架 vert.x 之类的
    Jrue0011
        19
    Jrue0011  
       2019-10-11 09:08:57 +08:00
    @zazalu lambda 挺好用的,如果你觉得一段方法链用了很多个 lambda 太长的话,可以定义把这些方法抽出来定义成静态方法或者成员方法,通过方法引用传递
    qping
        20
    qping  
       2019-10-11 09:13:35 +08:00
    @zhuangzhuang1988 #8 兄弟,你可以尝试用一下,一点也不复杂,当你了解后可读性并不差。最初我也是很抵制的,stream api 可以代替很多恶心的 for 循环的场景,用的飞起


    @zazalu #16 从代码的可读性来说还是 Function 接口是有点复杂,这些接口更像是给底层架构设计使用的。有的东西只需要了解,然后能读懂其他人的代码就可以了,日常你可以不用嘛。
    soeur
        21
    soeur  
       2019-10-11 09:17:44 +08:00 via Android
    我觉得挺好用的呀
    Jrue0011
        22
    Jrue0011  
       2019-10-11 09:18:00 +08:00
    大概是这样,手写没有编译器警告可能会有错误。。但是是能实现的

    import java.util.function.*;

    class I {
    @Override
    public String toString() { return "I"; }

    public O println() {
    System.out.println(this);
    return new O();
    }
    }

    class O {
    @Override
    public String toString() { return "O"; }

    public O println() {
    System.out.println(this);
    return this;
    }
    }

    public class TransformFunction {
    static Function<I,O> transform(Function<I,O> in) {
    return in.andThen(O::println);
    }

    public static void main(String[] args) {
    Function<I,O> f2 = transform(I::println);
    O o = f2.apply(new I());
    }
    }
    LeeSeoung
        23
    LeeSeoung  
       2019-10-11 09:22:35 +08:00
    技术每天都在更新,不是你能挑三拣四的时候,今天还在为掌握了这些而满足的时候,明天就有一个更高效的技术就替代它了,一生都需要学习。
    zzxop
        24
    zzxop  
       2019-10-11 09:31:57 +08:00
    建议你再看一下,了解了之后肯定不想再用以前的方法
    guolaopi
        25
    guolaopi  
       2019-10-11 09:32:13 +08:00
    我一直以为 java 跟 C#一样老早就支持这么写了(一脸懵逼
    buckbuckgo
        26
    buckbuckgo  
       2019-10-11 09:36:16 +08:00
    我自己是熟悉的功能性接口(比如 Runnable, OnClickListener)用 lambda 很简洁, 自己也清楚, 不熟悉不常用的仍旧用 匿名对象
    zazalu
        27
    zazalu  
    OP
       2019-10-11 09:36:59 +08:00
    @zzxop 嗯,在看,新手第一次接触 Java 的 FP
    zazalu
        28
    zazalu  
    OP
       2019-10-11 09:38:41 +08:00
    @guolaopi java8 挺早的了!只不过我参与的项目开始用 8 版本是最近的事情 orz,之前一直 1.7
    softtwilight
        29
    softtwilight  
       2019-10-11 09:53:39 +08:00
    刚开始不熟悉正常的,大脑比较讨厌改变,多用用就能感受到好了,函数编程最主要的是对思维模式的影响,你对问题的抽象完全不一样了
    Aresxue
        30
    Aresxue  
       2019-10-11 10:18:14 +08:00
    性能稍差点,但是可读性上升了很多,前提是你习惯函数式编程的思维,毕竟面向对象的编程其实和人类思维的代沟还是差蛮多的
    kansyoukyou
        31
    kansyoukyou  
       2019-10-11 10:57:57 +08:00
    从 Java7 一路写过来的,觉得 Stream 和 FP 结合还是很好用的
    Kamiyu0087
        32
    Kamiyu0087  
       2019-10-11 11:00:58 +08:00
    函数式编程真的大大提高代码可读性
    真心建议啃下来,其实一点不难的
    djFFFFF
        33
    djFFFFF  
       2019-10-11 11:04:32 +08:00
    之前接触过 Python 或者 Scala 的话,沮丧是很正常的。Java 8 的实现一点都不优雅。没接触的话,应该是你还没从 oop 的思路转过来。
    djFFFFF
        34
    djFFFFF  
       2019-10-11 11:06:55 +08:00
    补充一下 @qping 的例子:

    Python 版:
    `[t.getTableName() for t in tables]`

    Scala 版:
    `tables.map(_.getTableName())`
    lihongjie0209
        35
    lihongjie0209  
       2019-10-11 11:13:42 +08:00
    @djFFFFF #34 scala 版本可以使用 vavr 实现。

    python 版本的是列表解析, 不上常规意义上的 map。
    djFFFFF
        36
    djFFFFF  
       2019-10-11 11:18:21 +08:00
    @lihongjie0209 嗯,python 这个是语法糖,不是函数式编程。vavr 看了下感觉还是很笨重
    feelinglucky
        37
    feelinglucky  
       2019-10-11 11:42:30 +08:00
    建议啃下来,真的
    Orenoid
        38
    Orenoid  
       2019-10-11 11:55:54 +08:00
    @djFFFFF #34 python 不是也有 map filter reduce 吗
    lazyfighter
        39
    lazyfighter  
       2019-10-11 11:59:51 +08:00
    我把他称之为,写着舒服看着难受,至于上面的 demo,都是太简单了,你见过上百行的 stream 处理吗,各种类型转换看着头都大了
    by73
        40
    by73  
       2019-10-11 12:04:31 +08:00
    是很鸡肋,连 pattern matching 都没有(逃
    dk7952638
        41
    dk7952638  
       2019-10-11 12:11:14 +08:00
    lambda 很优雅很装逼,但你看过他的实现方式之后你就会发现性能堪忧,想优雅还是直接 scala 吧,java 就不是干这事的
    Narcissu5
        42
    Narcissu5  
       2019-10-11 12:19:19 +08:00
    lambda 好不好,请去看下 lambda 之前无数的匿名类
    taotaodaddy
        43
    taotaodaddy  
       2019-10-11 12:26:49 +08:00 via Android
    java 的 fp 实现堪称是见过的颇不优雅
    @Senventise 还真是。。。我重说

    java 的 fp 实现实在是不优雅呢
    ipwx
        44
    ipwx  
       2019-10-11 13:22:57 +08:00
    去看看 Vert.x 吧。

    函数式对 CRUD 确实可能没啥用。但是对很多高级编程范式,还是很有用的。
    ipwx
        45
    ipwx  
       2019-10-11 13:24:56 +08:00
    @lazyfighter 上百行的 stream,写成普通形式不是要上千,不还是一样不容易懂。

    这种长长长的 stream 不该合理地分块、拆句子、加注释么?

    当然如果你说大部分 Java 程序员写不出容易看懂的 stream,那你的逻辑就和 go 语言那帮拥簇一样了:既然用不好,就砍掉呗(手动斜眼)。我反正不喜欢这样的哲学,我更喜欢 Scala 和 C++ 那种,菜全都端上来了,吃那些,自己看着办。
    optional
        46
    optional  
       2019-10-11 13:40:55 +08:00
    java lambda 最恶心的是 checked exception
    zazalu
        47
    zazalu  
    OP
       2019-10-11 13:49:42 +08:00
    @optional 和这个有什么关系吗?
    yukongzz
        48
    yukongzz  
       2019-10-11 13:49:55 +08:00
    可以看看 kotlin
    optional
        49
    optional  
       2019-10-11 13:57:28 +08:00
    @zazalu 大部分 fp interface 都不带 throw
    sevenstone
        50
    sevenstone  
       2019-10-11 14:09:22 +08:00
    Scala 欢迎你
    zazalu
        51
    zazalu  
    OP
       2019-10-11 14:09:48 +08:00
    @optional 嗯,但是这个自己实现一个不就好了吗(擦汗)
    lazyfighter
        52
    lazyfighter  
       2019-10-11 14:14:49 +08:00
    @ipwx stream 拆开写就不舒服了啊, 本来就是一个句子但是拆开了人为使他易读写着就不舒服了,所以我把它定位为写着爽读着累。另外我的观点是这样的,好比我写代码的时候不写注释,我看代码的时候骂别人不写注释,啊哈哈哈哈哈哈
    aguesuka
        53
    aguesuka  
       2019-10-11 14:29:37 +08:00 via Android
    @zazalu stream 只接受 jdk 的接口作为参数,而且 function 的 default 方法写不写都不好
    slanternsw
        54
    slanternsw  
       2019-10-11 14:37:11 +08:00
    函数式不好 x
    java 的函数式不好 √
    uleh
        55
    uleh  
       2019-10-11 15:33:08 +08:00
    作为一个从 JDK 1.4 用过来的 java 程序员,表示 lambda 真香……
    Cstone
        56
    Cstone  
       2019-10-11 15:40:40 +08:00
    函数式真的很香,没了函数式,没法用流没法链式操作,整个代码都会变得丑陋不堪
    mrobot
        57
    mrobot  
       2019-10-11 16:04:42 +08:00 via iPhone
    个人项目 上上上上真香
    团队项目 确实很怪 最好别写花里胡哨的代码 保重大家都看的懂能跑起来就行 减少沟通成本
    djFFFFF
        58
    djFFFFF  
       2019-10-11 16:12:22 +08:00
    @Orenoid 有但是用的不多,list comprehension 是被认为更 pythonic (可以理解为更有情怀)的方式
    CononYc
        59
    CononYc  
       2019-10-11 16:23:18 +08:00
    一开始我也是这么认为的,函数式看着头大,后面了解多了之后就感觉真香,真好用
    hitsmaxft
        60
    hitsmaxft  
       2019-10-11 17:00:27 +08:00   1
    只是从 api 上改善了对 lambda 支持而已。别提什么函数式。这么去看就释然了。

    1. 支持 lambda 写法的匿名接口实现,不用显示写匿名类实现。(仅限于单个实现方法的接口,多个方法就嗝屁了)
    2. 提供 function 包,这样子第三方有了公共的 api,大伙都可以快乐地玩高阶函数了,不用动不动一堆类。
    3. stream api 改善一些并发和列表处理的延迟计算的实现,基于 1,可以大大减少代码量

    只是提供了函数式的 api/语法糖 ,参考了函数式的一些优点。
    irgil
        61
    irgil  
       2019-10-11 17:01:05 +08:00
    这位亲亲你好,是你的问题呦
    wupher
        62
    wupher  
       2019-10-11 17:49:22 +08:00
    你这要是玩 ReactiveX 还不得吐?

    不过,我现在也更习惯 Groovy 和 Kotlin 风格的 lambda。

    Java 8 的能接受,自己写的时候会绕一下。
    zazalu
        63
    zazalu  
    OP
       2019-10-11 20:33:47 +08:00
    @hitsmaxft 到位,我看下来也觉得是这么回事
    haosamax
        64
    haosamax  
       2019-10-11 20:57:38 +08:00
    @qping 我觉得看起来挺爽的,比 for 明朗多了。看不懂的,是不了解 stream 吧
    islandev
        65
    islandev  
       2019-10-11 21:03:23 +08:00
    function 可以作为参数了 可以传递了 怎么好玩的
    可以精简代码
    ```java
    private Function<T, String> funca;

    private List<Function<T>> funcb

    private String name;

    ```
    bozhongshao
        66
    bozhongshao  
       2019-10-11 21:17:54 +08:00
    @qping 习惯简单不出错的转换 用 lambda 但是很复杂的还是习惯用大括号括住, 慢慢来。
    andyholo
        67
    andyholo  
       2019-10-11 21:33:56 +08:00 via Android
    函数式和面向对象不是对立的吧?怎么听你们说的好像两者有个地位高低似的,复杂逻辑我是不敢用函数式,太复杂耦合度太高了
    kingfalse
        68
    kingfalse  
       2019-10-11 21:50:47 +08:00 via Android
    kotlin 吧,spring boot 支持的很好
    wzdbsss
        69
    wzdbsss  
       2019-10-11 22:07:54 +08:00 via iPhone
    怎么实现 stream 里面的 if else ?最近用 reactor,不知道怎么优雅的 if else
    mskf
        70
    mskf  
       2019-10-11 23:52:39 +08:00
    函数式编程咯,并行运算只需要 parallelStream 就行了
    fuyufjh
        72
    fuyufjh  
       2019-10-12 15:56:47 +08:00
    @godlovesxcjtest 我不知道怎么解释,所以仅仅列出事实:FP 的代表语言 Haskell/Scheme 并不支持类似 Stream API 的东西,而 Stream API 的集大成者 ReactiveX 支持几乎所有语言
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2830 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 35ms UTC 14:31 PVG 22:31 LAX 06:31 JFK 09:31
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86