Effective Java总结

来源:互联网 发布:java随机数生成1到10 编辑:程序博客网 时间:2024/06/01 10:06

简洁!

首先学会基本的规则,然后要知道什么时候可以打破这些规则!

仅编写出能有效工作且能被别人理解的代码是不够的,还必须把代码组织成易于修改的形式!

代码应该被重用,而不是被拷贝!

 

1、In Action

(1)

(2)

(3)

 

1、TIPS

(1)创建和销毁对象

a、用静态工厂方法代替构造器

静态工厂方法不必在每次调用它时都创建一个新对象。可将构建好的实例缓存起来进行重复使用。如:Boolean.valueOf()——从不创建对象。享元模式。

静态工厂方法可以返回原返回类型的任何子类型的对象。一个应用为:API可以返回对象,同时又不会使对象的类变成公有的。接口不能有静态方法!通过接口来引用被返回的对象是一种好习惯!

 

静态工厂方法的一些惯用名称:

valueOf:该方法返回的实例与它的参数具有相同值;

getInstance:返回的实例通过方法的参数的描述的;

newInstance:newInstance能保证返回的每个实例都与所有其他实例不同。 

 

b、遇到多个(4个或者更多个)构造器参数时考虑构建器:易读和安全;

Builder模式:既有像构造器那样的安全性(线程安全),也能像javabean模式那么好的可读性。 不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或静态工厂),得到一个builder对象,然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数。最后,客户端调用无参的build方法来生成不可变的对象。这个builder是它构建的类的静态成员类。

如:

publi class Person {

     private final int age;

     private final String name;

 

     public static class Builder {

            //required parameters

            private final int age;

            //optional parameters

            private String name = "cc";

  

            public Builder(int age) {

                       this.age = age;

            }

            public Buidler setName(String val) {

                         name = val;

                         return this;

              }

              public Person build() {

                         return new Person(this);

              }

     }

 

      private Person(Builder builder) {

               age = builder.age; 

               name = builder.name;

      }

}

客户端调用:Person p = new Person.Builder(10).setName("aa").build();

 

c、用私有构造器或枚举类型强化单例Singleton

单元素的枚举类型是实现Singleton的最佳方法。

 

d、通过私有构造器强化不可实例化的能力

构造器是私有的,因此不可以在该类的外部访问它。也使得此类不能被子类化,因为子类没有可访问的父类构造器调用。

 

e、避免创建不必要的对象

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

f、消除过期对象引用

若一个对象引用被保留下来,那么垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的所有其它对象。

 

只要类是自己管理内存,就应该警惕内存泄露问题。一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。

 

内存泄露的另一个常见来源是缓存。

缓存应要清除掉没用的项,这项清除工作可以由一个后台线程(或Timer或ScheduledThreadPoolExecutor)来完成,或者可以在给缓存添加新条目时顺便进行清理。LinkedHashMap类利用它的removeEldestEntry方法可以很容易实现。

对于更加复杂的缓存,必须直接使用java.lang.ref。如:只要在缓存之外存在对某个项的键的引用,该项就有意义,那么就可以用WeakHashMap代表缓存;当缓存中的项过期之后,它们就会自动被删除。只有当所要的缓存项的生命周期是由该键的外部引用而不是由值决定时,WeakHashMap才有用处。

 

内存泄露的另一个常见来源是监听器和其它回调。若你实现了一个API,客户端在这个API中注册回调,却没有显式取消注册。

确保回调立即被当做垃圾回收的最佳方法是只保存它们的弱引用(weak reference),如只将它们保存成WeakHashMap中的键。

 

Heap剖析工具:Heap Profiler用于发现内存泄露。

 

g、避免使用终结方法

 

 

(2)对于所有对象都通用的方法

a、覆盖equals时总要覆盖hashCode

b、始终要覆盖toString

c、谨慎覆盖clone

d、考虑实现Comparable接口

 

(3)

 

2、PS

(1)服务提供者框架:指多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。如JDBC API。由静态工厂方法构成。

服务提供者框架中有三个组件:服务接口(提供者实现的);提供者注册API(系统用来注册实现,让客户端访问他们的);服务访问API(是客户端用来获取服务的实例的)。

服务访问API是灵活的静态工厂。

 

服务提供者框架的第四个组件可选:服务提供者接口(提供者负责创建其服务实现的实例)。若没有服务提供者接口,实现就按照类名称注册,并通过反射方式进行实例化。

 

对于JDBC来说,Connection就是它的服务接口,DriverManager.registerDriver是提供者注册API,DriverManager.getConnection是服务访问API,Driver是服务提供者接口。

 

Service provider framework sketch:

//Service interface

public interface Service {

 

}

 

//Service provider interface

public interface Provider{

         Service newService();

}

 

public class Services{

       private Services() {}

  

       private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();

       

       public static final String DEFAULT="def";

 

       //Provider registration API

      public static void registerDefaultProvider(Provider p) {

                 registerProvider(DEFAULT, p);

      }

 

      public static void registerProvider(String name, Provider p) {

                  providers.put(name, p);

      }

 

      public static Service newInstance() {

                 return newInstance(DEFAULT);

      }

 

     public static Service newInstance(String name) {

             Provider p = providers.get(name);

             if(p == null) {

                       throw new Exception();

             }

             return p.newService(); 

    }

}

 

(2)