日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自动处理重复的代码

發(fā)布時間:2023/12/3 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自动处理重复的代码 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在本文中,我將描述如何使用Java :: Geci生成器Repeated以克服泛型不能為原始類型的Java語言不足。 該示例是對Apache Commons Lang庫的建議擴(kuò)展。

介紹

當(dāng)您復(fù)制粘貼代碼時,您做錯了什么。 至少那是感知。 您必須創(chuàng)建更通用的代碼結(jié)構(gòu),以便可以多次使用不同的參數(shù)而不是類似的代碼。

這并非總是如此。 有時您必須重復(fù)一些代碼,因為您使用的語言(尚)不支持該問題所需的功能。

這太抽象了。 讓我們看一個特定的示例,以及如何使用在Java :: Geci框架中運行的Repeated源生成器來管理它。

問題

Apache Commons Lang庫中的org.apache.commons.lang3.Functions類定義了一個內(nèi)部接口FailableFunction 。 這是一個通用接口,定義為

@FunctionalInterface public interface FailableFunction<I, O, T extends Throwable> { /** * Apply the function. * @param pInput the input for the function * @return the result of the function * @throws T if the function fails */ O apply(I pInput) throws T; }

這本質(zhì)上與Function<I,O> ,后者將I轉(zhuǎn)換為O但是由于接口是有故障的,因此它也可能引發(fā)類型T的異常。

新的需要是

public interface Failable<I>Function<O, T extends Throwable>

每個<I>原語值的面。 問題是泛型在Java中還不能是原始的,因此我們應(yīng)該為每種原始類型分離接口,例如

@FunctionalInterface public interface FailableCharFunction<O, T extends Throwable> { O apply( char pInput) throws T; } @FunctionalInterface public interface FailableByteFunction<O, T extends Throwable> { O apply( byte pInput) throws T; } @FunctionalInterface public interface FailableShortFunction<O, T extends Throwable> { O apply( short pInput) throws T; } @FunctionalInterface public interface FailableIntFunction<O, T extends Throwable> { O apply( int pInput) throws T; } ... and so on ...

這是許多非常相似的方法,可以很容易地由模板描述,然后由某些代碼生成工具生成。

使用Java :: Geci進(jìn)行模板處理

Java :: Geci框架附帶了許多現(xiàn)成的生成器。 其中之一是功能強(qiáng)大的Repeated生成器,正是出于這個目的。 如果必須重復(fù)使用可能的參數(shù)的代碼,則可以定義模板,值和Repeated將生成解析模板參數(shù)的代碼。

向POM添加依賴項

我們要做的第一件事是將Java :: Geci依賴項添加到pom.xml文件中。 由于Apache Commons Language仍基于Java 8,因此我們必須使用Java :: Geci 1.2.0的Java 8反向端口:

< dependency > < groupId >com.javax1.geci</ groupId > < artifactId >javageci-core</ artifactId > < version >1.2.0</ version > < scope >test</ scope > </ dependency >

注意,依賴項的范圍是test 。 Repeated生成器可以方便地使用,而字節(jié)碼中不會保留任何Geci注釋,因此它們是編譯時的依賴項。 實際上,所有生成器都可以使用而無需注釋,因此不需要任何編譯依賴關(guān)系,而這對于生產(chǎn)來說是額外的依賴關(guān)系。 在Repeated的情況下,這甚至很容易做到。

運行發(fā)電機(jī)的單元測試

我們要做的第二件事是創(chuàng)建一個將執(zhí)行生成器的單元測試。 Java :: Geci生成器在單元測試階段運行,因此它們可以使用反射以及實際的源代碼訪問已編譯的代碼。 如果生成的任何代碼與源文件中已有的代碼不同,則測試將失敗,并且應(yīng)再次執(zhí)行生成過程。 由于發(fā)生器是(應(yīng)該)冪等的,因此測試第二次不應(yīng)失敗。

以我的經(jīng)驗,很遺憾,此工作流程會影響開發(fā)人員的行為。 運行測試/失敗,再次運行! 這是一個糟糕的循環(huán)。 有時我碰巧發(fā)現(xiàn)自己不是在代碼生成器發(fā)生故障的情況下重新執(zhí)行單元測試。 但是,這就是Java :: Geci的工作方式。

有一些關(guān)于Java :: Geci工作流程的文章

  • 您的代碼是多余的,請繼續(xù)使用!
  • 保持JavaDoc為最新
  • 將對象轉(zhuǎn)換為映射并返回
  • 反射選擇器表達(dá)式
  • 使用Java :: Geci生成Getter和Setters
  • 創(chuàng)建一個Java :: Geci生成器
  • 如何生成源代碼

因此,在此我不會重復(fù)總體架構(gòu)及其工作流程。

單元測試如下:

@Test void generatePrimitiveFailables() throws Exception { final Geci geci = new Geci(); Assertions.assertFalse(geci.source(Source.maven().mainSource()) .only( "Functions" ) .register(Repeated.builder() .values( "char,byte,short,int,long,float,double,boolean" ) .selector( "repeated" ) .define((ctx, s) -> ctx.segment().param( "Value" , CaseTools.ucase(s))) .build()) .generate(), geci.failed()); }

調(diào)用source() , register()和only()配置框架。 此配置告訴框架使用項目主Java src目錄中的源文件,并僅使用文件名"Functions" 。 在我們調(diào)用generate()開始代碼生成之前,對register()的調(diào)用會register() Repeated生成器實例。

生成器實例本身是使用內(nèi)置的生成器創(chuàng)建的,該生成器使我們可以配置生成器。 在這種情況下,對values()的調(diào)用定義了我們要重復(fù)使用模板的逗號分隔的值列表(稍后在注釋中的代碼中定義)。 對selector()的調(diào)用定義了此代碼重復(fù)代碼的標(biāo)識符。 單個源文件可能包含多個模板。 每個模板可以使用不同的值列表進(jìn)行處理,結(jié)果將插入到不同的輸出段中,并插入源文件中。 在這種情況下,仍然只有一個這樣的代碼生成模板,它必須用一個名稱標(biāo)識,并且該名稱也必須在editor-fold部分中使用,該部分是生成代碼的占位符。

實際使用生成器的名稱有兩個作用。 其一是它標(biāo)識了編輯器折疊段和模板。 另一個是框架將看到帶有該標(biāo)識符的編輯器折疊段,并且它將識別出該源文件需要該生成器的注意。 另一種可能性是在類中添加@Repeated或@Geci("repeated")批注。

如果標(biāo)識符是別的東西并且不repeated那么生成器“ Repeated將不會觸及源代碼,或者我們需要將另一個段標(biāo)識為“ repeated ,除了觸發(fā)生成器之外,它實際上不會被使用。

對define()的調(diào)用define()了一個BiConsumer ,該BiConsumer獲取了上下文引用和實際值。 在這種情況下, BiConsumer計算大寫值,并將其放入與名稱Value相關(guān)聯(lián)的實際細(xì)分參數(shù)集中。 默認(rèn)情況下,實際值與名稱value關(guān)聯(lián),并且傳遞給方法define()的BiConsumer可以定義和注冊其他參數(shù)。 在這種情況下,它將添加新值

value Value char --> Char byte --> Byte short --> Short int --> Int long --> Long float --> Float double --> Double boolean --> Boolean

源代碼

第三件事是在源文件中準(zhǔn)備模板和輸出段。

輸出段的準(zhǔn)備非常簡單。 它只是一個編輯器折疊:

//<editor-fold id="repeated"> //</editor-fold>

生成的代碼將自動插入兩行之間,并且編輯器(Eclipse,IntelliJ或NetBeans)將允許您關(guān)閉折疊。 您不想編輯此代碼:它已生成。

該模板將如下所示:

/* TEMPLATE repeated @FunctionalInterface public interface Failable{{Value}}Function<O, T extends Throwable> { O apply({{value}} pInput) throws T; } */

代碼生成器找到模板的開始,以查找與/* TEMPLATE name格式匹配的行,并收集連續(xù)的行,直到注釋的結(jié)尾。

該模板使用小胡子模板的占位符格式,即用雙括號括起來的值的名稱。 雙括號在Java中很少見。

當(dāng)我們運行單元測試時,它將生成我在本文開頭已經(jīng)列出的代碼。 (然后,它當(dāng)然會失敗:修改了源代碼,然后再次編譯。)

摘要和總結(jié)

最重要的要點和警告:源代碼生成是旨在彌補(bǔ)編程語言不足的一種工具。 不要使用代碼生成來修正語言的不足,而不僅僅是語言的不足,技能或知識的不足。 生成代碼的簡單方法不是生成不必要的冗余代碼的借口。

另一個收獲是,在Java中使用此生成器非常容易。 該功能可以與Java所沒有的C預(yù)處理器相媲美,而且效果良好。 需要時使用它。 即使依賴項的設(shè)置和單元測試的開銷可能很小,但可維護(hù)性通常會償還此成本。

翻譯自: https://www.javacodegeeks.com/2019/09/handling-repeated-code-automatically.html

總結(jié)

以上是生活随笔為你收集整理的自动处理重复的代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。