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

Java 中可以做到函数嵌套吗

  •  
  •   DIO · 17 天前 · 3645 次点击

    我知道可以通过 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  
       17 天前
    不支持,java 所有方法要么放在类里,要么放在接口里
    cpstar
        2
    cpstar  
       17 天前
    可以匿名类+继承/实现的方法
    kapaseker
        3
    kapaseker  
       17 天前
    没有特别明白你说的啥,但是 Java 我记得也支持 lambda 表达式以及 this::someMethod 这种写法啊。还是说你就是希望像 Kotlin 那样,编写 aabb {} 代码?
    lisongeee
        4
    lisongeee  
       17 天前
    你的 js 能运行是因为 function 有变量提升,你换成 const 就不行了而且会报错

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

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

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

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

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

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

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

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