IntelliJ IDEA教程:內(nèi)聯(lián)方法重構(gòu)
內(nèi)聯(lián)方法重構(gòu)的思想很簡單 - 用其內(nèi)容替換方法調(diào)用。它仍然非常強大。但要了解它的力量,你需要知道它的用例。
讓我們了解為什么,何時以及如何應用內(nèi)聯(lián)方法重構(gòu)以及IntelliJ IDEA如何幫助您入門。
一個方法的流程中斷
當方法調(diào)用中斷方法中的流而不是簡化它時,您可以考慮應用內(nèi)聯(lián)方法。在下面的代碼中,對方法的調(diào)用是在方法compareRatingWithMethodParameter()中插入不必要的間接方法scheduleSession()。
public class Talk { int rating; LocalTime scheduleSession() { return compareRatingWithMethodParameter(3) ? LocalTime.of(9, 0) : LocalTime.of(10, 0); } private boolean compareRatingWithMethodParameter(int param) { return rating < param; } }
通過內(nèi)聯(lián)方法可以簡化上面的代碼compareRatingWithMethodParameter():
但是,您不必內(nèi)聯(lián)每個只定義一行代碼的方法。決定應取決于它是否有助于您了解方法中的流程。
代碼遷移,或使用最新的Java語言功能
將代碼遷移到以后的Java版本時,您可能希望內(nèi)聯(lián)幾種方法,以便可以將操作應用于多個方法的代碼。
雖然在方法中的代碼getSortedListOfNames()看起來可讀,通過內(nèi)聯(lián)方法extractNamesFromSpeakerList()和sortSpeakerNames(),你可以重構(gòu)它使用Java流,而不是使用for循環(huán)和Collections.sort單獨的方法。這是原始代碼:
List getSortedListOfNames(List speakers) { List speakerNames = extractNamesFromSpeakerList(speakers); sortSpeakerNames(speakerNames); return speakerNames; } private void sortSpeakerNames(List speakerNames) { Collections.sort(speakerNames); } private List extractNamesFromSpeakerList(List speakers) { List result = new ArrayList<>(); for (Speaker speaker : speakers) { result.add(speaker.getName()); } return result; }
以下是如何內(nèi)聯(lián)方法并重構(gòu)生成的代碼:
這是重構(gòu)的代碼,您可以與原始代碼進行比較:
List getSortedListOfNames(List speakers) { return speakers.stream() .map(Speaker::getName) .sorted() .collect(Collectors.toList()); }
一組嚴重重構(gòu)的方法
程序員通常最終難以應用重構(gòu)實踐。例如,在下面的代碼中,程序員似乎已經(jīng)對每個單獨的代碼行應用了“Extract Method Refactoring”。
雖然它看起來仍然可讀,但是內(nèi)聯(lián)其中一些方法并將一個或多個方法的代碼組合到另一個方法中,然后進行(合理的)重構(gòu),可以改善代碼的意圖:
List getPanelists(Track track, List speakerList) { outputTrackName(track); outputSpeakerList(speakerList); List panelists = filterSpeakersWithoutTracks(speakerList); panelists = findSpeakerSpeakingOnTrack(track, panelists); return panelists; } private void outputTrackName(Track track) { System.out.println("Looking for panelists for track : " + track); } private void outputSpeakerList(List list) { list.forEach(System.out::println); } private List filterSpeakersWithoutTracks(List list) { return list.stream(). filter(s -> s.speakingOn != null) .collect(Collectors.toList()); } private List findSpeakerSpeakingOnTrack(Track track, List list) { return list.stream() .filter(s -> s.isSpeakingOn(track)) .collect(Collectors.toList()); }
讓我們看看我們?nèi)绾沃匦陆M織代碼。讓我們內(nèi)聯(lián)幾個方法,然后將代碼提取到方法中,使代碼簡潔易讀。
同樣,這是您與初始代碼進行比較的最終代碼:
List getPanelists(Track track, List speakerList) { outputParamValues(track, speakerList); return speakerList.stream(). filter(s -> s.speakingOn != null && s.isSpeakingOn(track)) .collect(Collectors.toList()); } private void outputParamValues(Track track, List speakerList) { System.out.println("Looking for panelists for track : " + track); speakerList.forEach(System.out::println); }
內(nèi)聯(lián)方法改進
(IntelliJ IDEA 2019.2中的新功能)
IntelliJ IDEA 2019.2包含對Inline Method重構(gòu)的重大改進。
通過定義多個return語句,方法可能包含多個出口點。當您在IntelliJ IDEA 2019.2中內(nèi)聯(lián)這樣的方法時,可以修改它以僅以單個return語句的形式定義一個退出點,以退出該方法。IntelliJ IDEA將此稱為“轉(zhuǎn)換為單一退出點”功能。
在下面的代碼中,當您內(nèi)聯(lián)方法時isBreakRequiredBetweenSession(),該過程會引入變量結(jié)果。多個return語句將替換為變量的賦值,最后result只有一個return語句:
void outputBreak() { boolean breakReq = isBreakRequiredBetweenSession(); System.out.println("Break required = " + breakReq); } private boolean isBreakRequiredBetweenSession() { if (isWeekend()) if (isDurationGreaterThan50min()) return true; else return false; else return false; }
讓我們內(nèi)聯(lián)方法isBreakRequiredBetweenSession():
如您所見,修改后的代碼更容易遵循 - 因為它沒有多個退出點。這是您與初始代碼進行比較的最終代碼:
void outputBreak() { boolean breakReq; if (isWeekend()) if (durationGreaterThan50min()) breakReq = true; else breakReq = false; else breakReq = false; System.out.println("Break required = " + breakReq); }
開發(fā)人員通常return在方法中定義多個語句,這些語句從各種控制語句(如if,for和其他語句)返回值。通常這種方法最后還包括一個return陳述。這是一個示例,它acceptSpeaker()使用行尾注釋在方法中定義多個出口點:
boolean acceptSession(Speaker speaker, Talk talk) { List days = List.of(DayOfWeek.SUNDAY, DayOfWeek.SATURDAY); if (speaker.getName().equals("JavaGuru")) return true; // Exit Point 1 if (talk.getTrack() == Track.SCALA) { return false; // Exit Point 2 } for (DayOfWeek day : days) { if(talk.date.getDayOfWeek().equals(day)) { return true; // Exit Point 3 } } return false; } boolean submitTalk(Speaker speaker, Talk talk) { System.out.println("Received another submission"); boolean isAccepted = acceptSession(speaker, talk); if (isAccepted) { // Update website } return isAccepted; }
當您在內(nèi)聯(lián)方法acceptSession()時submitTalk(),IntelliJ IDEA將檢測其多個退出語句并相應地修改代碼:
以下是您要比較的最終代碼(為方便起見添加了行尾注釋):
boolean submitTalk(Speaker speaker, Talk talk) { System.out.println("Received another submission"); boolean isAccepted = false; List days = List.of(DayOfWeek.SUNDAY, DayOfWeek.SATURDAY); if (speaker.getName().equals("JavaGuru")) { isAccepted = true; // Assignment } else { if (talk.getTrack() != Track.SCALA) { for (DayOfWeek day : days) { if (talk.date.getDayOfWeek().equals(day)) { isAccepted = true; // Assignment break; // break statement added } } } } if (isAccepted) { // Update website } return isAccepted; // single return statement }
具有否定的內(nèi)聯(lián)方法
(IntelliJ IDEA 2019.2中的新功能)
通過IntelliJ IDEA 2019.2的增強功能,內(nèi)聯(lián)方法重構(gòu)還支持呼叫站點的否定。在下面的代碼中,當您在方法中check()使用否定方法內(nèi)聯(lián)方法時isValidName(),它將不會被修改為“單個退出點”:
boolean check(Speaker speaker) { if (speaker == null) return false; String name = speaker.name.trim(); if (name.isEmpty()) return false; return name.length() % 2 == 0; } boolean isValidName(Speaker speaker) { return !check(speaker); }
這是內(nèi)聯(lián)代碼被否定的方式 - 注意返回值的反轉(zhuǎn)和條件(name.length() % 2 == 0)到(name.length() % 2 != 0):
以下是修改后的代碼,供您與原始代碼進行比較:
boolean isValidName(Speaker speaker) { if (speaker == null) return true; String name = speaker.name.trim(); if (name.isEmpty()) return true; return name.length() % 2 != 0; }
快樂的編碼和合理的重構(gòu)!
IntelliJ IDEA為您自動化各種重構(gòu)選項起著至關(guān)重要的作用。感興趣的朋友趕快下載體驗吧~
想要購買IntelliJ IDEA正版授權(quán)的朋友可以咨詢慧都官方客服。