当前位置 博文首页 > 阳阳的博客:这样写代码,直接被主管撵出去

    阳阳的博客:这样写代码,直接被主管撵出去

    作者:[db:作者] 时间:2021-08-04 08:55

    前言:

    编写具有规范、易懂的代码,注意代码的每一个细节,可以避免稀奇古怪的问题,在一定程度上也能小幅度的提升程序的运行效率。

    以下每个例子都是来源于日常的学习与工作中,随着工作年限的提升,我将会不定时地更新此文。


    一、简化if、else

    减少if、else判断的分支。当条件简单时,可以直接return一个表达式。

    优化前:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?被撵指数:50%

        //判断该数是否是正数
        public boolean isPositive(int num) {
            if (num > 0) {
                return true;
            } else {
                return false;
            }
        }

    优化后:

        //判断该数是否是正数
        public boolean isPositive(int num) {
            return num > 0;
        }

    4行代码直接简化到了1行,并且更加容易阅读。

    当然,优化if、else语句还有很多优化方式,具体可以参考我的这一篇文章优化if else的几种方式


    二、初始化集合时,最好指定容量

    如果能在一开始确定往集合存入的元素个数,那么最好先执行集合的容量,可以有效避免扩容以及内存浪费。

    优化前:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?被撵指数:20%

            Map<String, Object> response = new HashMap<>();
            response.put("code", 0);
            response.put("success", true);
            response.put("msg", "action success");

    优化后:

            Map<String, Object> response = new HashMap<>(3);
            response.put("code", 0);
            response.put("success", true);
            response.put("msg", "action success");

    其实我建议这里指定容量为4可能好点,即不触发扩容的最小的2的倍数。

    当然,这里设置为3也行,HashMap会自动找到第一个大于此数字的2的倍数,即4,并将4设置为table的初始长度。

    接下来会出一篇,讲解怎么去更好地设置HashMap初始容量的文章。

    相关的一个话题:为什么HashMap的容量总是2的倍数?有兴趣的同学可以移步到我的另外一篇文章为什么长度总是2的整数次方


    三、避免不必要的手动装箱或拆箱

    当将一个基本数据类型赋值给一个对应的包装类时,会自动进行装箱。当一个包装类型与基本数据类型比较时,也会触发包装类型的自动拆箱。这些都不需要我们手动的去进行。

    优化前:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?被撵指数:80%

        @Data
        private static class User {
            private Integer age;
        }
    
        public static void main(String[] args) {
            User user = new User();
            user.setAge(new Integer(12));
            //....
            if (user.getAge().intValue()<18){
                System.out.println("未满18岁不得...");
            }
        }

    优化后:

        @Data
        private static class User {
            private Integer age;
        }
    
        public static void main(String[] args) {
            User user = new User();
            user.setAge(12);
            //....
            if (user.getAge() < 18) {
                System.out.println("未满18岁不得...");
            }
        }

    对装箱和拆箱不熟悉的同学,可以参考我的另外一篇文章谈谈拆箱与装箱


    四、在代码中增加事务处理

    在多次对数据库进行操作时,需要增加事务以供出现异常时进行回滚。否则轻则数据冗余,重则数据错乱。

    优化前:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?被撵指数:100%

        public void deleteStudent(int studentId){
            //删除学生
            studentMapper.delete(studentId);
            //其他业务操作,可能会出现异常
            //删除学生成绩
            scoreMapper.delete(studentId);
        }

    优化后:

        @Transactional(propagation = Propagation.REQUIRED)
        public void deleteStudent(int studentId) {
            //删除学生
            studentMapper.delete(studentId);
            //其他操作,可能会出现异常
            //删除学生成绩
            scoreMapper.delete(studentId);
        }

    事务的传播行为还有很多种,有兴趣的可以参考我的另外一篇文章Spring事务的传播行为

    当然,如果涉及分布式事务时,情况会更加复杂,这里不作讨论。


    五、复制大数组时,使用System.arraycopy

    如果我们在业务中,需要复制一个特别大的数组(以万为单位),那么可以考虑使用System.arraycopy

    优化前:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?被撵指数:40%

            //原数组,含有大量元素
            int[] src = new int[20000];
            //目标数组
            int[] des = new int[src.length];
            //复制数组
            for (int i = 0; i < src.length; i++) {
                des[i] = src[i];
            }

    优化后:

            //原数组,含有大量元素
            int[] src = new int[20000];
            //目标数组
            int[] des = new int[src.length];
            //复制数组
            System.arraycopy(src, 0, des, 0, src.length);

    在数组长度单位不同的情况下,复制函数的选择不是一概而论的,具体可以参考我的这篇文章数组复制效率的比较


    六、使用确定值调用equals,或者直接使用Objects.equals

    当使用equals进行比较时,为了避免潜在的空指针风险,应该使用确定值发起equals调用。

    优化前:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?被撵指数:100%

            if (user.getName().equals("jack")) {
                //其他处理
            }

    优化后

            if ("jack".equals(user.getName())) {
                //其他处理
            }
    
            //或者使用Objects.equals()
            if (Objects.equals(user.getName(), "jack")) {
                //其他处理
            }

    Objects是JDK7时引入的,提供静态方法操作对象。

    这年头不怕面试官问Object类的方法,就怕问Objects,怕是很多人都不知道有这个类吧。

    关于Object类,可以看我的这篇文章Object类的方法简谈


    七、线程内使用完ThreadLocal后,记得remove

    子线程使用完ThreadLocal时,可以手动调用ThreadLocal的remove方法,将当前ThreadLocal从子线程的ThreadLocalMap中移除。

    如果我们只是一次性的使用该子线程,那么调用remove方法后,可以在一定程度上避免内存泄漏。

    如果子线程是从线程池中取出来的,那么调用remove方法后,可以避免潜在的数据错乱的问题。

    优化前:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?被撵指数:50%

        static ThreadLocal<Integer> tl = new ThreadLocal<>();
    
        public static void main(String[] args) throws InterruptedException {
    
            Thread t = new Thread(() -> {
                tl.set(1);
                //其他操作
            });
            t.start();
    
            //等待子线程执行完成
            t.join();
    
            //不再使用ThreadLocal
            tl = null;
        }

    优化后:

        static ThreadLocal<Integer> tl = new ThreadLocal<>();
    
        public static void main(String[] args) throws InterruptedException {
    
            Thread t = new Thread(() -> {
                tl.set(1);
                //其他操作
                tl.remove();
            });
            t.start();
    
            //等待子线程执行完成
            t.join();
    
            //不再使用ThreadLocal
            tl = null;
        }

    ThreadLocal使用不当,确实会引起可能的内存泄漏。我的这篇文章ThreadLocal使用不好,小心造成内存泄露!从直观易懂的引用图开始,分析了内存泄漏的原因。


    持续更新...

    cs