<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 9462字,需瀏覽 19分鐘

           ·

          2021-03-07 19:34

          一  背景


          1  目的


          欲善其事,先利其器。對(duì)于研發(fā)同學(xué),在日常的開(kāi)發(fā)工作中,我們與之打交道最多的便是編程的IDE。能否高效和靈活的使用IDE,將對(duì)我們的工作效率起著舉足輕重的作用。


          研發(fā)同學(xué)在開(kāi)發(fā)中最主要做的兩件事分別是架構(gòu)設(shè)計(jì)和編碼,前者主要取決于大量的項(xiàng)目經(jīng)驗(yàn)積累和個(gè)人的思考深度,也是作為研發(fā)的核心競(jìng)爭(zhēng)力,短時(shí)間內(nèi)很難快速求成;后者主要取決于日常的編碼練習(xí)和一定程度的IDE信息差,能夠通過(guò)下文中介紹的一系列技巧進(jìn)行能力的快速補(bǔ)齊和鞏固加強(qiáng)。


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


          • 一方面,對(duì)IDE的快捷操作和高效技巧,結(jié)合自己多年的實(shí)踐和理解,進(jìn)行一次系統(tǒng)性的總結(jié)和梳理。


          • 另一方面,希望通過(guò)本文系統(tǒng)性的梳理,能夠幫助更多的同學(xué)提高研發(fā)效率,無(wú)論你是剛?cè)胧植痪玫男氯耍€是有著多年開(kāi)發(fā)經(jīng)驗(yàn)的專(zhuān)家,相信你都能夠在本文中發(fā)現(xiàn)一片新天地,讓你能夠有更多的時(shí)間和精力去做更有意義的事情。


          2  定位


          網(wǎng)上很多技術(shù)網(wǎng)站和個(gè)人博客,對(duì)于IDE各種技巧和便捷操作總結(jié)得非常具體且詳細(xì),對(duì)于單點(diǎn)的詳盡程度都是極具參考和學(xué)習(xí)價(jià)值的。但其對(duì)應(yīng)的問(wèn)題是,這些很多很優(yōu)秀的文章,出自于不同的手筆,有各自的行文風(fēng)格,且分散在各個(gè)網(wǎng)站的散點(diǎn),難以系統(tǒng)化。


          我對(duì)本文的定位是,將各種技巧以大分類(lèi)的形式進(jìn)行收攏和聚合,以幫助大家構(gòu)建和完善整體的知識(shí)體系,大幅度提高開(kāi)發(fā)效率。對(duì)于每個(gè)分類(lèi)點(diǎn)到即止,替代咀嚼式灌輸方式的是,盡量使用漸進(jìn)式引導(dǎo)的方式。


          3  普適性


          JetBrains系列的IDE產(chǎn)品眾多,除了下圖之外,還有其他未列入的,如Google二次開(kāi)發(fā)的Android Studio等。雖然歸為多個(gè)產(chǎn)品實(shí)例,但這些IDE的內(nèi)核都是一樣的,只是在內(nèi)核的基礎(chǔ)上額外添加了各自的語(yǔ)言特性。本文將以使用量最高的一款I(lǐng)DE——IDEA為例進(jìn)行展開(kāi),文中提到的絕大多數(shù)能力和技巧,在其他IDE均同樣適用,一通則百通。



          二  Postfix Completion


          1  介紹


          Postfix Completion (下稱(chēng)Postfix) 是一種通過(guò) . + 模板Key 來(lái)對(duì)當(dāng)前已經(jīng)輸出的表達(dá)式,添加和應(yīng)用預(yù)設(shè)代碼模板的編碼增強(qiáng)能力。


          其核心要解決的問(wèn)題是,將編碼過(guò)程中一些通用的代碼結(jié)構(gòu)范式進(jìn)行抽象和沉淀,并能在同類(lèi)型的場(chǎng)景下,通過(guò) . + 模板Key 的方式進(jìn)行喚醒和復(fù)用。


          舉個(gè)例子,現(xiàn)在需要完成下面一段代碼的編寫(xiě),為了對(duì)name參數(shù)進(jìn)行判空保護(hù):


          if (name != null) {}


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


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


          在IDEA編輯器中,使用Postfix時(shí),只需要8次,如下圖:



          在這個(gè)例子中,可以對(duì)比出使用Postfix前后的效果,使用之后在編碼中減少了一半的手動(dòng)按鍵操作,且生成的代碼是自帶格式化的。在實(shí)際的編碼過(guò)程中,各項(xiàng)目大小和復(fù)雜度差異性雖然很大,但細(xì)化到這種基本單位的編程范式時(shí),它們都是融會(huì)貫通的。


          與上例中nn并列的Postfix,IDEA給我們預(yù)設(shè)的還有很多,下面對(duì)一些非常高頻使用的Postfix進(jìn)行梳理。


          2  梳理


          var


          快速定義一個(gè)局部變量,自帶IDE的類(lèi)型推斷



          notnull


          快速進(jìn)行NPE的判空保護(hù):



          nn


          同notnull,是它的簡(jiǎn)寫(xiě),推薦用這個(gè),更加便捷:



          try catch


          快速對(duì)當(dāng)前語(yǔ)句添加try catch異常捕獲,同時(shí)IDE還會(huì)對(duì)catch中的Exception自動(dòng)做類(lèi)型推斷:



          cast


          快速實(shí)現(xiàn)類(lèi)型強(qiáng)轉(zhuǎn),不需要反復(fù)使用()包裹和光標(biāo)切換;配合instanceof使用時(shí)還能自動(dòng)實(shí)現(xiàn)cast類(lèi)型的推斷:



          if


          快速實(shí)現(xiàn)if判斷的代碼范式:



          throw


          快速實(shí)現(xiàn)拋異常:



          for


          快速實(shí)現(xiàn)集合或數(shù)組的迭代:



          fori


          快速實(shí)現(xiàn)集合或數(shù)組的帶索引值迭代;同時(shí)對(duì)整型數(shù)字也支持:



          sout/soutv


          快速實(shí)現(xiàn)(不帶參數(shù)/帶參數(shù))的打印功能:



          return


          快速實(shí)現(xiàn)方法中的值返回邏輯:



          format


          快速實(shí)現(xiàn)字符串格式化:



          3  高級(jí)用法


          擔(dān)心系統(tǒng)預(yù)設(shè)的Postfix不足以滿(mǎn)足我們的編碼需求,IDEA還提供了Postfix的自定義功能。


          這里我以自定義一個(gè)對(duì)集合判空的代碼范式,來(lái)舉例說(shuō)明自定義Postfix的流程:


          1)進(jìn)入IDE設(shè)置界面,然后依次進(jìn)入Editor => General => Postfix Completion => 面板左下角加號(hào) => Java:



          2)在彈起的頁(yè)面中,按照下圖進(jìn)行配置,然后保存退出設(shè)置頁(yè)。



          此時(shí)我們自定義的 isempty 這個(gè)Postfix即完成了,下面來(lái)看下實(shí)際使用的效果:



          在實(shí)際開(kāi)發(fā)過(guò)程中,對(duì)于根據(jù)已經(jīng)輸入的表達(dá)式就能決定接下來(lái)代碼格式的功能,我們都能使用這種自定義方式進(jìn)行代碼的抽象和復(fù)用。


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


          三  Live Template


          1  介紹


          介紹之前可以先看一段簡(jiǎn)短的編碼過(guò)程:



          上面這段編碼中,我先后使用了Live Template的以下三個(gè)模板能力:


          • psfs:定義字符串常量
          • main:添加入口函數(shù)
          • sout:實(shí)現(xiàn)日志輸出


          這里我們將其和上面提到的Postfix對(duì)比來(lái)看,兩者都是提供代碼級(jí)別模板的功能。不同的是,Postfix需要一個(gè)已經(jīng)輸入的表達(dá)式和 . + 模板Key 來(lái)進(jìn)行觸發(fā),而Live Template不需要這些,它僅僅需要 模板Key 即可觸發(fā)。


          Live Template提供的預(yù)設(shè)模板要比Postfix要高出一個(gè)數(shù)量級(jí),因此這里我就不進(jìn)行一一演示,我們可以進(jìn)行設(shè)置面板,然后按照Editor => Live Templates的路徑自行查看,如下圖:



          2  高級(jí)用法


          和Postfix一樣,Live Template也支持自定義模板,但它的自定義模板相對(duì)來(lái)說(shuō)更加靈活和開(kāi)放,甚至支持我們直接植入腳本。鑒于Live Template的高度靈活性,單獨(dú)介紹這塊會(huì)占據(jù)大量的篇幅,因此這里我將從幾個(gè)實(shí)際的案例場(chǎng)景來(lái)開(kāi)拓一下思路,而具體自定義拓展過(guò)程就不詳細(xì)展開(kāi)介紹了。


          Key值映射


          將DB中查詢(xún)到 List<T> 結(jié)構(gòu)的數(shù)據(jù),根據(jù)Key值映射轉(zhuǎn)化為 Map<K, T> 結(jié)構(gòu)的數(shù)據(jù),以便于進(jìn)行后續(xù)的數(shù)據(jù)填充邏輯:



          DB批量查詢(xún)


          在數(shù)據(jù)查詢(xún)時(shí),我們會(huì)有根據(jù)ID主鍵進(jìn)行批量DB數(shù)據(jù)查詢(xún)的訴求,如下:


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


          這種寫(xiě)法會(huì)有一個(gè)弊端,就是當(dāng) userIds 大到一定的量級(jí)時(shí),該查詢(xún)會(huì)變得非常耗時(shí)。


          對(duì)于該問(wèn)題其中一個(gè)解法是,將這個(gè)大的 userIds 拆分成多個(gè)批次,然后讓這多個(gè)批次異步并行去查詢(xún)。這里便使用Live Template來(lái)抽取一個(gè)針對(duì)該場(chǎng)景的代碼模板,如下:



          按照該模板,我們的查詢(xún)語(yǔ)句將變成這樣:


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


          可以看到,和之前相比,多傳一個(gè)分批的size參數(shù),同時(shí)還支持指定的異步任務(wù)調(diào)度器的自定義配置,而返回結(jié)果和之前的查詢(xún)方式保持完全一致,不需要外部有額外的適配工作。


          腳本植入


          這個(gè)功能是我非常看好Live Template的主要原因,它的靈活性和拓展性也主要來(lái)源于這里。它支持我們通過(guò)一個(gè) 模板Key 來(lái)喚起和執(zhí)行一段腳本,這也就意味著,我們的自定義的Live Template模板是可編程的,極大程度提高了該模板的拓展性。


          單描述功能會(huì)有些空洞,這里我結(jié)合一個(gè)實(shí)際案例進(jìn)行介紹,我們來(lái)實(shí)現(xiàn)一個(gè)跨電腦的代碼共享功能:


          1)首先,使用python的flask框架寫(xiě)一個(gè)極簡(jiǎn)的服務(wù)端應(yīng)用并啟動(dòng),提供最簡(jiǎn)單的 pushpull 的能力,如下:


          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()

          2)然后,我們來(lái)通過(guò)groovy腳本實(shí)現(xiàn)一個(gè)代碼 pull 的模板,這里應(yīng)用了Live Template的 groovy script 能力,對(duì)應(yīng)腳本如下:


          def url = new URL('http://127.0.0.1:5000/pull');def conn = url.openConnection() as HttpURLConnection;def result = conn.inputStream.text;return result

          3)最后,再實(shí)現(xiàn)代碼push的模板,腳本如下(下面的代碼入?yún)ⅲ峭ㄟ^(guò)剪切板賦值傳遞過(guò)來(lái)的):


          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

          此時(shí)就已經(jīng)完成了跨設(shè)備的代碼分享功能,為方便演示,這里就用 People1People2 兩個(gè)類(lèi)來(lái)模擬兩臺(tái)獨(dú)立的電腦。People1 將自己的一段代碼復(fù)制到剪切板中,然后通過(guò) push 模板調(diào)用 push 接口來(lái)將這段代碼上傳到Python服務(wù)應(yīng)用中;People2 再通過(guò) pull 腳本來(lái)調(diào)用服務(wù)端的 pull 接口,訪(fǎng)問(wèn)到 People1 上傳的代碼并輸入到當(dāng)前的代碼編輯器中,實(shí)現(xiàn)效果如下圖:



          這里的代碼共享只是一個(gè)引子,除此之外,我們還能寫(xiě)很多有意思的腳本,比如在IDE中查天氣、通過(guò)IDE聊天等等,自行腦補(bǔ)拓展。


          介紹完Live Template之后,接下來(lái)介紹文件級(jí)別的模板——File Template。


          四  File Template


          1  介紹


          File Template,顧名思義,對(duì)應(yīng)文件級(jí)別的模板。對(duì)于該模板,我們使用腳本的主要在于兩個(gè)場(chǎng)景,分別是文件頭和文件的自定義,下面結(jié)合案例依次展開(kāi)。


          2  自定義文件頭


          按照下圖的路徑,來(lái)更改文件頭的格式,IDE就會(huì)在我們新建一個(gè)類(lèi)或接口時(shí),根據(jù)這里的配置格式來(lái)自動(dòng)生成對(duì)應(yīng)的文件注釋頭。



          3  抽象通用Controller


          看下面一段代碼,這是一個(gè)針對(duì)于User這個(gè)domain的增刪改查接口類(lèi):


          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 {
          @Resourceprivate UserService userService;
          @PostMappingpublic Result<User> create(@RequestBody User record) { User user = userService.insert(record);return Result.success(user); }
          @PutMappingpublic 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); }
          @GetMappingpublic Result<List<User>> queryByCondition(Condition<User> condition) { List<User> list = userService.queryByCondition(condition);return Result.success(list); }}


          仔細(xì)看這段代碼會(huì)發(fā)現(xiàn),如果基于該接口再新增另一個(gè)domain對(duì)應(yīng)的Controller接口類(lèi),代碼中的基本結(jié)構(gòu)和邏輯都是可以復(fù)用的。此時(shí),便是File Template排上用場(chǎng)的地方,我們定義一個(gè)通用的 Controller 模板,將共性的部分抽象到模板里,再將差異性的部分通過(guò)模板入?yún)?Subject 變量傳入進(jìn)來(lái)(注,這里需要用到Velocity 模板[1]的知識(shí))。


          #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); }}

          模板定義完成,接下來(lái)來(lái)看一下實(shí)際的使用效果:



          這里使用 Goods 作為新的domain對(duì)象,可以看到,生成的 Controller 代碼已經(jīng)具備 UserController 的全部能力,并且生成的代碼全部都是 Goods 相關(guān)的api,這樣就實(shí)現(xiàn)了File Template的橫向遷移能力。


          五  低頻高效快捷鍵


          1  介紹


          IDEA中的快捷鍵多達(dá)上百個(gè),我們很難把每個(gè)都記清楚,網(wǎng)上也有很多對(duì)應(yīng)的總結(jié)。這里我主要梳理一些,大家使用相對(duì)比較低頻,但又非常高效的快捷鍵。


          2  梳理


          選擇重復(fù)元素:Control + G


          通常情況下,我們可以使用 Shift + F6 對(duì)類(lèi)名、方法名和變量名進(jìn)行批量更改,但對(duì)于其他元素進(jìn)行批量更改時(shí),該快捷鍵特別合適,且不限編程語(yǔ)言。



          批量框選:Option + 鼠標(biāo)左鍵拖拽


          對(duì)于"對(duì)齊"的代碼進(jìn)行批量更改的最優(yōu)解,沒(méi)有之一:



          整行移動(dòng):Option + Shift + ↑/↓


          快速調(diào)整代碼執(zhí)行順序,免除繁瑣的剪切粘貼過(guò)程:



          整行/塊復(fù)制:Command + D


          對(duì)于整行/塊的復(fù)制,效率遠(yuǎn)高于純手動(dòng)的復(fù)制粘貼:



          展開(kāi)/收起:Command + . or Command + Shift + +/-


          前者,快速顯示/隱藏當(dāng)前方法體;后者,快速概覽當(dāng)前類(lèi)的所有方法:



          修改方法簽名:Command + F6


          在方法被多文件或多處調(diào)用時(shí),該方式替換效率極高:



          查看歷史剪切板:Command + Shift + V


          開(kāi)發(fā)中經(jīng)常會(huì)出現(xiàn)需要復(fù)制多個(gè)文本的訴求,而PC默認(rèn)的剪切板只能保存一個(gè),該功能專(zhuān)門(mén)用來(lái)解決這個(gè)痛點(diǎn):



          代碼抽取


          代碼抽取主要用在代碼重構(gòu)的時(shí)候,以最快速度達(dá)到我們抽取一個(gè)變量、方法的目的。


          1)抽局部變量:Command + Option + V



          2)抽成員變量:Command + Option + F



          3)抽靜態(tài)常量:Command + Option + C



          4)抽方法入?yún)ⅲ篊ommand + Option + P



          5)抽方法:Command + Option + M



          六  代碼調(diào)試


          代碼調(diào)試在開(kāi)發(fā)中使用的非常多,常規(guī)的單步、多步、進(jìn)入、跳出操作這里也不特殊說(shuō)明了。


          有一點(diǎn)值得說(shuō)的就是,利用條件斷點(diǎn)來(lái)實(shí)現(xiàn)運(yùn)行期的代碼植入功能,先看下圖:



          可以看到,Debug模式運(yùn)行時(shí),我們能動(dòng)態(tài)改變 age 變量的值,本來(lái)被賦值為 20 的,結(jié)果輸出出來(lái)卻是 10


          這個(gè)是我在開(kāi)發(fā)中無(wú)意間發(fā)現(xiàn)的一個(gè)功能,算是一個(gè)Trick了。但這個(gè)功能在實(shí)際的開(kāi)發(fā)過(guò)程中特別有用,尤其針對(duì)于一些代碼改動(dòng)后再次運(yùn)行的成本比較高的場(chǎng)景。比如Android開(kāi)發(fā)過(guò)程中,能夠在不重新打整包的情況下,動(dòng)態(tài)修改頁(yè)面中各個(gè)元素的樣式、接口的請(qǐng)求、數(shù)據(jù)的內(nèi)容等等;再比如服務(wù)端場(chǎng)景中,如果我們的應(yīng)用支持Debug模式,則可以通過(guò)該功能實(shí)現(xiàn)應(yīng)用無(wú)需重新部署的情況下,進(jìn)行動(dòng)態(tài)更改上下文邏輯的操作。


          七  寫(xiě)在最后


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


          相關(guān)鏈接

          [1]http://velocity.apache.org/engine/devel/user-guide.html


          有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)
          歡迎大家關(guān)注Java之道公眾號(hào)

          好文章,我在看??
          瀏覽 55
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品久久电影网 | 91一区二区三区 | 一级黄色免费观看 | 国产三级片视频 | 丁香五月婷婷亚洲 |