# java中多返回值的優雅解決方案


一、通過返回數組(或集合)實現

 @Test
    public void test1(){
        int a = 10,b =7;
        int[] compute = compute(a,b);
        System.out.println("兩數之和:"+compute[0]);
        System.out.println("兩數之差:"+compute[1]);
    }
    private int[] compute(int a,int b){
        return new int[]{a+b,a-b};
    }
  • 顯然這有致命的缺點,你無法通過下標直觀的對應[0]是什么含義,[1]是什么含義,特別是別人閱讀你的代碼可能會有些許的壓力。可維護性非常差。

二、通過參數列表帶回返回值

  • 同樣一種比較常用的方式,參考代碼如下
    @Test
    public void test2(){
        int a = 10, b = 7;
        IntBox aBox = new IntBox(a);
        IntBox bBox = new IntBox(b);
        compute2(aBox,bBox);
        System.out.println("兩數之和:" + aBox);
        System.out.println("兩數之差:" + bBox);
    }

    private void compute2(IntBox a,IntBox b){
        int diff = a.value - b.value;
        int sum = a.value + b.value;
        a.value = sum;
        b.value = diff;

    }

    private class IntBox{
        private int value;

        public IntBox(int value){
            this.value = value;
        }

        @Override
        public String toString(){
            return String.valueOf(value);
        }
    }

缺點

  1. 基本類型不支持,必須封裝成對象,比如上述代碼封裝了IntBox,造成代碼量冗長。
  2. 反代碼閱讀直覺,可讀性極差。在別人閱讀你的代碼時,看到方法調用,一般認為傳遞了xx參數,獲取到xx返回值,而不是參數都甚至被改變,這極大的增加了維護和理解成本,他為了了解參數被發生什么改變,甚至必須深入方法內部邏輯。

>
>

此方法由於過於反直覺、代碼量冗長,可讀性、可維護性極差,是充滿妥協的解決方案。但由於是最簡單的方法,所以在新手中不少見,我個人建議不到萬萬不得已,別使用。

三、通過map實現

比較容易想到的另一種方案,多返回值通過key-value形式返回,示例如下:

   @Test
    public void test3(){
        int a = 10,b =7;
        Map<String, Integer> resMap = compute3(a,b);
        System.out.println("兩數之和:" + resMap.get("sum"));
        System.out.println("兩數之差:" + resMap.get("diff"));
    }

    private Map<String,Integer> compute3(int a,int b){
        HashMap<String, Integer> hashMap = new HashMap<>();
        hashMap.put("diff",a-b);
        hashMap.put("sum",a+b);
        return hashMap;
    }
  1. 此方式和數組返回值有相似的地方,可以當做前者的升級版,但map的key是可讀的,而數組的下標是沒有可讀性的。
  2. 雖然消除了“數組返回值”時下標不可讀性的理解困難問題,但引入的硬編碼魔法值已經容易造成維護困難,比如后期可能忘記key的值是sum還是summation,甚至單詞拼錯都會把bug引入打運行時。這是動態語言常見的問題,在java身上不應該出現。

四、使用枚舉作為key消除硬編碼

hashMap作為返回值時,最大的缺點就是key的值是string魔法值,消除魔法值常見的辦法就是枚舉。因此考慮枚舉替代String作為key,代碼如下

    @Test
    public void test3(){
        int a = 10,b =7;
        Map<ResType, Integer> resMap = compute3(a,b);
        System.out.println("兩數之和:" + resMap.get(ResType.SUM));
        System.out.println("兩數之差:" + resMap.get(ResType.DIFF));
    }

    private Map<ResType,Integer> compute3(int a,int b){
        HashMap<ResType, Integer> hashMap = new HashMap<>();
        hashMap.put(ResType.DIFF,a-b);
        hashMap.put(ResType.SUM,a+b);
        return hashMap;
    }

    enum ResType{
        SUM,
        DIFF
    }

emmm,比上述好得多了,但是還是有優化空間。

  1. 在方法中必須顯式創建一個hashMap比較麻煩。
  2. 第9行map的泛型是可以不指定的,如果遇到不規范的隊友,依舊存在硬編碼問題。
  3. 必須多定義一個枚舉,一定程度上增加代碼量

最終方案:基於enumMap的自定義返回值

創建自定義返回值MutiResult.java代碼如下:

public class MutiResult<K extends Enum<K>,V>{
    private Map<K, V> resultMap;

    private MutiResult(Map<K, V> resultMap){
        this.resultMap = resultMap;
    }

    /**
     * 獲取返回值
     *
     * @param key
     * @return
     */
    public V get(K key){
        return resultMap.get(key);
    }


    public static <K extends Enum<K>,V> Builder<K, V> build(){
        return new Builder<>();
    }

    /**
     * @param keyClass key的類型
     * @param valueClass value類型
     * @return 建造者對象
     */
    public static <K extends Enum<K>,V> Builder<K, V> build(Class<K> keyClass,Class<V> valueClass){
        return new Builder<>();
    }

    /**
     * 建造者
     *
     * @param <K>
     * @param <V>
     */
    public static final class Builder<K extends Enum<K>,V>{
        private Map<K, V> resultMap;

        Builder(Map<K, V> resultMap){
            this.resultMap = resultMap;
        }

        Builder(){
            this(new ConcurrentHashMap<>());
        }

        /**
         * 生成目標類
         *
         * @return
         */
        public MutiResult<K, V> build(){
            return new MutiResult<>(resultMap);
        }

        /**
         * @param key
         * @param value
         * @return
         * @throws IllegalArgumentException 多次添加同一個key拋出此異常
         */
        public Builder<K, V> add(K key,V value){
            if(resultMap.get(key) != null){
                throw new IllegalArgumentException("重復添加key:" + key);
            }
            resultMap.put(key,value);
            return this;
        }
    }

使用方法:

    enum ResType{
        SUM,
        DIFF
    }


    @Test
    public void test4(){
        int a = 10,b =7;
        MutiResult<ResType, Integer> resMap = compute4(a,b);
        System.out.println("兩數之和:" + resMap.get(ResType.SUM));
        System.out.println("兩數之差:" + resMap.get(ResType.DIFF));
    }

    private MutiResult<ResType, Integer> compute4(int a,int b){
        return MutiResult.build(ResType.class,Integer.class)
                .add(ResType.SUM,a+b)
                .add(ResType.DIFF,a-b)
                .build();
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM