zoukankan      html  css  js  c++  java
  • java代码质量

    1.推荐使用枚举定义常量
          常量的声明是每个项目都不可缺少的,又或者是变相使用了数据字典的形式定义了常量,以往我们基本都使用类常量或接口常量的方式声明常量,但Java1.5以后,建议我们使用枚举(Enum)来声明常量,以下我们来看一下两种方式

    Java代码  
    1. public interface Test {  
    2.   
    3.     int SPRING = 0;  
    4.     int Summer = 1;  
    5.     int Autumn = 2;  
    6.     int Winter = 3;  
    7. }  
    Java代码  
    1. public enum Test {  
    2.     SPRING, SUMMER, AUTUMN, WINTER  
    3. }  



          枚举类型比接口常量声明的方式优势体现在哪里呢?
          1.枚举类型声明比接口常量声明更简单

          2.枚举类型其值为稳定的,使用起来更加安全和稳定,请看以下例子

    Java代码  
    1. public static void main(String[] args) {  
    2.         int num = 1;  
    3.         switch (num) {  
    4.         case TestInterface.spring:  
    5.             System.out.println("Spring");  
    6.             break;  
    7.         case TestInterface.summer:  
    8.             System.out.println("Summer");  
    9.             break;  
    10.         case TestInterface.autumn:  
    11.             System.out.println("Autumn");  
    12.             break;  
    13.         case TestInterface.winter:  
    14.             System.out.println("Winter");  
    15.             break;  
    16.         default:  
    17.             System.out.println("error");  
    18.         }  
    19.   
    20.         // Enum  
    21.         TestEnum enum1 = TestEnum.SUMMER;  
    22.         switch (enum1) {  
    23.         case SPRING:  
    24.             System.out.println(TestEnum.SPRING.name());  
    25.             break;  
    26.         case SUMMER:  
    27.             System.out.println(TestEnum.SUMMER.name());  
    28.             break;  
    29.         case AUTUMN:  
    30.             System.out.println(TestEnum.AUTUMN.name());  
    31.             break;  
    32.         case WINTER:  
    33.             System.out.println(TestEnum.WINTER.name());  
    34.             break;  
    35.         }  
    36.     }  



            从上面一段简短的代码就可以看出两者的区别,首先第一段使用接口常量,
            若然此时我的num是10呢?能否传递到switch当中,答案当然是完全可以的,  
            而枚举呢?甚至不需要编写default,因为在case当中已经穷举了所有的枚举
            类型,而枚举类型只的值只能限制与枚举所声明的,还有一点,当我想要把
            0 = spring时,我可以怎么做?像作者一样写一个switch吧.而枚举类型只需
            要简单的调用.name()即可获得枚举类型的名字,也就是SPRING

          3.枚举类型具有内置方法,从上面已经可以看出枚举类型具有name方法获取
            枚举的名字,当然还有values()方法返回1个枚举类内的枚举型,ordinal()
            返回枚举类型的下标等等.

          4.枚举类型可以自定义方法,每个枚举类中的枚举类型实际上就是枚举类的
           一个对象,一个实例,对象当然可以拥有方法,构造方法,非静态方法等,但枚
           举类型不能继承,枚举类型除非重构,否则是无法扩展的,在项目当中推荐使
            用枚举代替接口常量


    2.使用构造函数描述枚举项
          当我们想要使用一个业务逻辑,当使用枚举值为SPRING,但想返回中文为春天时,我们可以怎么做的?此时枚举项的构造函数将会帮助你有效完成

    Java代码  
    1. public enum TestEnum {  
    2.     SPRING("春天"), SUMMER("夏天"), AUTUMN("秋天"), WINTER("冬天");  
    3.   
    4.     private String name;  
    5.   
    6.     TestEnum(String name) {  
    7.         this.name = name;  
    8.     }  
    9.   
    10.     public String getName() {  
    11.         return name;  
    12.     }  
    13.   
    14.     public void setName(String name) {  
    15.         this.name = name;  
    16.     }  
    17.   
    18. }  



          就像编写普通的构造函数一样编写枚举类的构造函数即可,但注意,枚举类型的构造函数是没有访问修饰符的,此时当使用枚举时调用getName()方法即可获得春,夏,秋,冬,而使用接口常量要实现以上逻辑,2个字,麻烦


    3.注意枚举的空值
          我们注意,上述曾说过,枚举类型是枚举类的一个实例,对象,那既然是对象当然可以为null,所以在使用switch或枚举类型时,要注意空值的判断


    4.在switch的default代码增加异常
          上述也曾说过,在使用枚举时,switch当中可以不编写default,因为枚举类型是限定的,稳定的,只要在case当中穷举枚举的值就可以保证不会 执行到default,但前提是在case中进行声明,这就涉及到switch和枚举的关系,是非常脆弱的,只要手工增加了多一个枚举,就必须在 switch中编写case,当遇到这种情况时,在default中抛出异常或记录日志就变得重要


    5.使用valueOf前必须进行检验
          每个枚举类都拥有valueOf()的方法,用来将字符串类型的值转换成一个枚举类型,请观察以下代码

    Java代码  收藏代码
    1. public static void main(String[] args) {  
    2.         String str = "Spring";  
    3.         TestEnum enum1 = TestEnum.valueOf(str);  
    4.         if (enum1 == null)  
    5.             System.out.println("转换失败");  
    6.         else  
    7.             System.out.println("转换成功");  
    8.   
    9.         // 很遗憾,程序运行结果抛出java.lang.IllegalArgumentException  
    10.     }  



          从上面可以看到.我们已经对enum1进行了空值判断,那为什么还会抛出异常呢?原因是异常在调用valueOf()方法时已经抛出,注意我们的枚举是SPRING,而不是Spring,因大小写区分导致失败,我们可以用以下方式来进行判断

    Java代码  
    1. public static void main(String[] args) {  
    2.         String str = "Spring";  
    3.         TestEnum enum1 = null;  
    4.         for (TestEnum e : TestEnum.values()) {  
    5.             if (str.equals(e.getName())) {  
    6.                 enum1 = TestEnum.valueOf(str);  
    7.             }  
    8.         }  
    9.         // 先进行判断即可解决异常参数问题  
    10.     }  



    6.使用枚举工厂代替工厂
          以下代码为工厂模式的传统实现

    Java代码  
    1. interface Car {  
    2.   
    3. }  
    4.   
    5. class FordCar implements Car {  
    6.   
    7. }  
    8.   
    9. class BuickCar implements Car {  
    10.   
    11. }  
    12.   
    13. class CarFactory {  
    14.     public static Car createCar(Class<? extends Car> c) {  
    15.         try {  
    16.             return (Car) c.newInstance();  
    17.         } catch (Exception e) {  
    18.             e.printStackTrace();  
    19.         }  
    20.         return null;  
    21.     }  
    22. }  



          以上代码为实现工厂模式的其中一种,当然亦可以传递字符串通过反射创建等等,以下就来看一下使用枚举类型的实现

    Java代码  收藏代码
    1. public enum CarFactory {  
    2.   
    3.     FordCar {  
    4.         @Override  
    5.         public Car createCar() {  
    6.             return new FordCar();  
    7.         }  
    8.     },  
    9.     BuickCar {  
    10.         @Override  
    11.         public Car createCar() {  
    12.             return BuickCar();  
    13.         }  
    14.     };  
    15.     public abstract Car createCar();  
    16. }  



          枚举当中亦可定义抽象方法,通过抽象方法强制要求每个枚举项都需要实现该方法,而不同的枚举项返回不同的子类,从而实现了工厂方法,使用枚举类型实现工厂方法有以下三个优点
          1.避免错误调用的发生,一般的工厂模式的生产方法都是接受字符串,int类
            型,Class等,但这三种参数是具有宽度的,例如null,边界问题,或Car.class
            等,而且出现这种问题编译时还是可以正常通过的,造成了不必要的错误
         
          2.降低类之间的耦合,不管生产方法接受的是String,int或class,这些都不是
            客户端必须的,而是工厂方法需要的限制,例如class,他必须要传递一个子
            类型的class才能实例化该类型,这严重违背了迪米特原则,也就是最少知识
            原则,一个对象应该对其他对象最少的了解

          3.性能好,使用便捷,枚举类型是以int类型的计算为基础,这是Java中最基本
            的操作,速度当然是非常快速的,至于使用便捷,从代码中就可以看出,我是
            汽车工厂,我需要一辆别克汽车,完全具备面向对象应该拥有的语义性


    7.枚举项的数量限制在64个以内
          为什么要枚举类型要限制在64个以内呢?在看这个问题之前首先我们要知道,JDK为了帮助我们更方便的处理枚举类型,为我们提供了EnumSet和EnumMap两个集合,该集合的详细方法请参考JDK帮助文档,以下来看一段代码

    Java代码  收藏代码
    1. public static void main(String[] args) {  
    2.         EnumSet<TestEnum> enumSet = EnumSet.allOf(TestEnum.class);  
    3.   
    4.         // LargeTestEnum数量为>64  
    5.         EnumSet<LargeTestEnum> enumSet2 = EnumSet.allOf(LargeTestEnum.class);  
    6.   
    7.         System.out.println(enumSet.getClass());  
    8.         // 输出为java.util.RegularEnumSet  
    9.   
    10.         System.out.println(enumSet2.getClass());  
    11.         // 输出为java.util.JumboEnumSet  
    12.   
    13.     }  



          从以上代码可以看到,仅仅因为多出一个枚举类型就导致EnumSet的实现类不一样,这是因为JDK在遇到枚举类型小于等于64个的时候会创建 java.util.RegularEnumSet,而遇到大于64时则会创建java.util.JumboEnumSet,这是因为底层JDK使用了 Long类型进行了映射,我们都知道Long类型是64位的,而枚举类型又可以化为整数来储蓄,刚好64个枚举类型对应到Long类型的64位进行存储, 而当大于64时,则需要使用java.util.JumboEnumSet来创建,使用了Long数组进行存储



    8.小心注解继承
          请观察以下代码

    Java代码  收藏代码
    1. @Retention(RetentionPolicy.RUNTIME)  
    2. @Target(ElementType.TYPE)  
    3. @Inherited  
    4. public @interface TestAnnotation {  
    5.     String test() default "Hello World";  
    6. }  



          以上代码就是声明了一个注解,其中该注解上的三个注解为原元注解,@Retention表示运行时的保留级别,@Target代表该注解可以被方式在什么 地方,@Inherited代表该注解是否可以被继承,而需要注意的地方就是@Inherited,例如类A使用了增加了@Inherited的注解,类 B继承类A,会将增加在类A的注解一并继承下来,这样做利有弊,利的地方是当为父类增加了注解就可以让子类自动继承,从而达到整齐,统一和方便管理,而弊 的地方就是从代码阅读的层面上,只阅读子类代码无法了解到该注解,这是非常糟糕的设计,所以能不使用时尽量不要使用@Inherited


    9.注解配合枚举使用威力更大
          注解中声明的类型可以是枚举类型,这样配合使用将更加能表达语义


    10.注意@Override版本问题
          在Java5的编译环境是,若复写父类方法是,父类若然是接口,增加@Override则不能算是复写,会报出编译错误,而若然是Java6则进行了宽松 处理,实现接口方法亦可以增加@Override,若然是Java6移植到Java5的环境上,就需要注意了 

  • 相关阅读:
    如何在CPU上优化GEMM(下)
    如何在CPU上优化GEMM(上)
    编译ONNX模型Compile ONNX Models
    深度学习加速器堆栈Deep Learning Accelerator Stack
    TVM部署和集成Deploy and Integration
    Relay张量集成
    TVM 架构设计
    NVIDIA Turing Architecture架构设计(下)
    NVIDIA Turing Architecture架构设计(上)
    antD——upLoad组件控制台报错404,405问题
  • 原文地址:https://www.cnblogs.com/blogszixin/p/3287033.html
Copyright © 2011-2022 走看看