Java優(yōu)化重復(fù)冗余代碼的8種方式總結(jié)
1. 抽取公用方法
抽取公用方法,是最常用的代碼去重方法~
比如這個(gè)例子,分別遍歷names
列表,然后各自轉(zhuǎn)化為大寫和小寫打印出來:
public class TianLuoExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "TianLuo"); System.out.println("Uppercase Names:"); for (String name : names) { String uppercaseName = name.toUpperCase(); System.out.println(uppercaseName); } System.out.println("Lowercase Names:"); for (String name : names) { String lowercaseName = name.toLowerCase(); System.out.println(lowercaseName); } } }
顯然,都是遍歷names
過程,代碼是重復(fù)的,只不過轉(zhuǎn)化大小寫不一樣。我們可以抽個(gè)公用方法processNames
,優(yōu)化成這樣:
public class TianLuoExample { public static void processNames(List<String> names, Function<String, String> nameProcessor, String processType) { System.out.println(processType + " Names:"); for (String name : names) { String processedName = nameProcessor.apply(name); System.out.println(processedName); } } public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "TianLuo"); processNames(names, String::toUpperCase, "Uppercase"); processNames(names, String::toLowerCase, "Lowercase"); } }
2. 抽工具類
我們優(yōu)化重復(fù)代碼,抽一個(gè)公用方法后,如果發(fā)現(xiàn)這個(gè)方法有更多共性,就可以把公用方法升級(jí)為一個(gè)工具類。比如這樣的業(yè)務(wù)場(chǎng)景:我們注冊(cè)的時(shí)候,修改郵箱,重置密碼等,都需要校驗(yàn)郵箱
實(shí)現(xiàn)注冊(cè)功能時(shí),用戶會(huì)填郵箱,需要驗(yàn)證郵箱格式,
public class RegisterServiceImpl implements RegisterService{ private static final String EMAIL_REGEX = "^[A-Za-z0-9+_.-]+@(.+)$"; public boolean registerUser(UserInfoReq userInfo) { String email = userInfo.getEmail(); Pattern pattern = Pattern.compile(EMAIL_REGEX); Matcher emailMatcher = pattern.matcher(email); if (!emailMatcher.matches()) { System.out.println("Invalid email address."); return false; } // 進(jìn)行其他用戶注冊(cè)邏輯,比如保存用戶信息到數(shù)據(jù)庫等 // 返回注冊(cè)結(jié)果 return true; } }
在密碼重置流程中,通常會(huì)向用戶提供一個(gè)鏈接或驗(yàn)證碼,并且需要發(fā)送到用戶的電子郵件地址。在這種情況下,也需要驗(yàn)證郵箱格式合法性:
public class PasswordServiceImpl implements PasswordService{ private static final String EMAIL_REGEX = "^[A-Za-z0-9+_.-]+@(.+)$"; public void resetPassword(PasswordInfo passwordInfo) { Pattern pattern = Pattern.compile(EMAIL_REGEX); Matcher emailMatcher = pattern.matcher(passwordInfo.getEmail()); if (!emailMatcher.matches()) { System.out.println("Invalid email address."); return false; } //發(fā)送通知修改密碼 sendReSetPasswordNotify(); } }
我們可以抽取個(gè)校驗(yàn)郵箱的方法出來,又因?yàn)樾r?yàn)郵箱的功能在不同的類中,因此,我們可以抽個(gè)校驗(yàn)郵箱的工具類:
public class EmailValidatorUtil { private static final String EMAIL_REGEX = "^[A-Za-z0-9+_.-]+@(.+)$"; private static final Pattern pattern = Pattern.compile(EMAIL_REGEX); public static boolean isValid(String email) { Matcher matcher = pattern.matcher(email); return matcher.matches(); } } //注冊(cè)的代碼可以簡(jiǎn)化為這樣啦 public class RegisterServiceImpl implements RegisterService{ public boolean registerUser(UserInfoReq userInfo) { if (!EmailValidatorUtil.isValid(userInfo.getEmail())) { System.out.println("Invalid email address."); return false; } // 進(jìn)行其他用戶注冊(cè)邏輯,比如保存用戶信息到數(shù)據(jù)庫等 // 返回注冊(cè)結(jié)果 return true; } }
3. 反射
我們?nèi)粘i_發(fā)中,經(jīng)常需要進(jìn)行PO、DTO和VO的轉(zhuǎn)化。所以大家經(jīng)??吹筋愃频拇a:
//DTO 轉(zhuǎn)VO public UserInfoVO convert(UserInfoDTO userInfoDTO) { UserInfoVO userInfoVO = new UserInfoVO(); userInfoVO.setUserName(userInfoDTO.getUserName()); userInfoVO.setAge(userInfoDTO.getAge()); return userInfoVO; } //PO 轉(zhuǎn)DTO public UserInfoDTO convert(UserInfoPO userInfoPO) { UserInfoDTO userInfoDTO = new UserInfoDTO(); userInfoDTO.setUserName(userInfoPO.getUserName()); userInfoDTO.setAge(userInfoPO.getAge()); return userInfoDTO; }
我們可以使用BeanUtils.copyProperties()
去除重復(fù)代碼,BeanUtils.copyProperties()
底層就是使用了反射:
public UserInfoVO convert(UserInfoDTO userInfoDTO) { UserInfoVO userInfoVO = new UserInfoVO(); BeanUtils.copyProperties(userInfoDTO, userInfoVO); return userInfoVO; } public UserInfoDTO convert(UserInfoPO userInfoPO) { UserInfoDTO userInfoDTO = new UserInfoDTO(); BeanUtils.copyProperties(userInfoPO,userInfoDTO); return userInfoDTO; }
4.泛型
泛型是如何去除重復(fù)代碼的呢?給大家看個(gè)例子,我有個(gè)轉(zhuǎn)賬明細(xì)和轉(zhuǎn)賬余額對(duì)比的業(yè)務(wù)需求,有兩個(gè)類似這樣的方法:
private void getAndUpdateBalanceResultMap(String key, Map<String, List<TransferBalanceDTO>> compareResultListMap, List<TransferBalanceDTO> balanceDTOs) { List<TransferBalanceDTO> tempList = compareResultListMap.getOrDefault(key, new ArrayList<>()); tempList.addAll(balanceDTOs); compareResultListMap.put(key, tempList); } private void getAndUpdateDetailResultMap(String key, Map<String, List<TransferDetailDTO>> compareResultListMap, List<TransferDetailDTO> detailDTOS) { List<TransferDetailDTO> tempList = compareResultListMap.getOrDefault(key, new ArrayList<>()); tempList.addAll(detailDTOS); compareResultListMap.put(key, tempList); }
這兩塊代碼,流程功能看著很像,但是就是不能直接合并抽取一個(gè)公用方法,因?yàn)轭愋筒灰恢?/strong>。單純類型不一樣的話,我們可以結(jié)合泛型處理,因?yàn)榉盒偷谋举|(zhì)就是參數(shù)化類型.優(yōu)化為這樣:
private <T> void getAndUpdateResultMap(String key, Map<String, List<T>> compareResultListMap, List<T> accountingDTOS) { List<T> tempList = compareResultListMap.getOrDefault(key, new ArrayList<>()); tempList.addAll(accountingDTOS); compareResultListMap.put(key, tempList); }
5. 繼承與多態(tài)
假設(shè)你正在開發(fā)一個(gè)電子商務(wù)平臺(tái),需要處理不同類型的訂單,例如普通訂單和折扣訂單。每種訂單都有一些共同的屬性(如訂單號(hào)、購買商品列表)和方法(如計(jì)算總價(jià)、生成訂單報(bào)告),但折扣訂單還有特定的屬性和方法。
在沒有使用繼承和多態(tài)的話,會(huì)寫出類似這樣的代碼:
//普通訂單 public class Order { private String orderNumber; private List<Product> products; public Order(String orderNumber, List<Product> products) { this.orderNumber = orderNumber; this.products = products; } public double calculateTotalPrice() { double total = 0; for (Product product : products) { total += product.getPrice(); } return total; } public String generateOrderReport() { return "Order Report for " + orderNumber + ": Total Price = $" + calculateTotalPrice(); } } //折扣訂單 public class DiscountOrder { private String orderNumber; private List<Product> products; private double discountPercentage; public DiscountOrder(String orderNumber, List<Product> products, double discountPercentage) { this.orderNumber = orderNumber; this.products = products; this.discountPercentage = discountPercentage; } public double calculateTotalPrice() { double total = 0; for (Product product : products) { total += product.getPrice(); } return total - (total * discountPercentage / 100); } public String generateOrderReport() { return "Order Report for " + orderNumber + ": Total Price = $" + calculateTotalPrice(); } }
顯然,看到在Order
和DiscountOrder
類中,generateOrderReport()
方法的代碼是完全相同的。calculateTotalPrice()
則是有一點(diǎn)點(diǎn)區(qū)別,但也大相徑庭。
我們可以使用繼承和多態(tài)去除重復(fù)代碼,讓DiscountOrder
去繼承Order
,代碼如下:
public class Order { private String orderNumber; private List<Product> products; public Order(String orderNumber, List<Product> products) { this.orderNumber = orderNumber; this.products = products; } public double calculateTotalPrice() { double total = 0; for (Product product : products) { total += product.getPrice(); } return total; } public String generateOrderReport() { return "Order Report for " + orderNumber + ": Total Price = $" + calculateTotalPrice(); } } public class DiscountOrder extends Order { private double discountPercentage; public DiscountOrder(String orderNumber, List<Product> products, double discountPercentage) { super(orderNumber, products); this.discountPercentage = discountPercentage; } @Override public double calculateTotalPrice() { double total = super.calculateTotalPrice(); return total - (total * discountPercentage / 100); } }
6.使用設(shè)計(jì)模式
很多設(shè)計(jì)模式可以減少重復(fù)代碼、提高代碼的可讀性、可擴(kuò)展性.比如:
- 工廠模式: 通過工廠模式,你可以將對(duì)象的創(chuàng)建和使用分開,從而減少重復(fù)的創(chuàng)建代碼。
- 策略模式: 策略模式定義了一族算法,將它們封裝成獨(dú)立的類,并使它們可以互相替換。通過使用策略模式,你可以減少在代碼中重復(fù)使用相同的邏輯。
- 模板方法模式:模板方法模式定義了一個(gè)算法的骨架,將一些步驟延遲到子類中實(shí)現(xiàn)。這有助于避免在不同類中重復(fù)編寫相似的代碼。
我給大家舉個(gè)例子,模板方法是如何去除重復(fù)代碼的吧,業(yè)務(wù)場(chǎng)景:
假設(shè)你正在開發(fā)一個(gè)咖啡和茶的制作流程,制作過程中的熱水和添加物質(zhì)的步驟是相同的,但是具體的飲品制作步驟是不同的。
如果沒有使用模板方法模式,實(shí)現(xiàn)是醬紫的:
public class Coffee { public void prepareCoffee() { boilWater(); brewCoffeeGrinds(); pourInCup(); addCondiments(); } private void boilWater() { System.out.println("Boiling water"); } private void brewCoffeeGrinds() { System.out.println("Brewing coffee grinds"); } private void pourInCup() { System.out.println("Pouring into cup"); } private void addCondiments() { System.out.println("Adding sugar and milk"); } } public class Tea { public void prepareTea() { boilWater(); steepTeaBag(); pourInCup(); addLemon(); } private void boilWater() { System.out.println("Boiling water"); } private void steepTeaBag() { System.out.println("Steeping the tea bag"); } private void pourInCup() { System.out.println("Pouring into cup"); } private void addLemon() { System.out.println("Adding lemon"); } }
這個(gè)代碼例子,我們可以發(fā)現(xiàn),燒水和倒入杯子的步驟代碼,在Coffee
和Tea
類中是重復(fù)的。
使用模板方法模式,代碼可以優(yōu)化成這樣:
abstract class Beverage { public final void prepareBeverage() { boilWater(); brew(); pourInCup(); addCondiments(); } private void boilWater() { System.out.println("Boiling water"); } abstract void brew(); private void pourInCup() { System.out.println("Pouring into cup"); } abstract void addCondiments(); } class Coffee extends Beverage { @Override void brew() { System.out.println("Brewing coffee grinds"); } @Override void addCondiments() { System.out.println("Adding sugar and milk"); } } class Tea extends Beverage { @Override void brew() { System.out.println("Steeping the tea bag"); } @Override void addCondiments() { System.out.println("Adding lemon"); } }
在這個(gè)例子中,我們創(chuàng)建了一個(gè)抽象類Beverage
,其中定義了制作飲品的模板方法 prepareBeverage()
。這個(gè)方法包含了燒水、倒入杯子等共同的步驟,而將制作過程中的特定步驟 brew() 和 addCondiments()
延遲到子類中實(shí)現(xiàn)。這樣,我們避免了在每個(gè)具體的飲品類中重復(fù)編寫相同的燒水和倒入杯子的代碼,提高了代碼的可維護(hù)性和重用性。
7.自定義注解(或者說AOP面向切面)
使用 AOP
框架可以在不同地方插入通用的邏輯,從而減少代碼重復(fù)。
業(yè)務(wù)場(chǎng)景:
假設(shè)你正在開發(fā)一個(gè)Web
應(yīng)用程序,需要對(duì)不同的Controller
方法進(jìn)行權(quán)限檢查。每個(gè)Controller
方法都需要進(jìn)行類似的權(quán)限驗(yàn)證,但是重復(fù)的代碼會(huì)導(dǎo)致代碼的冗余和維護(hù)困難。
public class MyController { public void viewData() { if (!User.hasPermission("read")) { throw new SecurityException("Insufficient permission to access this resource."); } // Method implementation } public void modifyData() { if (!User.hasPermission("write")) { throw new SecurityException("Insufficient permission to access this resource."); } // Method implementation } }
你可以看到在每個(gè)需要權(quán)限校驗(yàn)的方法中都需要重復(fù)編寫相同的權(quán)限校驗(yàn)邏輯,即出現(xiàn)了重復(fù)代碼.我們使用自定義注解的方式能夠?qū)?quán)限校驗(yàn)邏輯集中管理,通過切面來處理,消除重復(fù)代碼.如下:
@Aspect @Component public class PermissionAspect { @Before("@annotation(requiresPermission)") public void checkPermission(RequiresPermission requiresPermission) { String permission = requiresPermission.value(); if (!User.hasPermission(permission)) { throw new SecurityException("Insufficient permission to access this resource."); } } } public class MyController { @RequiresPermission("read") public void viewData() { // Method implementation } @RequiresPermission("write") public void modifyData() { // Method implementation } }
就這樣,不管多少個(gè)Controller
方法需要進(jìn)行權(quán)限檢查,你只需在方法上添加相應(yīng)的注解即可。權(quán)限檢查的邏輯在切面中集中管理,避免了在每個(gè)Controller
方法中重復(fù)編寫相同的權(quán)限驗(yàn)證代碼。這大大提高了代碼的可讀性、可維護(hù)性,并避免了代碼冗余。
8.函數(shù)式接口和Lambda表達(dá)式
業(yè)務(wù)場(chǎng)景:
假設(shè)你正在開發(fā)一個(gè)應(yīng)用程序,需要根據(jù)不同的條件來過濾一組數(shù)據(jù)。每次過濾的邏輯都可能會(huì)有些微的不同,但基本的流程是相似的。
沒有使用函數(shù)式接口和Lambda表達(dá)式的情況:
public class DataFilter { public List<Integer> filterPositiveNumbers(List<Integer> numbers) { List<Integer> result = new ArrayList<>(); for (Integer number : numbers) { if (number > 0) { result.add(number); } } return result; } public List<Integer> filterEvenNumbers(List<Integer> numbers) { List<Integer> result = new ArrayList<>(); for (Integer number : numbers) { if (number % 2 == 0) { result.add(number); } } return result; } }
在這個(gè)例子中,我們有兩個(gè)不同的方法來過濾一組數(shù)據(jù),但是基本的循環(huán)和條件判斷邏輯是重復(fù)的,我們可以使用使用函數(shù)式接口和Lambda表達(dá)式,去除重復(fù)代碼,如下:
public class DataFilter { public List<Integer> filterNumbers(List<Integer> numbers, Predicate<Integer> predicate) { List<Integer> result = new ArrayList<>(); for (Integer number : numbers) { if (predicate.test(number)) { result.add(number); } } return result; } }
我們將過濾的核心邏輯抽象出來。該方法接受一個(gè) Predicate
函數(shù)式接口作為參數(shù),以便根據(jù)不同的條件來過濾數(shù)據(jù)。然后,我們可以使用Lambda
表達(dá)式來傳遞具體的條件,這樣最終也達(dá)到去除重復(fù)代碼的效果啦.
以上就是Java優(yōu)化重復(fù)冗余代碼的8種方式總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Java優(yōu)化代碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java報(bào)錯(cuò)sun.misc.Unsafe.park(Native Method)問題
這篇文章主要介紹了Java報(bào)錯(cuò)sun.misc.Unsafe.park(Native Method)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07Java多線程中不同條件下編寫生產(chǎn)消費(fèi)者模型方法介紹
這篇文章主要介紹了Java多線程中不同條件下編寫生產(chǎn)消費(fèi)者模型方法介紹,介紹了生產(chǎn)消費(fèi)者模型,然后分享了相關(guān)代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11搜索一文入門ElasticSearch(節(jié)點(diǎn) 分片 CRUD 倒排索引 分詞)
這篇文章主要為大家介紹了搜索一文入門ElasticSearch(節(jié)點(diǎn) 分片 CRUD 倒排索引 分詞)的基礎(chǔ)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Java SpringMVC攔截器與異常處理機(jī)制詳解分析
SpringMVC是一種基于Java,實(shí)現(xiàn)了Web MVC設(shè)計(jì)模式,請(qǐng)求驅(qū)動(dòng)類型的輕量級(jí)Web框架,即使用了MVC架構(gòu)模式的思想,將Web層進(jìn)行職責(zé)解耦。基于請(qǐng)求驅(qū)動(dòng)指的就是使用請(qǐng)求-響應(yīng)模型,框架的目的就是幫助我們簡(jiǎn)化開發(fā),SpringMVC也是要簡(jiǎn)化我們?nèi)粘eb開發(fā)2021-10-10Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(61)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-08-08Java使用Hutool實(shí)現(xiàn)AES、DES加密解密的方法
本篇文章主要介紹了Java使用Hutool實(shí)現(xiàn)AES、DES加密解密的方法,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08JAVA幫助文檔全系列 JDK1.5 JDK1.6 JDK1.7 官方中英完整版整理
JDK(Java Development Kit,Java開發(fā)包,Java開發(fā)工具)是一個(gè)寫Java的applet和應(yīng)用程序的程序開發(fā)環(huán)境。它由一個(gè)處于操作系統(tǒng)層之上的運(yùn)行環(huán)境還有開發(fā)者編譯,調(diào)試和運(yùn)行用Java語言寫的applet和應(yīng)用程序所需的工具組成2014-01-01MyBatis-Plus動(dòng)態(tài)返回實(shí)體類示例詳解
這篇文章主要為大家介紹了MyBatis-Plus動(dòng)態(tài)返回實(shí)體類示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07