動態語言的閉包是一個永恆的話題。閉包在編碼過程的方便和快捷使得動態語言的擁護者對它津津樂道,而靜態語言特別是Java語言的扇子們會拿出匿名內部類來說Java語言也有類似的功能。我使用Java語言至今也有六七年的時間了,實話來說我也很喜歡Java語言,但我萬萬不敢拿Java語言的匿名內部類和閉包來對比。因為匿名內部類的隱晦和繁瑣,使得我在編碼的過程中很少使用它,怎麼敢拿它出來吹噓呢?而在我使用Groovy編碼的不到一年的過程中,我卻時時刻刻在使用閉包。
閉包實在是太方便和靈活了,使得我在使用它的時候信手拈來。在我看來,閉包就像Groovy等動態語言給我們的一道魚翅大餐。這道大餐的好處需要我們慢慢的一一道來,記得星爺的《濟公》裡有一句台詞:來碗魚翅嗽嗽口。不錯,今天我們先要說說閉包在Groovy編碼過程中隨處可用小用法,權當使用閉包這碗魚翅來嗽嗽口。
溫馨提示,閱讀本文需要您有閉包的基礎知識。例如,關於閉包的定義及調用;閉包的參數、變量和返回值的作用域等一些簡單的基礎知識。當然,您也可以試著在閱讀本文的時候,同時把上述的基礎知識一並找來看,借此來相互理解和相互支持。對閉包基礎闡述得最清楚的書籍是《Groovy in Action》
一.小試身手,隨處可用
Java語言的編碼過程中,有隨處可見的我們用起來覺得別扭的地方,卻又無計可施。例如,我們經常要對一系列的String進行非空判斷以後再進行操作:
if(str1!=null&&!str1.trim().equals(“”))
{
……
}
if(str2!=null&&!str2.trim().equals(“”))
{
……
}
if(str3!=null&&!str3.trim().equals(“”))
{
……
}
……
這樣反復的if判斷真讓人忍無可忍,但是你沒有好的解決辦法,只能這樣五個、六個甚至十個的寫下去。
Stop!我們來考慮一下閉包的解決方案吧。
來,我們先定義一個閉包,很簡單。
def isNotNull = {
str,Closure closure ->
if(str!=null&&!str.trim().equals(""))
{
closure.call()
}
}
很普通的一個閉包,兩個輸入參數,如果沒明白的話,現在就翻出閉包的基礎知識看一看。
簡單的閉包定義好了以後,我們就可以開始使用它了:
def abc = 'abc'
isNotNull(abc)
{
println abc
}
在上面的例子中,我們小試牛刀了一次,只是判斷了一下字符串abc是否為空,如果不為空就打印到控制台。比起我們上面的if語言,是不是簡潔多了。
像這樣的用法,我們在編碼的過程中隨處可見,下面再舉一個例子:
String cateType = getRequest().getParameter("cateType");//1: 確認存儲 2:反確認
String cateId = getRequest().getParameter("cateId");
String year = getRequest().getParameter("year");
String percent = getRequest().getParameter("percent");
不錯,這是一段獲取request參數的代碼。我們在寫這樣的代碼的時候,多了就會郁悶,我老是先要getRequest,然後getParameter,重復的同樣的鍛煉我們的盲打能力。
Stop!我們來使用閉包減輕我們的打字頻率吧。
同樣,先是定義一個閉包:
def getReqParam = {
paramName ->
return getRequest().getParameter(paramName)
}
那麼,上面的代碼,我們可以寫成下面的樣子:
String cateType = getReqParam("cateType");//1: 確認存儲 2:反確認
String cateId = getReqParam("cateId");
String year = getReqParam("year");
String percent = getReqParam("percent");
怎麼樣,是不是簡潔多了?
二.神來之筆
除了上面的一些小用法,閉包的靈活性在編碼的過程中隨時可能顯示出來。你會在Java編程過程中隨時找到一些對閉包的妙用。
比如,我們在編碼的過程中,隨時會做一些log記錄。
logger.debug("importPartList condition:");
logger.debug("userid=" + excelModel.getUserid());
這樣的log是我們常用的,但鑒於性能方面的要求,我們實際上不會直接打印log,而是首先判斷log的開關狀態。如下:
if (logger.isDebugEnabled()) {
logger.debug("isPPRMBuyer=" + isPPRMBuyer);
}
下面的一小段代碼就是這樣一個場景。
if (logger.isDebugEnabled()){
logger.debug("updateAfterUploadRaw start:");
}
ret = (String)dao.getObjectByStoredProcedure(
"updateBuyerCRDetail",
map,
new String[]{"v_matetype"},
OracleTypes.VARCHAR);
if (logger.isDebugEnabled()){
logger.debug("1. updateBuyerCRDetail result ret=" + ret);
}
if(!ret.equals("0"))
{
errMsg += "Update Buyer管控總表 failed! ";
}
ret = (String)dao.getObjectByStoredProcedure(
"updateBuyerCRDetailYt",
map,
new String[]{"v_matetype"},
OracleTypes.VARCHAR);
if (logger.isDebugEnabled()){
logger.debug("2. updateBuyerCRDetailYt result ret=" + ret);
}
可以看到,就是上面的一小段代碼,卻已經使用了三個if (logger.isDebugEnabled())。
這樣重復使用的判斷語句讓我們在編碼的過程中相當郁悶,可能有很多人想把它抽象成下面的一個方法:
publicstaticvoid debug(logger,String str)
{
if(logger.isDebugEnabled())
{
logger.debug(str);
}
}
這樣使用使用固然是方便了很多,但卻違背了我們使用該判斷語句的初衷,即不能解決性能方面的問題。
顯然,這不是一個好的解決方法。
現在,我們來看看閉包的解決方法:
def isdebuged = {
Closure closure ->
if(logger.isDebugEnabled())
{
closure.call();
}
}
使用這個閉包,上面的那一小段代碼就變成下面的樣子:
isdebuged {
logger.debug("updateAfterUploadRaw start:");
}
ret = (String)dao.getObjectByStoredProcedure(
"updateBuyerCRDetail",
map,
new String[]{"v_matetype"},
OracleTypes.VARCHAR);
isdebuged {
logger.debug("1. updateBuyerCRDetail result ret=" + ret);
}
if(!ret.equals("0"))
{
errMsg += "Update Buyer管控總表 failed! ";
}
ret = (String)dao.getObjectByStoredProcedure(
"updateBuyerCRDetailYt",
map,
new String[]{"v_matetype"},
OracleTypes.VARCHAR);
isdebuged {
logger.debug("2. updateBuyerCRDetailYt result ret=" + ret);
}
這樣,我們就可以從寫if判斷語句中解脫出來。
好了,作為系列《Groovy探索之閉包》的第一篇,我們暫時談到這裡。上面的例子可能有人覺得毫無意義,沒有太大的用處,但是我舉出這些例子是為了提供一些使用閉包的思路,並不見得實際編碼過程中就要這樣用。
閉包還有很多有趣的、方便快捷的使用方法。我們會在後續的文字中一一道來。