Java開發(fā)過程中往往需要編寫固定格式的代碼,比如聲明私有變量、logger或者bean等。對(duì)于這種小規(guī)模的代碼生成,我們可以使用IDEA提供的Live Templates功能。
 1 背景
Java開發(fā)過程中往往需要編寫固定格式的代碼,比如聲明私有變量、logger或者bean等。對(duì)于這種小規(guī)模的代碼生成,我們可以使用IDEA提供的Live Templates功能。一開始我以為它只是一個(gè)簡(jiǎn)單的Code Snippet,后來發(fā)現(xiàn)它支持變量函數(shù)配置,可以支持非常復(fù)雜的代碼生成。下面介紹一下Live Templates的用法。
2 基本使用
IDEA自帶很多常用的動(dòng)態(tài)模板,在Java代碼中輸入fori,回車會(huì)出現(xiàn):
for (int i = 0; i < ; i++) {
}按 T?ab 跳入每個(gè)空白并手動(dòng)填寫值。

更多 IDEA 操作如下:
public class Example {
    // geti 生成單例語句
    public static Example getInstance() {
        return new Example();
    }
    // prsf 生成 private static final
    private static final ...;
    // psf 生成 public static final
    public static final ...;
    // psfi 生成 public static final int
    public static final int ...;
    // psfs 生成 public static final String
    public static final String ...;
    // main 或者 psvm 生成 main 函數(shù)
    public static void main(String[] args) {
        // fori 生成 for 循環(huán)
        for (int i = 0; i < 10; i++) {
        }
        // C 生成 Callable
        Callable<Object> callable = new Callable<Object>() {
            public Object call() throws Exception {
            }
        };
        // I 生成遍歷語句
        for (Object o :) {
        }
        // ifn 生成 if null 語句
        if (callable == null) {
        }
        // inn 生成 if not null 語句
        if (callable != null) {
        }
        // inst 生成 instanceof 語句
        if (callable instanceof Object) {
            Object o = (Object) callable;
        }
        // itar 生成數(shù)組遍歷語句
        for (int i = 0; i < args.length; i++) {
            String arg = args[i];
        }
        // itco 生成 java.util.Collection 遍歷語句
        for (Iterator iterator = collection.iterator(); iterator.hasNext(); ) {
            Object next =  iterator.next();
        }
        // iten 生成 java.util.Enumeration 遍歷語句
        while (enumeration.hasMoreElements()) {
            Object nextElement = enumeration.nextElement();
        }
        // iter 生成 Iterable 或 數(shù)組 遍歷語句
        for (String arg : args) {
        }
        // itit 生成 java.util.Iterator 遍歷語句
        while (iterator.hasNext()) {
            Object next = iterator.next();
        }
        // itli 生成 java.util.List 遍歷語句
        for (int i = 0; i < list.size(); i++) {
            Object o = list.get(i);
        }
        // ittok 生成遍歷 token 的語句
        for (StringTokenizer stringTokenizer = new StringTokenizer(); stringTokenizer.hasMoreTokens(); ) {
            String s = stringTokenizer.nextToken();
        }
        // lazy 生成延遲初始化語句
        if (callable == null) {
            callable = new Callable<Object>();
        }
        // lst 生成獲取數(shù)組最后一個(gè)元素語句
        args[args.length - 1];
        // mn 生成 Math.min
        min = Math.min(min, max);
        // mx 生成 Math.max
        max = Math.max(max, min);
        // ritar 生成降序遍歷數(shù)組的語句
        for (int i = args.length - 1; i >= 0; i--) {
            String arg = args[i];
        }
        // RL 生成 ReadWriteLock.readLock()
        ReadWriteLock.readLock().lock();
        try {
        } finally {
            ReadWriteLock.readLock().unlock();
        }
        // serr 生成 System.err.println()
        System.err.println();
        // serrc 生成 System.err::println
        System.err::println;
        // souf 生成 System.out.printf("")
        System.out.printf("");
        // sout 生成 System.out.println()
        System.out.println();
        // soutc 生成 System.out::println
        System.out::println;
        // soutm 生成打印當(dāng)前類和方法的語句
        System.out.println("Example.main");
        // soutp 生成打印當(dāng)前方法的參數(shù)名字和值
        System.out.println("args = " + Arrays.deepToString(args));
        // soutv 生成打印一個(gè)值的語句
        System.out.println("callable = " + callable);
        // St 生成 String
        String ;
        // thr 生成 throw new
        throw new;
        // toar 生成 java.util.Collection 元素到數(shù)組的語句
        .toArray(new Object[0]);
        // WL 生成 WriteLock.writeLock() 語句
        ReentrantReadWriteLock.WriteLock.writeLock().lock();
        try {
        } finally {
            ReentrantReadWriteLock.WriteLock.writeLock().unlock();
        }
    }
}3 自定義模板
畢竟官方內(nèi)置的模板不能滿足我們個(gè)人編碼風(fēng)格的需求。Live Templates 提供了可變函數(shù)供我們自定義。
簡(jiǎn)單用法
添加自定義模板,首先需要填寫觸發(fā)詞(即Abbreviation),描述可選,然后定義模板的上下文,點(diǎn)擊define選擇Java,這樣編輯Java的時(shí)候就會(huì)觸發(fā)當(dāng)前模板,定義好上下文后,就可以填寫模板了。

比如定義一個(gè)私有變量:

通過輸入 privateField 就可以輸出以下代碼:
/**
 * $COMMENT$
 */
@Getter
@Setter
private $TYPE$ $NAME$;
模板支持定義變量,$$包圍的字符代表一個(gè)變量。$END$ 是一個(gè)特殊的預(yù)定義變量,表示光標(biāo)最后跳轉(zhuǎn)的位置。每個(gè)變量的位置都可以跳轉(zhuǎn)到。
4 進(jìn)階用法
如果你用過vim的Code Sinppet插件,你會(huì)發(fā)現(xiàn)函數(shù)可以在模板中執(zhí)行,當(dāng)然強(qiáng)大的Live Templates也支持,IDEA可以感知代碼的語義,比如參數(shù)當(dāng)前編輯的功能。但這就是讓我們玩得開心的原因。我們從易到難探索模板函數(shù)的功能。

前面我們提到的變量可以綁定到函數(shù)上,配置方法如上圖所示。
聲明變量是一個(gè)常見的操作,尤其是需要聲明需要注解的變量時(shí)。注釋的時(shí)候,這些代碼寫起來很枯燥。這是我定義的模板:

聲明 logger 也是一個(gè)常見的操作?,F(xiàn)在我們使用一個(gè)函數(shù) className() 來實(shí)現(xiàn)。顧名思義,它的作用就是返回當(dāng)前的類名。

5 總結(jié)
上面我們簡(jiǎn)單介紹了常用的模板函數(shù)。其實(shí)IDEA還有很多其他的模板函數(shù)。有關(guān)詳細(xì)信息,請(qǐng)參閱創(chuàng)建和編輯模板變量。IDEA 是一個(gè)非常強(qiáng)大的工具。善用工具可以大大提高工作效率,把精力集中在關(guān)鍵的事情上,而不是把時(shí)間浪費(fèi)在寫重復(fù)的代碼上。一些更高級(jí)的用法還有待發(fā)現(xiàn)。好好利用它,也可以省下很多重復(fù)寫代碼的時(shí)間。