主頁 >  其他 > 爛慫if-else代碼優化方案

爛慫if-else代碼優化方案

2023-06-01 08:22:20 其他

0.問題概述

代碼可讀性是衡量代碼質量的重要標準,可讀性也是可維護性、可擴展性的保證,因為代碼是連接程式員和機器的中間橋梁,要對雙邊友好,Quora 上有一個帖子: “What are some of the most basic things every programmer should know?”

其中:

  • Code that’s hard to understand is hard to maintain.

  • Code that’s hard to maintain is next to useless.

也強調了"easy understand"代碼的重要性,

寫這篇文章的貧訓是在研讀Apache ShenYu專案時,看到了很大一坨的if else陳述句,如下:
image.png

這里并非評論這段代碼寫法有問題,因為我還并沒有深入到專案細節之中,可能這已經是多輪優化的結果嘞,

但是這個多層if else的形式引發了我的思考,因為我也曾在專案代碼中引入過如此繁重的if else結構,并在Code Review中被指出了問題,從那以后,我對if else的最大容忍層數就是三層,

我把大量if else的場景按照深度和廣度兩個維度劃分為兩種情況:

  • 嵌套層級過深

  • 平鋪范圍太廣

下面就討論一下,當代碼中存在大量這樣結構的代碼的時候,該如何優化?

1.解決方案

1.1 盡早回傳

又稱衛陳述句,即Guard Statement

WikiPedia:

In computer programming, aguardis abooleanexpressionthat must evaluate to true if the program execution is to continue in the branch in question.

Regardless of which programming language is used, aguard clause,guard code, orguard statement, is a check of integritypreconditionsused to avoid errors during execution. A typical example is checking that a reference about to be processed is not null, which avoids null-pointer failures. Other uses include using a boolean field foridempotence(so subsequent calls are nops), as in thedispose pattern. The guard provides anearly exitfrom asubroutine, and is a commonly used deviation fromstructured programming, removing one level of nesting and resulting in flatter code:[1]replacingif guard { ... }withif not guard: return; ....

實際應用:

if (CollectionUtils.isNotEmpty(list)) {
	// do something
} else {   
	return xxx;
}


使用盡早回傳優化:

if (CollectionUtils.isEmpty(list)) {
	return xxx;
}

// do something


可以看到,優化后的代碼不僅節省了一個else陳述句,也能讓后續的"do something"節省一層if else包裹,代碼看起來更干凈一些

結合這個例子再說一下我對衛陳述句的理解:

可以將“衛”理解為“門衛”,門衛的作用是檢查過濾,只有符合條件的陳述句,才可以繼續執行,否則直接勸返(return),吐槽一下這種中文直譯有些晦澀,未免有點“德先生賽先生”的意思了,,,

1.2 使用switch或三元運算子

可以利用語法知識,對if else進行簡化,

例如,當if else滿足一定條件時:

if (condition1) {
    doSomeThing1();
} else if (condition2) {
    doSomeThing2();
} else if (condition3) {
    doSomeThing3(); 
} else if (condition4) {
    doSomeThing4();
} else {
    doSomeThing5(); 
}...


可以使用switch case語法進行替換

或,

例如使用三元運算子進行賦值操作:

Integer num = obejct == null ? 1 : object.value();

1.3 策略模式

1.3.1 概念

策略模式是一種行為設計模式,即一個物件有一個確定的行為,在不同場景下,這些行為有不同的演算法實作,

例如從內蒙通過公共交通去北京是一個確定的行為,在天上這種場景可以選擇飛機,地上的場景可以選擇火車~

策略模式一般包含三個要素:

  • 抽象策略(Abstract strategy):定義所謂的“確定的行為”,一般由介面或抽象類實作

  • 具體實作(Concrete strategy):封裝對應場景下的具體演算法實作,

  • 背景關系(Context):負責具體實作策略的管理并供物件使用,

1.3.2 使用場景

  • 一個介面或抽象類的各個子類都是為了解決相同的問題,區分這些子類的只有方法實作的不同,

  • 代碼中使用大量if else或大面積switch case來選擇具體的子實作類

1.3.3 實際應用

例如:

if ("man".equals(strategy)) {   
	// Perform related operations 
} else if ("woman".equals(strategy)) {   
	// Perform operations related to women
} else if ("other".equals(strategy)) {   
	// Perform other operations
}


上面一段代碼,每一個if分支完成的都是相同的操作,只是在不同的性別場景下,操作方法的實作不同,那么就可以使用策略模式進行優化:

首先,定義一個抽象策略介面:

public interface Strategy {

    void run() throws Exception;

}


然后,進行不同策略的實作:

//Men's strategy implementation class
@Slf4j
public class ManStrategy implements Strategy {

    @Override
    public void run() throws Exception {
        // Fast man's logic
        log.debug("Execute the logic related to men...");
    }

}

//Women's strategy implementation class
@Slf4j
public class WomanStrategy implements Strategy {

    @Override
    public void run() throws Exception {
        // Fast woman's logic
        log.debug("Execute women related logic...");
    }

}

//Others' policy implementation class
@Slf4j
public class OtherStrategy implements Strategy {

    @Override
    public void run() throws Exception {
        // Fast other logic
        log.debug("Perform other related logic...");
    }

}


最后,進行策略的應用:

public class StrategyTest {

    public static void main(String[] args) {
        try {
            Strategy strategy = initMap("man");
            strategy.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //Initialize the Map to obtain a gender policy
    private static Strategy initMap(String key) {
        //Use simple example
        HashMap<String, Strategy> map = new HashMap<>();
        map.put("man", new ManStrategy());
        map.put("woman", new WomanStrategy());
        map.put("other", new OtherStrategy());
        return map.get(key);
    }

}


1.3.4 優劣勢分析及優化

1.3.4.1 劣勢

整體上來看,使用策略模式雖然剔除了大量的if else陳述句,但是也引入了更多的類檔案,同時在Context中需要維護一個類似注冊表的map物件,當增加策略實作時,容易忘記,

優化措施:

在Java中,可以使用函式式編程進行優化:

@Slf4j
public class StrategyTest {

    public static void main(String[] args) {
        //Use simple example
        HashMap<String, Strategy> map = new HashMap<>();
        map.put("man", () -> log.debug("Execute the logic related to men..."));
        map.put("woman", () -> log.debug("Execute women related logic..."));
        map.put("other", () -> log.debug("Execute logic related to others..."));

        try {
            map.get("woman").run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


或者,使用列舉進行優化:

@Slf4j
public enum Strategy {

    //Man state
    MAN(0) {
        @Override
        void run() {
            //Perform related operations
            log.debug("Execute the logic related to men");
        }
    },
    //Woman state
    WOMAN(1) {
        @Override
        void run() {
            //Perform operations related to women
            log.debug("Execute women related logic");
        }
    },
    //Other status
    OTHER(2) {
        @Override
        void run() {
            //Perform other related operations
            log.debug("Perform other related logic");
        }
    };

    abstract void run();

    public int statusCode;

    Strategy(int statusCode) {
        this.statusCode = statusCode;
    }

}


public static void main(String[] args) {
        try {
            //Simple use example
            String param = String.valueOf(Strategy.WOMAN);
            Strategy strategy = Strategy.valueOf(param);
            strategy.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
}


除此以外,在客戶端實際使用策略時,即物件進行方法的呼叫時,客戶端必須知道這個策略的所有實作子類,并需要了解這些子類之間的不同以及各自的應用場景,這樣客戶端才能選擇合適的策略實作“確定的行為”,

1.3.4.2 優勢

  • 最直接的好處就是可以讓又臭又長的if else代碼塊看起來更干凈,

  • 面向物件的三大特點:封裝、繼承、多型,在策略模式中都能找到影子,面向介面編程,代碼的可擴展性好

  • 代碼的可測性好,Mock更方便,減少了分支判斷,實作類只需要各自測驗即可,

1.4 Optional

if else分支判斷的很多情況都是進行非空條件的判斷,Optional是Java8開始提供的新特性,使用這個語法特性,也可以減少代碼中if else的數量,例如:

優化前:

String str = "Hello World!";

if (str != null) {
    System.out.println(str);
} else {
    System.out.println("Null");
}


優化后:

Optional<String> optional = Optional.of("Hello World!");
optional.ifPresentOrElse(System.out::println, () -> System.out.println("Null"));


1.5 注冊表

這種方式和策略模式有相似之處,但注冊表更自由,不需要提煉介面,只需要將自定義實作在注冊表中注冊即可,

例如,優化前:

if (param.equals(value1)) {
    doAction1(someParams);
}else if (param.equals(value2)) {
    doAction2(someParams);
}else if (param.equals(value3)) {
    doAction3(someParams);
}


優化后:

//Generic here? For the convenience of demonstration, it can be replaced with the real type we need in actual development
Map<?, Function<?> action> actionMappings = new HashMap<>(); 
// When init
actionMappings.put(value1, (someParams) -> { doAction1(someParams)});
actionMappings.put(value2, (someParams) -> { doAction2(someParams)});
actionMappings.put(value3, (someParams) -> { doAction3(someParams)});
 
// Omit null judgment
actionMappings.get(param).apply(someParams);


1.6 責任鏈模式

先來看一段代碼:

public void handle(request) {
    if (handlerA.canHandle(request)) {
        handlerA.handleRequest(request);
    } else if (handlerB.canHandle(request)) {
        handlerB.handleRequest(request);
    } else if (handlerC.canHandle(request)) {
        handlerC.handleRequest(request);
    }
}


代碼中也是存在一坨if else陳述句,但是和上述例子不同之處在于,if條件判斷權在每個handler組件中,每一個handler的判斷方式也可能不盡相同,相當靈活,同一個request可能同時滿足多個if條件

解決方案就是參考開源組件中Filter或者Interceptor責任鏈機制,優化后代碼:

public void handle(request) {
  handlerA.handleRequest(request);
}
 
public abstract class Handler {
    
  protected Handler next;
    
  public abstract void handleRequest(Request request);
    
  public void setNext(Handler next) { this.next = next; }
}
 
public class HandlerA extends Handler {
  public void handleRequest(Request request) {
    if (canHandle(request)) doHandle(request);
    else if (next != null) next.handleRequest(request);
  }
}


2.總結&思考

這篇文章主要介紹了代碼中if else代碼塊泛濫時的治理措施,在實際應用時可根據具體場景選擇合理的方案,

其實代碼中存在大面積if else本無問題,用一句網路流行語來反駁就是:“你就說能不能用吧!”,但是作為有追求的工程師,我們要對專案以及代碼負責,要及時的識別到代碼中的壞味道,并持續重構優化,最后還想說一定要擁抱開源,多研讀他人優秀代碼,并臨摹、思考、實踐,日拱一卒,不期而至,

3.參考

  • https://programmer.ink/think/how-to-optimize-if-there-are-too-many-if-statements-in-java-code-of-series-17.html
  • WikiPedia
  • Quora

作者:京東零售 韓超

來源:京東云開發者社區

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/553976.html

標籤:其他

上一篇:Midjourney終極指南:提示的藝術

下一篇:返回列表

標籤雲
其他(160101) Python(38193) JavaScript(25469) Java(18172) C(15235) 區塊鏈(8268) C#(7972) AI(7469) 爪哇(7425) MySQL(7219) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5873) 数组(5741) R(5409) Linux(5344) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4580) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2434) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1979) 功能(1967) Web開發(1951) HtmlCss(1950) C++(1928) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1879) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 爛慫if-else代碼優化方案

    # 0.問題概述 代碼可讀性是衡量代碼質量的重要標準,可讀性也是可維護性、可擴展性的保證,因為代碼是連接程式員和機器的中間橋梁,要對雙邊友好。Quora 上有一個帖子: “What are some of the most basic things every programmer should k ......

    uj5u.com 2023-06-01 08:22:20 more
  • Midjourney終極指南:提示的藝術

    通過制作完美的提示,發現使用Midjourney生成令人驚嘆的影像的秘密。在這個終極指南中,將帶您完成創建有效提示的程序,這將釋放Midjourney AI的全部潛力,從而產生與您的創意愿景相匹配的令人驚嘆的視覺效果。 ......

    uj5u.com 2023-06-01 08:21:37 more
  • 決策樹

    # 決策樹 ? 決策樹是一種機器學習的方法。決策樹的生成演算法有ID3(資訊增益), C4.5(資訊增益率)和CART(Gini系數)等。決策樹是一種樹形結構,其中每個內部節點表示一個屬性上的判斷,每個分支代表一個判斷結果的輸出,最后每個葉節點代表一種分類結果。 ? 構造樹的基本想法是隨著樹深度的增加 ......

    uj5u.com 2023-06-01 08:21:25 more
  • ChatGPT正式登陸iOS平臺

    6天前,ChatGPT在美區App Store中上架了官方App,累計下載量已經突破 50 萬次,OpenAI 的 ChatGPT 應用在上架之后,其熱度遠超必應聊天等聊天機器人,以及其它使用 GPT-4 的第三方應用。 3.5是免費的,GPT4是收費的,需要開通Plus會員,還集成了OpenAI的 ......

    uj5u.com 2023-06-01 08:21:20 more
  • 基于AIGC的京東購物助手的技術方案設想

    隨著AIGC的爆火,ChatGPT,GPT-4的發布,我作為一個演算法作業者,深感AI發展的迅猛。最近,OpenAI的插件和聯網功能陸續向用戶公開,我也在第一時間試用了這些最新的功能。在OpenAI的插件市場上,我被一個可以幫助分析食譜,并生成購物清單的功能所吸引。 ......

    uj5u.com 2023-06-01 08:21:06 more
  • 玩轉服務器之網站篇:新手使用WordPress搭建博客和靜態網站部署

    在之前的玩轉服務器系列文章里,我們介紹了如何構建小型的高可用環境、PHP、Python、Java web、docker環境部署,以及Node.js SSR應用,本篇文章主要介紹新手也能快速上手的WordPress博客搭建和靜態網站部署的教程 ......

    uj5u.com 2023-06-01 08:20:47 more
  • 【經驗分享】銳捷EVE在火狐游覽器中,取消一律打開此應用的選項,重

    # 環境: >工具:銳捷EVE模擬器,火狐游覽器,SecureCRT_8.7 系統版本:Windows 10 # 需求描述: >描述:在選擇一律使用此程式打開應用后,找不到取消的地方,也因此無法更改打開的應用。 >提示: >若按照教程還是無法完成操作,可以進入右側的企鵝,找我看看,或者進嗶哩嗶哩自行 ......

    uj5u.com 2023-06-01 08:20:03 more
  • 爛慫if-else代碼優化方案

    # 0.問題概述 代碼可讀性是衡量代碼質量的重要標準,可讀性也是可維護性、可擴展性的保證,因為代碼是連接程式員和機器的中間橋梁,要對雙邊友好。Quora 上有一個帖子: “What are some of the most basic things every programmer should k ......

    uj5u.com 2023-06-01 08:19:55 more
  • 解讀與用戶一起“跳動”的開源實時監控工具 HertzBeat

    摘要:開源專案遇上華為云,會擦出怎樣的火花? 在本期《開源實時監控工具HertzBeat如何與用戶一起“跳動? 》的主題直播中,HertzBeat & TanCloud 創始人鞏超與開發者和伙伴朋友們交流當前主流指標監控方案,解讀HertzBeat及能力特點,并為大家演示了如何通過華為云商店安裝部署 ......

    uj5u.com 2023-06-01 08:19:21 more
  • 讀書的竅門

    提供一個讀書老竅門 - "讀萬卷書". 特別是對于讀國內書籍, 比較好用, 自己之前 準備出書和編輯們聊過, 聊了幾次后暫停出書計劃, 當時編輯說了一個頗有智慧的話: "有深度的書讓國外出就行了". 但凡想找點意思并挖掘全貌的話, 可能類似書籍要讀 個幾十本, 然后可能其中一兩本的作者比較實在零星說 ......

    uj5u.com 2023-06-01 08:18:24 more