美文网首页
Effective Java2 摘要

Effective Java2 摘要

作者: 魔焰joy | 来源:发表于2017-07-28 17:58 被阅读0次

    第1条:

    第29条:优先考虑类型安全的异构容器

    当一个容器(如Map)实现多种类型的key时,可以使用 Class<T>来作为key

        Map<Class<?>,Object> map = new HashMap<>();
        
        public <T> void putV(Class<T> type, T v){
            map.put(type,v);
        }
        
        public <T> T getV(Class<T> type){
            return  type.cast(map.get(type));
        }
    
    

    这种方式有两种局限性:
    第一种,原生态形式使用Class对象,可以通过检查, 例如List<String> 和 List<Char> 的原生态Class对象是 List.class
    解决方案,在put时检查值是否是真的type所对应的实例

      public <T> void putV(Class<T> type, T v){
            map.put(type,type.cast(v));
      }
    

    第二种,有些类型不可以具体化,比如List<String>没有对应的Class对象,只有原生态形式擦除了类型 List.class

    第30条,用枚举代替int常量

    用int类型列举的方式叫做int枚举模式,存在诸多不足,比如可以任意赋值没有任何检查.同样的还有String枚举模式
    枚举提供编译时的类型安全
    枚举可以重新排列或修改,不用重新编译客户端代码
    枚举可以添加方法和域,并实现任意接口

    第31条,用实例域代替序数

    枚举默认和一个单独的int值关联,所有默认枚举有个ordinal方法,返回枚举常量在类型中的数字位置

    public enum Ensemble{
          SOLO,DUET
          
        public int getPosition(){
              return ordinal()+1000;
        }
    }
    

    但是如果调整位置,就会导致使用ordinal相关的方法被破坏,这种情况可以通过添加域来保存相关信息

    public enum Ensemble{
          SOLO(1),DUET(2)
          
        private final int position;
        Ensemble(int position){this.position = position}
        public int getPosition(){
              return position;
        }
    }
    

    第32条,用EnumSet 代替位域

    枚举类型用在集合中时,允许联合使用,int枚举模式如下

    public class Text{
        public static final int STYLE_BOLD = 1<<0; //1
        public static final int STYLE_ITALIC = 1 <<1;
    
        public void applyStyles(int styles){...}
    
    }
    
    //使用
    text.applyStyles(STYLE_BOLD|STYLE_ITALIC)
    
    

    这种可以 使用EnumSet

    public class Text{
        
        public enum Style{ BOLD,ITALIC }
    
        public void applyStyles(Set<Style> styles){...}
    
    }
    
    //使用
    text.applyStyles(EnumSet.of(Style.BOLD,Style.ITALIC))
    
    

    第33条,用 EnumMap代替序数索引

    用枚举索引作为数组下标,隐藏这很多问题,这种情况可以用EnumMap来实现

    public class Herb{
        public enum Type{  ANNUAL,PERENNIAL,BIENNIAL}
    
        private final String name;
        private final Type type;
    
        Herb(String name,Type type){
            this.name = name;
            this.type = type;
        }
    }
    
    Map<Herb.Type,Set<Herb>> herbsByType = new EnumMap<Herb.Type,Set<Herb>>(Herb.Type.class);
    for(Herb.Type t: Herb.Type.values())
        herbsByType.put(t,new HashSet<Herb>());
    for(Herb h:garden)
        herbsByType.get(h.type).add(h);
    
    

    第34条,用接口模拟可伸缩枚举

    枚举在这中语言特性下,是不可以继承扩展的,但有一种方式可以利用接口

    public interface Operation{
        double apply(double x,double y);
    }
    
    public enum BasicOperation implements Operation{
        PLUS("+"){
            public double apply(double x,double y){return x + y;}
        }
       MINUS("-"){
            public double apply(double x,double y){return x - y;}
        }
       TIMES("*"){
            public double apply(double x,double y){return x * y;}
        }
       DIVIDE("/"){
            public double apply(double x,double y){return x / y;}
        }
        private final String symbol;
        BaseOperation(String symbol){this.symbol = symbol;}
    }
    
    public enum ExtendedOperation implements Operation{
        EXP("^"){
            public double apply(double x,double y){return Math.pow(x,y);}
        } 
        private final String symbol;
        ExtendedOperation (String symbol){this.symbol = symbol;}
    }
    

    第35条,注解优先于命名

    第36条,坚持使用Override注解

    第37条,用标记接口定义类型

    比如Serializable接口表明此类可以被序列化

    第38条,检查参数的有效性

    声明的方法,对应的参数要执行检查可以适当的抛出错误

    第39条,必要时进行保护性拷贝

    将参数复制到方法内的局部变量,再处理,避免方法执行后或过程中参数有修改.

    第40条,谨慎设计方法签名

    避免过长的参数列表,可采用:
    分解方法,建辅助类保存多个参数,采用Builder模式三种方式

    第41条,慎用重载

    重载不同函数避免参数有继承关系,选择是由参数决定,没有根据具体对象

    public void m(String str){}
    public void m(CharSequence cs){}
    
    CharSequence[] css =  {"str",new CharSequence()}
    m(css[0]);//执行的是第二个方法
    m(css[1]);//执行的是第二个方法
    

    第42条,慎用可变参数

    使用可变参数时注意参数可能为0个,所以要有显示的检查或者改为一个默认参数和可变参数两个参数

    第43条,返回零长度的数组或者合集,而不是null

    这样做避免调用方进行再次非空判断

    第44条,为所有导出的API元素编写文档注释

    使用标签
    @param @return @throws

    第45条,局部变量的作用域最小化

    避免局部变量被其他代码错误使用

    第46条,for-each循环优先于传统的for循环

    比for循环有性能优势,数组边界值值计算一次.
    但有些情况不可以使用:
    1)删除元素,要用显示的迭代器
    2)修改元素要索引下标
    3)多个集合并行迭代,要用索引同步

    第47条,了解和使用类库

    1,随机 Random.nextInt(int maxValue)
    常用工具库包名
    java.util
    java.util.concurrent
    java.lang

    第48条,精准的结果,避免使用float和double

    这些事有损运算,精准的可以使用 BigDecimal

    第49条,基本类型优先于装箱基本类型

    二者区别:
    1,基本类型只有值,二装箱基本类型则具有与它们的值不同的同一性,装箱的是对象.
    2,装箱的值可以为null
    3,基本类型更节省时间空间.

    第50条,如果其他类型更合适,尽量避免使用字符串

    第51条,当心字符串连接的性能

    要多次字符串拼接时,可以使用StringBuilder替代String

    第52条:通过接口引用对象

    第53条,接口优先于反射机制

    第54条,谨慎使用本地方法JNI

    常用情形
    1,访问特定于平台的机制,如注册表
    2,访问遗留代码库
    3,提升性能
    缺点:
    不安全,不利于阅读,可移植性差

    第58条,对可恢复的情况使用受检查异常,对编程错误使用运行的异常

    三种可抛出结构:
    受检查的异常(checked exception)
    运行时异常 (run-time exception)
    错误(error)

    第78条,考虑用序列化代理代替序列化实例

    序列化增加出错和出现安全问题.
    代理模式:
    为可序列化的类设计一个私有的静态嵌套类,精确地标识外围类的实例的逻辑状态,这个嵌套类被称作序列化代理,它应该有一个单独的构造器,参数类型就是那个外围类,可以防止字节流攻击

    public final class Period{
          private final Date start;
          private final Date end;
    
          public Period(Date start,Date end){
                this.start = new Date(start.getTime());
                this.end  = new Date(end.getTiem());
          }
          
    private startic class SerializationProxy implements Serializable{
          private final Date start;
          private final Date end;
    
         SerializationProxy(Period p){
                this.start = p.start;
                this.end = p.end;
        }
        private startic final long serialVersionUID = ....;
    
        private Object readResolve(){
              return new Period(start,end)
        }
    }
           
    private Object writerReplace(){
            return new SerializationProxy(this);
    }
    privatevoid readObject(ObjectInputStream stream)throws InvalidObjectException{
            throw new InvalidObjectException("")
    }
    
    }
    

    局限性:
    不能与可以被客户端扩展的类兼容,也不能和包含循环的某些类兼容.
    开销代价变大

    相关文章

      网友评论

          本文标题:Effective Java2 摘要

          本文链接:https://www.haomeiwen.com/subject/wuhzkxtx.html