这样写代码,直接被主管撵出去

前言:

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

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


一、简化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使用不好,小心造成内存泄露!从直观易懂的引用图开始,分析了内存泄漏的原因。


持续更新...

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SunAlwaysOnline

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值