Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 10827|回复: 0

# java中多返回值的优雅解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-16 09:29:03 | 显示全部楼层 |阅读模式

    一、通过返回数组(或集合)实现

     @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();
        }
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-5 15:45 , Processed in 0.065306 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表