0

0

Groovy中利用闭包优雅合并相似轮询方法

聖光之護

聖光之護

发布时间:2025-11-05 15:53:02

|

358人浏览过

|

来源于php中文网

原创

Groovy中利用闭包优雅合并相似轮询方法

本文探讨了在groovy中如何通过闭包(closure)来优雅地合并具有相似逻辑但条件判断不同的轮询方法,以减少代码冗余并提高可维护性。通过引入一个通用的`waituntil`方法,它接受一个返回布尔值的闭包作为条件检查器,并支持自定义重试间隔和最大重试次数,从而实现灵活且高效的条件等待机制,同时优化了潜在的垃圾回收开销。

优化相似轮询逻辑的挑战

软件开发中,我们经常会遇到需要等待某个条件满足才能继续执行的场景。这些场景往往表现为一段轮询代码,其核心逻辑是在一个循环中反复检查某个状态,直到满足特定条件后退出。当存在多个这样的轮询逻辑,它们之间除了条件判断不同外,其余部分(如循环结构、等待机制、错误处理)高度相似时,代码冗余就会成为一个问题。

例如,考虑以下两个Groovy方法:

def someCondition = false

def method1() {
    while(!someCondition) {
        def connectionStatus = getConnectionStatus() // return 200, 404, etc.
        if (connectionStatus == 200) {
            someCondition = true
        } else {
            println "repeat until connection is 200"
            sleep 15
        }
    }
}

def method2(){
    while(!someCondition) {
        def result = getResult() // A, B, C, etc. 
        if (result in ["A", "B", "C"]) {
            someCondition = true
        } else {
            println "waiting until result is either A, B, or C"
            sleep 15
            result = getResult() // call again to check if result changed
        }
    }
}

这两个方法都包含了一个while循环、一个内部的条件检查以及一个sleep调用。它们的区别仅在于if语句中的具体条件。直接复制粘贴并修改条件虽然可行,但会导致代码重复,降低可维护性。当需要修改等待逻辑(例如,改变等待时间或增加最大重试次数)时,必须修改所有相似的方法,这增加了出错的风险。

利用闭包实现通用等待机制

Groovy的闭包(Closure)提供了一种优雅的方式来抽象行为,使其作为参数传递给方法。我们可以利用这一特性,将上述两个方法中不同的条件判断逻辑封装成闭包,然后传递给一个通用的等待方法。

下面是一个名为waitUntil的通用方法,它接受一个闭包作为参数,该闭包负责执行实际的条件检查并返回一个布尔值(true表示条件满足,false表示条件不满足)。

/**
 * 等待直到指定条件满足。
 * @param sleep 每次重试之间的等待时间(毫秒)。
 * @param maxRetries 最大重试次数。
 * @param test 一个闭包,执行条件检查并返回布尔值。
 */
def waitUntil(int sleep = 1, int maxRetries = 10, Closure test) {
    int retries = 0
    while (retries++ < maxRetries && !test()) {
        println "Failed at attempt $retries/$maxRetries, sleeping for $sleep ms before retrying"
        Thread.sleep(sleep)
    }
    // 可以在此处添加逻辑来判断是否成功,例如返回一个布尔值
    // return test() // 返回最终条件是否满足
}

方法解析:

  • sleep:每次重试之间的等待时间,默认为1毫秒。
  • maxRetries:最大重试次数,默认为10次。
  • test:这是一个Closure类型的闭包,它不接受参数,并期望返回一个布尔值。当test()返回true时,表示条件已满足,循环终止。
  • retries++
  • !test():如果条件未满足(闭包返回false),则继续循环。
  • Thread.sleep(sleep):暂停当前线程以避免忙等。

如何使用:

有了waitUntil方法,我们可以将之前的两个示例方法重构为简洁的调用:

// 假设 getConnectionStatus() 和 getResult() 是已定义的方法

// 对应 method1 的场景
waitUntil {
    getConnectionStatus() == 200
}

// 对应 method2 的场景
waitUntil {
    getResult() in ["A", "B", "C"]
}

此外,waitUntil方法还支持自定义等待参数:

Magician
Magician

Figma插件,AI生成图标、图片和UX文案

下载
// 等待时间更长(100毫秒)
waitUntil(100) {
    getResult() in ["A", "B", "C"]
}

// 等待时间更长(100毫秒),且只重试5次
waitUntil(100, 5) {
    getResult() in ["A", "B", "C"]
}

通过这种方式,我们成功地将重复的轮询逻辑抽象到一个通用方法中,极大地减少了代码冗余,并提高了灵活性。

优化闭包中的对象创建

在使用闭包进行条件检查时,需要注意一个潜在的性能问题:如果闭包内部每次执行都会创建新的对象(例如,每次都创建一个新的列表),在长时间运行或高速循环的任务中,这可能导致大量的临时对象被创建,从而增加垃圾回收的负担。

以上述 getResult() in ["A", "B", "C"] 为例,每次闭包执行时都会创建一个新的 ["A", "B", "C"] 列表。为了优化这一点,我们可以修改waitUntil方法,使其能够接受期望值作为参数,并将这些值传递给闭包。这样,列表或其他期望对象只需创建一次。

/**
 * 等待直到指定条件满足,支持传递期望值到闭包。
 * @param expectedResult 期望的结果值,可以是一个列表、单个值或其他任何闭包所需的参数。
 * @param sleep 每次重试之间的等待时间(毫秒)。
 * @param maxRetries 最大重试次数。
 * @param test 一个闭包,执行条件检查并返回布尔值。它接受 expectedResult 作为参数。
 */
def waitUntil(Object expectedResult, int sleep = 1, int maxRetries = 10, Closure test) {
    int retries = 0
    while (retries++ < maxRetries && !test(expectedResult)) { // 将 expectedResult 传递给闭包
        println "Failed at attempt $retries/$maxRetries, sleeping for $sleep ms before retrying"
        Thread.sleep(sleep)
    }
    // return test(expectedResult) // 返回最终条件是否满足
}

使用优化后的方法:

// 期望结果列表只创建一次
waitUntil(["A", "B", "C"]) { expected -> // 闭包现在接受一个参数
    getResult() in expected // 使用传入的 expected 参数
}

// 也可以传递单个值
waitUntil(200) { expectedStatus ->
    getConnectionStatus() == expectedStatus
}

在这个优化版本中,["A", "B", "C"] 列表只在 waitUntil 方法被调用时创建一次,然后作为参数传递给闭包。闭包在每次执行时,都使用这个已经存在的列表进行比较,避免了重复创建对象的开销。

总结与注意事项

通过利用Groovy的闭包特性,我们可以将相似的轮询等待逻辑进行高度抽象和合并,从而实现:

  • 代码去重(DRY原则):消除了重复的轮询结构。
  • 提高可维护性:所有等待逻辑的修改都集中在一个地方。
  • 增强灵活性:通过参数和闭包,可以轻松定制等待时间、重试次数和具体条件。
  • 优化性能:通过将期望值作为参数传递,减少了闭包内部的重复对象创建。

注意事项:

  1. 异常处理:在test闭包内部执行的操作(如getConnectionStatus()或getResult())可能会抛出异常。在实际应用中,你可能需要在闭包内部或waitUntil方法中添加适当的异常捕获和处理逻辑。
  2. 日志记录:waitUntil方法中简单的println语句可以替换为更专业的日志框架(如Log4j或SLF4J),以便更好地控制日志输出级别和目标。
  3. 超时机制:虽然maxRetries提供了一种超时机制,但有时直接设置一个总的等待时间会更直观。可以考虑在waitUntil方法中增加一个timeoutMillis参数,与maxRetries结合使用或作为替代。
  4. 异步操作:对于涉及异步操作的等待场景,闭包同样强大。可以修改test闭包来检查Future、Promise或其他异步结果的状态。

通过上述方法,Groovy开发者可以编写出更简洁、更健壮、更易于维护的轮询等待代码。

相关专题

更多
java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

342

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

19

2025.11.30

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

697

2023.08.22

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

79

2023.09.25

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

462

2023.08.10

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

53

2025.12.01

java值传递和引用传递有什么区别
java值传递和引用传递有什么区别

java值传递和引用传递的区别:1、基本数据类型的传递;2、对象的传递;3、修改引用指向的情况。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

106

2024.02.23

go语言闭包相关教程大全
go语言闭包相关教程大全

本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

130

2025.07.29

苹果官网入口直接访问
苹果官网入口直接访问

苹果官网直接访问入口是https://www.apple.com/cn/,该页面具备0.8秒首屏渲染、HTTP/3与Brotli加速、WebP+AVIF双格式图片、免登录浏览全参数等特性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

7

2025.12.24

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.8万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号