天天看點

收藏!這些 IDE 使用技巧,你都知道嗎

欲善其事,先利其器。對于研發同學,在日常的開發工作中,我們與之打交道最多的便是程式設計的 IDE。能否高效和靈活的使用 IDE,将對我們的工作效率起着舉足輕重的作用。

收藏!這些 IDE 使用技巧,你都知道嗎

作者 | 璞珂

來源 | 阿裡巴巴雲原生公衆号

背景

1. 目的

研發同學在開發中最主要做的兩件事分别是架構設計和編碼,前者主要取決于大量的項目經驗積累和個人的思考深度,也是作為研發的核心競争力,短時間内很難快速求成;後者主要取決于日常的編碼練習和一定程度的 IDE 資訊差,能夠通過下文中介紹的一系列技巧進行能力的快速補齊和鞏固加強。

本文的主要目的有兩方面:

  • 一方面,對 IDE 的快捷操作和高效技巧,結合自己多年的實踐和了解,進行一次系統性的總結和梳理。
  • 另一方面,希望通過本文系統性的梳理,能夠幫助更多的同學提高研發效率,無論你是剛入手不久的新人,還是有着多年開發經驗的專家,相信你都能夠在本文中發現一片新天地,讓你能夠有更多的時間和精力去做更有意義的事情。

2. 定位

網上很多技術網站和個人部落格,對于 IDE 各種技巧和便捷操作總結得非常具體且詳細,對于單點的詳盡程度都是極具參考和學習價值的。但其對應的問題是,這些很多很優秀的文章,出自于不同的手筆,有各自的行文風格,且分散在各個網站的散點,難以系統化。

我對本文的定位是,将各種技巧以大分類的形式進行收攏和聚合,以幫助大家建構和完善整體的知識體系,大幅度提高開發效率。對于每個分類點到即止,替代咀嚼式灌輸方式的是,盡量使用漸進式引導的方式。

3. 普适性

JetBrains 系列的 IDE 産品衆多,除了下圖之外,還有其他未列入的,如 Google 二次開發的 Android Studio 等。雖然歸為多個産品執行個體,但這些 IDE 的核心都是一樣的,隻是在核心的基礎上額外添加了各自的語言特性。本文将以使用量最高的一款IDE——IDEA 為例進行展開,文中提到的絕大多數能力和技巧,在其他 IDE 均同樣适用,一通則百通。

收藏!這些 IDE 使用技巧,你都知道嗎

Postfix Completion

1. 介紹

Postfix Completion (下稱 Postfix) 是一種通過 . + 模闆 Key 來對目前已經輸出的表達式,添加和應用預設代碼模闆的編碼增強能力。

其核心要解決的問題是,将編碼過程中一些通用的代碼結構範式進行抽象和沉澱,并能在同類型的場景下,通過 . + 模闆 Key 的方式進行喚醒和複用。

舉個例子,現在需要完成下面一段代碼的編寫,為了對 name 參數進行判空保護:

if (name != null) {
  
}
           

在普通文本編輯器中,其中 if 2 次,name 4 次,(){}!= 共 6 次,再加空格 Tab 和光标切換,一共需要按鍵 23 次。

在 IDEA 編輯器中,不使用 Postfix 時,一共需要按鍵 20 次,不考慮代碼格式化的情況可以減少到 16 次。

在 IDEA 編輯器中,使用 Postfix 時,隻需要 8 次,如下圖:

收藏!這些 IDE 使用技巧,你都知道嗎

在這個例子中,可以對比出使用 Postfix 前後的效果,使用之後在編碼中減少了一半的手動按鍵操作,且生成的代碼是自帶格式化的。在實際的編碼過程中,各項目大小和複雜度差異性雖然很大,但細化到這種基本機關的程式設計範式時,它們都是融會貫通的。

與上例中 nn 并列的 Postfix,IDEA 給我們預設的還有很多,下面對一些非常高頻使用的 Postfix 進行梳理。

2. 梳理

1)var

快速定義一個局部變量,自帶 IDE 的類型推斷:

收藏!這些 IDE 使用技巧,你都知道嗎

2)notnull

快速進行 NPE 的判空保護:

收藏!這些 IDE 使用技巧,你都知道嗎

3)nn

同 notnull,是它的簡寫,推薦用這個,更加便捷:

收藏!這些 IDE 使用技巧,你都知道嗎

4)try catch

快速對目前語句添加 try catch 異常捕獲,同時 IDE 還會對 catch 中的 Exception 自動做類型推斷:

收藏!這些 IDE 使用技巧,你都知道嗎

5)cast

快速實作類型強轉,不需要反複使用()包裹和光标切換;配合instanceof使用時還能自動實作cast類型的推斷:

收藏!這些 IDE 使用技巧,你都知道嗎

6)if

快速實作 if 判斷的代碼範式:

收藏!這些 IDE 使用技巧,你都知道嗎

7)throw

快速實作抛異常:

收藏!這些 IDE 使用技巧,你都知道嗎

8)for

快速實作集合或數組的疊代:

收藏!這些 IDE 使用技巧,你都知道嗎

9)fori

快速實作集合或數組的帶索引值疊代;同時對整型數字也支援:

收藏!這些 IDE 使用技巧,你都知道嗎

10)sout/soutv

快速實作(不帶參數/帶參數)的列印功能:

收藏!這些 IDE 使用技巧,你都知道嗎

11)return

快速實作方法中的值傳回邏輯:

收藏!這些 IDE 使用技巧,你都知道嗎

12)format

快速實作字元串格式化:

收藏!這些 IDE 使用技巧,你都知道嗎

3. 進階用法

擔心系統預設的 Postfix 不足以滿足我們的編碼需求,IDEA 還提供了 Postfix 的自定義功能。

這裡我以自定義一個對集合判空的代碼範式,來舉例說明自定義 Postfix 的流程:

  • 進入 IDE 設定界面,然後依次進入 Editor => General => Postfix Completion => 面闆左下角加号 => Java:
收藏!這些 IDE 使用技巧,你都知道嗎
  • 在彈起的頁面中,按照下圖進行配置,然後儲存退出設定頁。
收藏!這些 IDE 使用技巧,你都知道嗎

此時我們自定義的 isempty 這個 Postfix 即完成了,下面來看下實際使用的效果:

收藏!這些 IDE 使用技巧,你都知道嗎

在實際開發過程中,對于根據已經輸入的表達式就能決定接下來代碼格式的功能,我們都能使用這種自定義方式進行代碼的抽象和複用。

接下來介紹 IDE 中一種跟 Postfix 功能很相像,但靈活度更高的能力 —— Live Template。

Live Template

介紹之前可以先看一段簡短的編碼過程:

收藏!這些 IDE 使用技巧,你都知道嗎

上面這段編碼中,我先後使用了 Live Template 的以下三個模闆能力:

  • psfs:定義字元串常量
  • main:添加入口函數
  • sout:實作日志輸出

這裡我們将其和上面提到的 Postfix 對比來看,兩者都是提供代碼級别模闆的功能。不同的是,Postfix 需要一個已經輸入的表達式和 . + 模闆 Key 來進行觸發,而 Live Template 不需要這些,它僅僅需要**模闆 Key **即可觸發。

Live Template 提供的預設模闆要比 Postfix 要高出一個數量級,是以這裡我就不進行一一示範,我們可以進行設定面闆,然後按照 Editor => Live Templates 的路徑自行檢視,如下圖:

收藏!這些 IDE 使用技巧,你都知道嗎

2. 進階用法

和 Postfix 一樣,Live Template 也支援自定義模闆,但它的自定義模闆相對來說更加靈活和開放,甚至支援我們直接植入腳本。鑒于 Live Template 的高度靈活性,單獨介紹這塊會占據大量的篇幅,是以這裡我将從幾個實際的案例場景來開拓一下思路,而具體自定義拓展過程就不詳細展開介紹了。

1)Key 值映射

将 DB 中查詢到 List 結構的資料,根據 Key 值映射轉化為 Map<K, T> 結構的資料,以便于進行後續的資料填充邏輯:

收藏!這些 IDE 使用技巧,你都知道嗎

2)DB 批量查詢

在資料查詢時,我們會有根據 ID 主鍵進行批量 DB 資料查詢的訴求,如下:

List<User> users = userMapper.queryUserByIds(userIds);
           

這種寫法會有一個弊端,就是當 userIds 大到一定的量級時,該查詢會變得非常耗時。

對于該問題其中一個解法是,将這個大的 userIds 拆分成多個批次,然後讓這多個批次異步并行去查詢。這裡便使用 Live Template 來抽取一個針對該場景的代碼模闆,如下:

收藏!這些 IDE 使用技巧,你都知道嗎

按照該模闆,我們的查詢語句将變成這樣:

List<User> users = batchQuery(userIds, 100, userMapper::queryUserByIds, null);
           

可以看到,和之前相比,多傳一個分批的 size 參數,同時還支援指定的異步任務排程器的自定義配置,而傳回結果和之前的查詢方式保持完全一緻,不需要外部有額外的适配工作。

3)腳本植入

這個功能是我非常看好 Live Template 的主要原因,它的靈活性和拓展性也主要來源于這裡。它支援我們通過一個**模闆 Key **來喚起和執行一段腳本,這也就意味着,我們的自定義的 Live Template 模闆是可程式設計的,極大程度提高了該模闆的拓展性。

單描述功能會有些空洞,這裡我結合一個實際案例進行介紹,我們來實作一個跨電腦的代碼共享功能:

  • 首先,使用 python 的 flask 架構寫一個極簡的服務端應用并啟動,提供最簡單的 push 和 pull 的能力,如下:
from flask import Flask, request

DEFAULT = 'nothing'
code = DEFAULT

app = Flask(__name__)

@app.route('/push')
def push():
  global code
  code = request.args.get('code', DEFAULT)
  return 'Success'

@app.route('/pull')
def pull():
  return code

app.run()
           
  • 然後,我們來通過 groovy 腳本實作一個代碼 pull 的模闆,這裡應用了 Live Template 的 groovy script 能力,對應腳本如下:
def url = new URL('http://127.0.0.1:5000/pull');
def conn = url.openConnection() as HttpURLConnection;
def result = conn.inputStream.text;
return result
           
  • 最後,再實作代碼 push 的模闆,腳本如下(下面的代碼入參,是通過剪切闆指派傳遞過來的):
def code = _1;
def url = new URL('http://127.0.0.1:5000/push?code=' + new URLEncoder().encode(code));
def conn = url.openConnection() as HttpURLConnection;
def result = conn.inputStream.text;
return result
           

此時就已經完成了跨裝置的代碼分享功能,為友善示範,這裡就用 People1 和 People2 兩個類來模拟兩台獨立的電腦。People1 将自己的一段代碼複制到剪切闆中,然後通過 push 模闆調用 push 接口來将這段代碼上傳到 Python 服務應用中;People2 再通過 pull 腳本來調用服務端的 pull 接口,通路到 People1 上傳的代碼并輸入到目前的代碼編輯器中,實作效果如下圖:

收藏!這些 IDE 使用技巧,你都知道嗎

這裡的代碼共享隻是一個引子,除此之外,我們還能寫很多有意思的腳本,比如在 IDE 中查天氣、通過 IDE 聊天等等,自行腦補拓展。

介紹完 Live Template 之後,接下來介紹檔案級别的模闆 —— File Template。

File Template

File Template,顧名思義,對應檔案級别的模闆。對于該模闆,我們使用腳本的主要在于兩個場景,分别是檔案頭和檔案的自定義,下面結合案例依次展開。

2. 自定義檔案頭

按照下圖的路徑,來更改檔案頭的格式,IDE 就會在我們建立一個類或接口時,根據這裡的配置格式來自動生成對應的檔案注釋頭。

收藏!這些 IDE 使用技巧,你都知道嗎

3. 抽象通用 Controller

看下面一段代碼,這是一個針對于 User 這個 domain 的增删改查接口類:

package com.alibaba.ide.code.controller;

import com.alibaba.ide.code.entity.Result;
import com.alibaba.ide.code.entity.User;
import com.alibaba.ide.code.service.Condition;
import com.alibaba.ide.code.service.UserService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;

/**
 * @author puke
 * @version 2021/2/9
 */
@RestController
@RequestMapping("api/user")
public class UserController {

    @Resource
    private UserService userService;

    @PostMapping
    public Result<User> create(@RequestBody User record) {
        User user = userService.insert(record);
        return Result.success(user);
    }

    @PutMapping
    public Result<User> update(@RequestBody User record) {
        User user = userService.update(record);
        return Result.success(user);
    }

    @DeleteMapping("{id}")
    public Result<Void> deleteById(@PathVariable Serializable id) {
        boolean success = userService.deleteById(id);
        return success ? Result.success() : Result.fail();
    }

    @GetMapping("{id}")
    public Result<User> queryById(@PathVariable Serializable id) {
        User user = userService.queryById(id);
        return Result.success(user);
    }

    @GetMapping
    public Result<List<User>> queryByCondition(Condition<User> condition) {
        List<User> list = userService.queryByCondition(condition);
        return Result.success(list);
    }
}
           

仔細看這段代碼會發現,如果基于該接口再新增另一個 domain 對應的 Controller 接口類,代碼中的基本結構和邏輯都是可以複用的。此時,便是 File Template 排上用場的地方,我們定義一個通用的 Controller 模闆,将共性的部分抽象到模闆裡,再将差異性的部分通過模闆入參 Subject 變量傳入進來(注,這裡需要用到 Velocity 模闆的知識)。

#set($SubjectOfLowerFirst = ${Subject.substring(0,1).toLowerCase()} + $Subject.substring(1))
package ${PACKAGE_NAME};

import com.alibaba.ide.code.entity.Result;
import com.alibaba.ide.code.entity.${Subject};
import com.alibaba.ide.code.service.Condition;
import com.alibaba.ide.code.service.${Subject}Service;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;

#parse("File Header.java")
@RestController
@RequestMapping("api/${SubjectOfLowerFirst}")
public class ${Subject}Controller {

    @Resource
    private ${Subject}Service ${SubjectOfLowerFirst}Service;

    @PostMapping
    public Result<${Subject}> create(@RequestBody ${Subject} record) {
        ${Subject} ${SubjectOfLowerFirst} = ${SubjectOfLowerFirst}Service.insert(record);
        return Result.success(${SubjectOfLowerFirst});
    }

    @PutMapping
    public Result<${Subject}> update(@RequestBody ${Subject} record) {
        ${Subject} ${SubjectOfLowerFirst} = ${SubjectOfLowerFirst}Service.update(record);
        return Result.success(${SubjectOfLowerFirst});
    }

    @DeleteMapping("{id}")
    public Result<Void> deleteById(@PathVariable Serializable id) {
        boolean success = ${SubjectOfLowerFirst}Service.deleteById(id);
        return success ? Result.success() : Result.fail();
    }

    @GetMapping("{id}")
    public Result<${Subject}> queryById(@PathVariable Serializable id) {
        ${Subject} ${SubjectOfLowerFirst} = ${SubjectOfLowerFirst}Service.queryById(id);
        return Result.success(${SubjectOfLowerFirst});
    }

    @GetMapping
    public Result<List<${Subject}>> queryByCondition(Condition<${Subject}> condition) {
        List<${Subject}> list = ${SubjectOfLowerFirst}Service.queryByCondition(condition);
        return Result.success(list);
    }
}
           

模闆定義完成,接下來看一下實際的使用效果:

收藏!這些 IDE 使用技巧,你都知道嗎

這裡使用 Goods 作為新的 domain 對象,可以看到,生成的 Controller 代碼已經具備 UserController 的全部能力,并且生成的代碼全部都是 Goods 相關的 api,這樣就實作了 File Template 的橫向遷移能力。

低頻高效快捷鍵

IDEA 中的快捷鍵多達上百個,我們很難把每個都記清楚,網上也有很多對應的總結。這裡我主要梳理一些,大家使用相對比較低頻,但又非常高效的快捷鍵。

1)選擇重複元素:Control + G

通常情況下,我們可以使用 Shift + F6 對類名、方法名和變量名進行批量更改,但對于其他元素進行批量更改時,該快捷鍵特别合适,且不限程式設計語言。

收藏!這些 IDE 使用技巧,你都知道嗎

2)批量框選:Option + 滑鼠左鍵拖拽

對于"對齊"的代碼進行批量更改的最優解,沒有之一:

收藏!這些 IDE 使用技巧,你都知道嗎

3)整行移動:Option + Shift + ↑/↓

快速調整代碼執行順序,免除繁瑣的剪切粘貼過程:

收藏!這些 IDE 使用技巧,你都知道嗎

4)整行/塊複制:Command + D

對于整行/塊的複制,效率遠高于純手動的複制粘貼:

收藏!這些 IDE 使用技巧,你都知道嗎

5)展開/收起:Command + . or Command + Shift + +/-

前者,快速顯示/隐藏目前方法體;後者,快速概覽目前類的所有方法:

收藏!這些 IDE 使用技巧,你都知道嗎

6)修改方法簽名:Command + F6

在方法被多檔案或多處調用時,該方式替換效率極高:

收藏!這些 IDE 使用技巧,你都知道嗎

7)檢視曆史剪切闆:Command + Shift + V

開發中經常會出現需要複制多個文本的訴求,而PC預設的剪切闆隻能儲存一個,該功能專門用來解決這個痛點:

收藏!這些 IDE 使用技巧,你都知道嗎

8)代碼抽取

代碼抽取主要用在代碼重構的時候,以最快速度達到我們抽取一個變量、方法的目的。

  • 抽局部變量:Command + Option + V
收藏!這些 IDE 使用技巧,你都知道嗎
  • 抽成員變量:Command + Option + F
收藏!這些 IDE 使用技巧,你都知道嗎
  • 抽靜态常量:Command + Option + C
收藏!這些 IDE 使用技巧,你都知道嗎
  • 抽方法入參:Command + Option + P
收藏!這些 IDE 使用技巧,你都知道嗎
  • 抽方法:Command + Option + M
收藏!這些 IDE 使用技巧,你都知道嗎

代碼調試

代碼調試在開發中使用的非常多,正常的單步、多步、進入、跳出操作這裡也不特殊說明了。

有一點值得說的就是,利用條件斷點來實作運作期的代碼植入功能,先看下圖:

收藏!這些 IDE 使用技巧,你都知道嗎

可以看到,Debug 模式運作時,我們能動态改變 age 變量的值,本來被指派為 20 的,結果輸出出來卻是 10。

這個是我在開發中無意間發現的一個功能,算是一個 Trick 了。但這個功能在實際的開發過程中特别有用,尤其針對于一些代碼改動後再次運作的成本比較高的場景。比如 Android 開發過程中,能夠在不重新打整包的情況下,動态修改頁面中各個元素的樣式、接口的請求、資料的内容等等;再比如服務端場景中,如果我們的應用支援 Debug 模式,則可以通過該功能實作應用無需重新部署的情況下,進行動态更改上下文邏輯的操作。

寫在最後

跬步至千裡,小流成江海,開發工作有大小,業務需求有緩急,但終究要落到眼下,從一磚一瓦的基石開始,從一行一列的編碼開始,希望本文中能幫助到更多的研發同學。

繼續閱讀