带有条件日志记录的闭包



我有一个这样的函数:

private downloadAllFiles() {
    sftpRetriever.listFiles().findAll {
        filter.isResponse(it) || filter.isResponseTurned(it)
    }.each { String fileName ->
        log.info 'Downloading file: {}', fileName
        sftpRetriever.downloadFile(fileName)
        log.info 'File downloaded'
        removeRemoteFile(fileName)
    }
}

我正在寻找一种简单的方法来在该函数中修改这个闭包,所以如果findAll的size()为0,它只会记录"没有更多的文件要下载"和.每个都不会被执行。有没有什么简单的方法可以使它在单个闭包中?如果我把它分成几个部分,这真的很简单,但要尝试在这里学习闭包并提高我的表达能力:)提前感谢您的帮助。

看看下面的生物:)它之所以有效,是因为each返回了调用它的集合(+elvis运算符和相当不错的Groovy真值评估):

def printContents(Collection collection) {
    collection.each {
        println it
    } ?: println('Collection is empty')
}
printContents([1,2,'hello'])
printContents([])

我不喜欢这种语法,但我想到的是较短的版本。

您还可以使用元编程来添加Steinar提供的方法。在第一次使用之前,它必须添加到metaClass中,但您将避免制作扩展模块:

Collection.metaClass.doIfEmpty { Closure ifEmptyClosure ->
        if (delegate.empty) {
            ifEmptyClosure()
        }
        return delegate
}
def printContents(Collection collection) {
    collection.doIfEmpty {
        println "Collection is empty"
    }.each {
        println it
    }
}
printContents([1,2,'hello'])
printContents([])

一个相当通用且可重复使用的选项是使用扩展模块扩展Collection。这非常容易做到,甚至在IDE中也能识别(至少在IntelliJ中),因此您可以完成代码等。

例如,为集合编写一个扩展类,如果集合为空,它将执行闭包。此外,它应该始终返回集合以允许进一步的链接:

package stackoverflow
class CollectionExtension {
    static <T extends Collection> T doIfEmpty(T self, Closure closure) {
        if (self.empty) {
            closure()
        }
        return self
    }
}

您还需要告诉groovy这个文件是一个扩展模块。在类路径上添加一个属性文件作为资源:META-INF/services/org.codehaus.groovy.runtime.ExtensionModule(注意:这个名称和位置对于扩展模块是强制性的,即您不能更改它)。

moduleName=stackoverflow-module
moduleVersion=1.0
extensionClasses=stackoverflow.CollectionExtension

最后是一个简单的测试脚本来展示如何使用它:

def printContents(Collection collection) {
    collection.doIfEmpty {
        println "Collection is empty"
    }.each {
        println it
    }
}
printContents([1,2,'hello'])
printContents([])

输出:

1
2
hello
Collection is empty

您可以尝试以下代码:

def l1 = [1,2,3,4]
def l2 = [5,6,7,8]
def m(list) {
    list.findAll { it < 5}.with { l ->
        size > 0 ? 
            l.each { e ->
                println e  
            }
        : 
            println('Zero elements found')
    }
}
m(l1)
m(l2)

目前没有更好的主意。

最新更新