基于Java的架构设计

Effective java总结

2016-11-06  本文已影响85人  nyle

总结

effecttive java 注意的地方简单概括下。
并发部分没有java并发编程实战全。就不写在这了

effectiveJava.png

JDBC

java Database Connectivity java数据库连接

重叠构造器

这种构造器是什么,就是提供很多个构造函数。短的构造器,会给没有赋值的,给一个默认值。
public A(int i, int j) {
    this(i, j ,0);
}

public A(int i, int j, int k) {
    ...
}


这种模式是可行,但是当有很多参数的时候,客户端代码会很难编写,并且仍然很难以阅读。

Build模式

new NutritionFacts.Build(1, 2).calories(11).sodium(23).build();
优秀的可读性、有保证重复构造器模式的安全性。
不足: 为了创建对象,要先构造它的构造器。 只有在很多参数的时候才使用,比如4个活着更多的参数。
如果类的构造器活着静态工厂中具有多个参数,设计这种类的时,Build模式就是种不错的选择。

singleton

最原始的singleton

public class Singleton
{
    private volatile static Singleton singleton = null;
    private Singleton()  {    }
    public static Singleton getInstance()   {
        if (singleton== null)  {
            synchronized (Singleton.class) {
                if (singleton== null)  {
                    singleton= new Singleton();
                }
            }
        }
        return singleton;
    }
}

私有构造器单例模型

public class Elvis {
    public static final Elvis instantce = new Elvis();
    private Elvis() {...}
}

但是某些客户端可以反射机制调用私有构造器,所有要防止其他人调用私有的构造器,要在创建第二个实例的时候抛出异常。

静态工厂方法

public class Elvis {
    private static final Elvis instantce = new Elvis();
    private Elvis() {...}
    public static Elvis getInstance() {return instantce;}
}

但是这种会在类构造的时候就会调用。所以用下面这种:
由于 SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,因此它只有在getInstance()被调用时才会真正创建;
public class Singleton {
    private static class SingletonHolder {
    private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton (){}
    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

枚举Singleton

public enum Elvis {
    INSTANCE;
}

单例序列化问题

要实现readResolve()函数;
而枚举enum单例不需要处理这个
最佳的实现方法

怎样实现不可实例化的能力,比如说一些静态类

让这类包含私有的构建器

避免自动装箱autoboxing

Long sum = 0l;
for(int i = 0; i < Interger.Max_Value; i++) {
    sum += i;
}
这个启示会构建大约 2的31次方个Long实例。
如果用long而不是Long,就可以解决

优先使用基本类型而不是装箱的基本类型。

java的什么时候需要考虑内存泄漏的问题

只要是类自己管理内存的,比如说实现了一个对象池,堆栈,就应该警惕内存泄漏的问题
缓存
监听器和其他回调(因为要保存需要回调的客户端,这里最好只保存弱引用,否则可能会堆积)

java缓存,怎么实现,方法 ?

只要缓存之外存在某个项的引用,该项就有意义,可以用WeakHashMap代表缓存。
或者起一个后台线程定时清理
或者在新家条目的时候清理,LinkedHashMap removeEldestEntry,lRu
更复杂,使用java.lang.ref

弱引用是什么,有什么用?

终结方法的问题。

不应该依赖终结方法来更新重要的持久状态。因为java规范不保证他们会执行。
而且有严重的性能问题

子类中的终结方法不会自动调用父类的终结方法,必须要手动调

除非最为安全网,或者未来终止非关键多本地资源,否则不要使用终结方法。

object.equals方法

这些方法都要遵循约定,因为像hashset、list这些都遵循约定的。如果有问题会出错。

  1. 自反性

  2. 对称性

     这里要注意子类和父类的equals结果可能不一样。
    
  3. 传递性

     同样对于子类和父类有问题。
    
  4. 一致性

另外注意点:

float和double要单独比较。 
不要将equals中的Object替换成其他class,因为这样就没有覆盖了

重写了equals方法点要重写hashcode()

因为hashMap这些如果没重写,会有问题。
规则见书

DAO

Data Access Object

接口优于抽象类

接口可以继承自两个接口

常量接口

是不良使用!类如果继承类常量接口,它的所有子类的命名空间也会被接口中的常量所污染。

应该用什么呢:

枚举类型

不可实例化的工具类,private的构造函数。

类层次优于标签类

就是说在class中加type,不如编写不同形式的class

策略模式

比如Arrays.sort(arrays, new Comparator<String> {
    public int compare(String s1, s2) {
    }
})

java中实现这种模式,要声明一个接口来表示该策略,然后为每一个具体策略声明一个实现了该接口的类。
通常用匿名类
当一个具体策略是设计用来重复使用的,别实现为私有的静态成员类,并通过公有的静态final 域被导出。
public class A {
    private final B = new B();
    private static class B imple... {
        private String name;
        private int age;
}

}

嵌套类

  1. 静态成员类

    如果是public,就最好看做一个普通的类,只是碰巧申明在内部
    可以访问外围类的所有static成员,包括私有
    如果是private,他就只能在外围类的内部才能访问。

  2. 非静态成员类

    非静态成员类与一个外部类相关联,可以直接调用外部类的非static方法

泛型

Set<Object>  是一个参数化类型,可以包含任意对象的集合。但是如果Set<String> 传进来,会报错
Set<?> 是一个通配符类型,不能将任何(除了null)放到里面
Set 是一个原生态类型,它脱离了泛型类型。

class DelayQueue<E extends Delayed> . 可以有extends的泛型,传进来的必须是这个的子类。

总而言之,泛型比在客户端代码中进行类型转换更安全,也更容易。

List优于数组

这些数组创建表达式不合法:
new List<E>[]
new List<String>[]
new E[]

传一个类的超类子类进泛型函数

如果要传一个子类进函数,进行处理。用 do(Iterable<? extends E> src)
如果需要一个类的超类传进函数,用do(Iterable<? super E>)

如果想对<?>的list进行操作怎么办

因为这种只能插null。那么需要定义一个泛型的辅助方法

枚举

  1. 枚举天生是不可变的,所有的域都应该是final的,他们可以是公有的,但最好做成私有的.
  2. ordinal 返回每个枚举常量的位置,但是不要用这个,除非自己写一个enumSet这种东西的时候。
  3. enumSet很快,相当于位域实现,实际就是用一个long来标记。
  4. enumMap很快,相当于一个数组,index就是用ordinal,所以get的时候很快
  5. 枚举可以extents吗?不行

每种枚举类实现的方法不同怎么实现

可以用抽象方法

public enum Operation {
    PLUS {double apply(double a, double b){return a + b}},
    SUB {double apply(double a, double b){return a - b}},
    abstract double apply(double a, double b);
}

当想给枚举分类,不同类的枚举用不同的策略,怎么实现

多个枚举常量同时共享相同的行为时,则考虑枚举策略

enum PayrollDay {
    MON(PayType.WEEKDAY),TUE(PayType.WEEKDAY)
    ....SAT(PayType.WEEKEND), SUN(PayType.WEEKDAY);
    
    ...
    private final PayType type;
    
    double pay() {
        return type.pay();
    }
    
    private enum PayType {
        ....
        abstact double pay();
    }
}

注解

一般的自己的注解

@Retention(RetentionPolicty.RUNTIME)
@Targe(ElementType.METHOD/CLASS)

可变参数

可变参数每次调用都会导致一次数组的分配和初始化,性能不如正常函数。

要精确计算浮点应该用什么

float和double不准,要不就用整数,然后确定有效位。
或者使用BigDecimal(不过有点慢)

装箱类型

每次与基础类型进行混合计算时,都会自动拆箱和装箱。要考虑性能问题

StringBuild,StringBuffer

StringBuffer线程安全,但没有StringBuild速度快

反射

反射利用了 java.lang.reflect 包里。
但是反射调用回避普通方法慢很多

并发

Thread.stop 不安全,不要用。可能导致数据破坏
不要依赖线程调度器
线程组已经过时了,不要用

executor 和task 优于线程

  1. Executors.newCachedThreadPool 每次如果不够久新建线程。
  2. Executors.newFixedThreadPool 提供了一个包换固定线程的线程池
  3. ScheduledThreadPoolExecutor 用来代替timer

上一篇下一篇

猜你喜欢

热点阅读