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

Java 中可以做到函数嵌套吗

  •  
  •   DIO · 5 天前 · 3225 次点击

    我知道可以通过 Runnable 来让 lambda 前置并在后面调用,而且最终实际上是通过包装成私有函数运行,不会有额外开销。但是有没有办法让子函数体后置,业务代码在前?

    函数式编程貌似可以做到。Java 中有没有办法呢。

    至于为什么不用 kt ,嗯,公司业务积重难返了。

    
    function parentFunction() {
        // 业务代码部分
        const data = [1, 2, 3, 4, 5];
        
        const doubled = doubleData(data);
        console.log('Doubled Data:', doubled);
        
        const filtered = filterData(doubled, isEven);
        console.log('Filtered Data (Even):', filtered);
        
        // 子函数定义部分
        function doubleData(arr) {
            return arr.map(function(num) {
                return multiply(num, 2);
            });
        }
    
        function multiply(a, b) {
            return a * b;
        }
    
        function filterData(arr, predicate) {
            const result = [];
            for (let i = 0; i < arr.length; i++) {
                if (predicate(arr[i])) {
                    result.push(arr[i]);
                }
            }
            return result;
        }
    
        function isEven(num) {
            return num % 2 === 0;
        }
    }
    
    
    
    fun parentFunction() {
        // 业务代码部分
        val data = listOf(1, 2, 3, 4, 5)
        
        val doubled = doubleData(data)
        println("Doubled Data: $doubled")
        
        val filtered = filterData(doubled, ::isEven)
        println("Filtered Data (Even): $filtered")
    
        // 子函数定义部分
        fun doubleData(arr: List<Int>): List<Int> {
            return arr.map { multiply(it, 2) }
        }
    
        fun multiply(a: Int, b: Int): Int {
            return a * b
        }
    
        fun filterData(arr: List<Int>, predicate: (Int) -> Boolean): List<Int> {
            return arr.filter(predicate)
        }
    
        fun isEven(num: Int): Boolean {
            return num % 2 == 0
        }
    }
    
    
    31 条回复    2024-12-14 02:10:18 +08:00
    iPisces77
        1
    iPisces77  
       5 天前
    不支持,java 所有方法要么放在类里,要么放在接口里
    cpstar
        2
    cpstar  
       5 天前
    可以匿名类+继承/实现的方法
    kapaseker
        3
    kapaseker  
       5 天前
    没有特别明白你说的啥,但是 Java 我记得也支持 lambda 表达式以及 this::someMethod 这种写法啊。还是说你就是希望像 Kotlin 那样,编写 aabb {} 代码?
    lisongeee
        4
    lisongeee  
       5 天前
    你的 js 能运行是因为 function 有变量提升,你换成 const 就不行了而且会报错

    此外如果你在函数里访问了外部 const 变量但是此时 const 变量还未初始化,也会报错
    qW7bo2FbzbC0
        5
    qW7bo2FbzbC0  
       5 天前
    @kapaseker lamda 我记得也是生成匿名类把这个方法附加上去?楼主说的这种,纯 OOP 风格的语言应该有点难度
    justdoit123
        6
    justdoit123  
       5 天前
    个人实在不喜欢函数里声明大量函数的做法。

    感觉一打开一个函数,就要先面对大量的“子函数”实现细节,然后才能看到函数本身的逻辑,这个跟你提问的苦恼一样。我感觉组织这种逻辑,还是 class 最适合。
    wolfie
        7
    wolfie  
       5 天前
    Why ???
    同一个 class 下 定义 private method 不行吗?
    必须 method 级别隔离吗?
    DIO
        8
    DIO  
    OP
       5 天前
    @kapaseker 是的,希望能实现函数内部嵌套子函数,但是子函数体{...}后置,母函数代码在最前面且能调用后面的子函数。
    tbc3211
        9
    tbc3211  
       5 天前
    内联函数 jvm 负责搞定了吧,开发 java 应该不用在意这些
    assiadamo
        10
    assiadamo  
       5 天前 via iPhone
    你可以嵌个 nashron js 引擎,java 调用 js 代码。
    不过 nashron 支持的 js 语法有限,比如=>就不支持
    Nitsuya
        11
    Nitsuya  
       5 天前
    lambda 对象, 类型转为 Function 这类的.. 相比 kt 这样做 会导致多这个匿名对象出来...
    DIO
        12
    DIO  
    OP
       5 天前
    @wolfie 因为有些逻辑确实只是为了让函数可读性更好而剥离出来的函数,基本没有类内其他函数复用的可能,后续改起来如果可以 metod 级别隔离,心理负担更小。
    meilicat
        13
    meilicat  
       5 天前
    lambda + function 可以,但还不如写方法。。。java 这块做得确实不如 py 、go 、cpp 好。
    wanniwa
        14
    wanniwa  
       5 天前
    不行。没理解为什么有这种需求。
    wolfie
        15
    wolfie  
       5 天前   ❤️ 1
    @DIO
    如果说,其他业务没法复用的话。
    你要不针对你的 FooBarService ,定义一个 FooBarHelper
    把这些 function 都扔到那里边,写好注释 仅服务于 @link FooBarService#myFunction
    acorngyl
        16
    acorngyl  
       5 天前
    不理解,把 multiply(),放类里和放方法里,就是写法不同,代码量上没区别吧?
    doubleData 和 multiply 都放一个类里,声明 private ,一样只能 parentFunction 内使用。现在的写法,也不能限制 parentFunction 内的其它方法调用 multiply 吧。
    就算是执行的时候,解释器也是把 parentFunction 和 multiply 当作两个独立的对象处理的,跟是不是嵌套,也没关系。parentFunction 说叫 function ,实际上就是个类,生成对象才加载内存的。
    yazinnnn0
        17
    yazinnnn0  
       5 天前
    啥函数式语言支持这种写法?
    edwardzcn98
        18
    edwardzcn98  
       5 天前
    没太看懂问题,函数式编程里也不能自行推断匿名函数行为
    BBCCBB
        19
    BBCCBB  
       5 天前
    我还以为你是想要用闭包直接在嵌套的函数里用 parent method 里定义的一些参数, 而不需要再次在方法上声明..

    结果你就是定义了一个简单方法.
    edwardzcn98
        20
    edwardzcn98  
       5 天前
    @wolfie #15 我觉得这个方案合理,为了可读性半解耦子函数还不如定义一个 helper 写明白,易于维护。

    怀疑楼主说的把“λ ...... {...} 函数体”后置是单子组合的写法,但这和你需求的 application 先于 define 不一致啊。
    caiqichang
        22
    caiqichang  
       4 天前
    你这段 kotlin 代码可以运行?
    xuanbg
        23
    xuanbg  
       4 天前
    lambda 可以把方法作为参数。但是,普通的方法调用你把对象作为参数就行了,没必要非得把对象的方案作为参数啊
    xuanbg
        24
    xuanbg  
       4 天前
    对象的方法,不是方案。笔误
    Belmode
        25
    Belmode  
       4 天前
    Java 做不到。一种语言有一种语言的范式,别套。
    layxy
        26
    layxy  
       4 天前
    lambda 可以在函数内定义函数,但是必须在调用前定义
    ychost
        27
    ychost  
       4 天前
    我们也是在历史业务里面嵌入 kotlin 的,慢慢迭代呗不存在积重难返,kt 和 java 交互没啥卡点,甚至还可以把 Groovy 加进来作为扩展点
    Dropless
        28
    Dropless  
       4 天前   ❤️ 1
    题外话, C# 的函数支持这样, 就跟 js 里一样, 一般叫 local function. 一个函数里有大量的 local function 肯定是不推荐的, 不过 js 里因为有闭包的需求, 这种范式倒是不少见. 如果一个函数(A)太长, 那么可以把部分代码单独作为另外一个函数(B), 如果 B 只会被 A 调用, 那么把 B 作为 A 的 local function 是合理的, 这样可以减轻对类成员的"污染"
    xiangyuecn
        29
    xiangyuecn  
       4 天前
    我的 java 骚操作,可以让 java 函数返回多个结果,用在闭包里面也是一样的,原理就是 1 个元素的数组

    final Func[] xxx=new Func[]{ null }

    .... 你的 lambda{
    xxx[0].xxx()
    }

    xxx[0]=()->{} 你的函数定义放后面
    Cbdy
        30
    Cbdy  
       4 天前
    Java 不是可以定义 Lambda 吗?
    netabare
        31
    netabare  
       4 天前 via Android
    没有办法做到,某种程度上说这是 Java 的一大缺陷了。

    放心,以后也不会修,因为这个功能养活了许多设计模式。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3563 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 04:26 · PVG 12:26 · LAX 20:26 · JFK 23:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.