zoukankan      html  css  js  c++  java
  • 编写高质量代码:改善Java程序的151个建议 --[26~36]

    提防包装类型的null值

    public static int testMethod(List<Integer> list) {
            int count = 0;
            for (Integer i : list) {
                count += (i != null) ? i : 0;
            }
            return count;
        }
    

    包装对象和拆箱对象可以自由转换,这不假,但是要剔除null值,null值并不能转换为基本类型。对于此问题,我们谨记一点:包装类型参与运算时,要做null值校验。

    谨慎包装类型的大小比较

    public class Client {
        public static void main(String[] args) {
            Integer i = new Integer(1345);
            Integer j = new Integer(1345);
            compare(i, j);
        }
    
        public static void compare(Integer i, Integer j) {
            System.out.println(i == j);
            System.out.println(i > j);
            System.out.println(i < j);
    
        }
    }
    

    运行结果:
    false
    false
    false

    1. ij:在java中""是用来判断两个操作数是否有相等关系的,如果是基本类型则判断值是否相等,如果是对象则判断是否是一个对象的两个引用,也就是地址是否相等,这里很明显是两个对象,两个地址不可能相等。
    2. i>j 和 i<j:在Java中,">" 和 "<" 用来判断两个数字类型的大小关系,注意只能是数字类型的判断,对于Integer包装类型,是根据其intValue()方法的返回值(也就是其相应的基本类型)进行比较的(其它包装类型是根据相应的value值比较的,如doubleValue,floatValue等),那很显然,两者不肯能有大小关系的。

    优先使用整型池

    (1)、new产生的Integer对象

        new声明的就是要生成一个新的对象,没二话,这是两个对象,地址肯定不等,比较结果为false。

    (2)、装箱生成的对象

      对于这一点,首先要说明的是装箱动作是通过valueOf方法实现的,也就是说后两个算法相同的,那结果肯定也是一样的,现在问题是:valueOf是如何生成对象的呢?我们来阅读以下Integer.valueOf的源码:

     public static Integer valueOf(int i) {
            assert IntegerCache.high >= 127;
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
    
     private static class IntegerCache {
            static final int low = -128;
            static final int high;
            static final Integer cache[];
    
            static {
                // high value may be configured by property
                int h = 127;
                String integerCacheHighPropValue =
                    sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
                if (integerCacheHighPropValue != null) {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low));
                }
                high = h;
    
                cache = new Integer[(high - low) + 1];
                int j = low;
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++);
            }
    
            private IntegerCache() {}
        }
    

    cache是IntegerCache内部类的一个静态数组,容纳的是-128到127之间的Integer对象。通过valueOf产生包装对象时,如果int参数在-128到127之间,则直接从整型池中获得对象,不在该范围内的int类型则通过new生成包装对象。

    不要随便设置随机种子

    在Java中,随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个原则:
    种子不同,产生不同的随机数
    种子相同,即使实例不同也产生相同的随机数

    import java.util.Random;
    
    public class Client30 {
        public static void main(String[] args) {
            Random r = new Random();
            for(int i=1; i<=4; i++){
                System.out.println("第"+i+"次:"+r.nextInt());
                
            }
        }
    }
    
    Random r = new Random(1000);
    

    1000为随机种子,运行多次,虽然实例不同,但都会获得相同的四个随机数。

    在接口中不要存在实现代码

    public class Client31 {
        public static void main(String[] args) {
            //调用接口的实现
            B.s.doSomeThing();
        }
    }
    
    // 在接口中存在实现代码
    interface B {
        public static final S s = new S() {
            public void doSomeThing() {
                System.out.println("我在接口中实现了");
            }
        };
    }
    
    // 被实现的接口
    interface S {
        public void doSomeThing();
    }
    

    在B接口中声明了一个静态常量s,其值是一个匿名内部类(Anonymous Inner Class)的实例对象,就是该匿名内部类(当然,也可以不用匿名,直接在接口中是实现内部类也是允许的)实现了S接口。

    静态变量一定要先声明后赋值

    静态变量是在类初始化的时候首先被加载的,JVM会去查找类中所有的静态声明,然后分配空间,注意这时候只是完成了地址空间的分配,还没有赋值,之后JVM会根据类中静态赋值(包括静态类赋值和静态块赋值)的先后顺序来执行。对于程序来说,就是先声明了int类型的地址空间,并把地址传递给了i,然后按照类的先后顺序执行赋值操作,首先执行静态块中i = 100,接着执行 i = 1,那最后的结果就是 i =1了。

    不要覆写静态方法

    避免在构造函数中初始化其它类

    public class Client35 {
        public static void main(String[] args) {
            Son son = new Son();
            son.doSomething();
        }
    }
    
    // 父类
    class Father {
        public Father() {
            new Other();
        }
    }
    
    // 相关类
    class Other {
        public Other() {
            new Son();
        }
    }
    
    // 子类
    class Son extends Father {
        public void doSomething() {
            System.out.println("Hi, show me Something!");
        }
    }
    

    构造方法循环调用

  • 相关阅读:
    第三周课程总结
    Java第一次学习总结
    第十二周编程总结
    第九周作业
    第八周作业
    第五周编程总结
    第三周作业
    第二周编程总结
    JAVA第二周学习总结
    2019春总结作业
  • 原文地址:https://www.cnblogs.com/androidsuperman/p/9358122.html
Copyright © 2011-2022 走看看