有效的java(第三版)
(一)、考虑用静态方法而不是构造器
1号,优点:静态工厂方法,命名方式则能表达得更清楚。
静态工厂方法,初始化时缓存实例,避免创建不必要重复对象。
静态工厂方法,能返回原返回类型的任意子类型的对象。
静态工厂方法,可以根据调用时传入的不同参数而返回不同类的对象。
静态工厂方法,在编写包含该方法的类时,返回对象的类不需要存在。
2、缺点:私有构造方法,不能被子类实例化。
静态方法没有特殊提示,不方便别人调用容易找到。
3、总结:可以减少对外暴露属性,调用者不必知道内部实现细节。
能够增大提供者对类的控制力,让代码更加简洁,结构清晰。
(二)、遇到多个构造器参数时,考虑用构建者
1号,多个可选参数构造器,可伸缩构造器模式。
例:
公共营养事实(int servingSize,int servings) { this(servingSize,servings,0);}公共营养事实(int servingSize,int servings,int卡路里){这(份,份,卡路里,0);}2、建设者模式,解决多个参数构造器
例:
公共类营养事实{私有int servingSize私人国际服务;//私有实例私人营养事实(建设者建设者){服务量=建设者。食用量;服务=builder.servings} //静态内部类公共静态类生成器{私有int servingSize私人国际服务;公共生成器addServingSize(int vservingSizeal){ serving size=serving size;还这个;} public Builder addServings(int servings){ servings=servings;还这个;}公共营养事实构建(){返回新的营养事实(this);} } }调用者:营养事实。建筑商。添加服务(1).构建()。(三)、私有构造器或者枚举类型来强化一个属性
1、私有构造器来强化
public class Singleton { private static final Singleton INSTANCE=new Singleton();私有Singleton() { if (INSTANCE!=null){ throw new UnsupportedOperationException("实例已经存在");} }公共静态singleton getInstance(){ return INSTANCE;}}2、利用枚举强化单身(最佳方案)
公共枚举猫王实例私有字符串a;公共字符串getA(){ return a;} public void setA(String a){ this。a=a}公共静态void main(String args){ Elvis Elvis=Elvis .实例;猫王。seta(' 1 ');系统。出去。println(猫王。geta());} }(四)、通过私有化构造器强化不可实例化的能力
1、类中包含静态方法和静态域,避免被实例化和继承使用,私有化构造方法,类定义最后的关键字,避免对类扩展(java.lang.Math、java.util.Arrays)
公共最终类实用程序类{//取消非实性的默认构造函数私有实用程序类(){抛出新资产
rtionError(); }}(五)、优先使用依赖注入而不是硬连接资源1、依赖注入方式,往构造器传入资源工厂
// Dependency injection provides flexibility and testabilitypublic class SpellChecker { private final Lexicon dictionary; public SpellChecker(Lexicon dictionary) { this.dictionary = Objects.requireNonNull(dictionary); } public boolean isValid(String word) { ... } public List<String> suggestions(String typo) { ... }}(六)、避免创建不必要的对象
1、不可变对象,始终重用,不需要重新创建。
反例:String str=new String("aaa");正例:String str="aaa";2、尽量使用静态工厂方法替代构造器
package com.czgo.effective;public class Test { public static void main(String<> args) { // 使用带参构造器 Integer a1 = new Integer("1"); Integer a2 = new Integer("1"); //使用valueOf()静态工厂方法 Integer a3 = Integer.valueOf("1"); Integer a4 = Integer.valueOf("1"); //结果为false,因为创建了不同的对象 System.out.println(a1 == a2); //结果为true,因为不会新建对象 System.out.println(a3 == a4); }}3、避免每次都创建没有必要的对象
package com.czgo.effective;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;public class DBUtil { private static final String URL = "jdbc:mysql://127.0.0.1:3306/imooc"; private static final String UNAME = "root"; private static final String PWD = "root"; private static Connection conn = null;//正例 static { try { //Connection conn = null;//反例 // 1.加载驱动程序 Class.forName("com.mysql.jdbc.Driver"); // 2.获得数据库的连接 conn = DriverManager.getConnection(URL, UNAME, PWD); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } public static Connection getConnection() { return conn; }}4、不可变的对象,可以作为初始化缓存起来
// Reusing expensive object for improved performancepublic class RomanNumerals { private static final Pattern ROMAN = Pattern.compile("^(?=.)M*(C
1、一旦对象引用过期,只需清空既可。
public Object pop() { if(size == 0) { throw new EmptyStackException(); } Object result = elements<--size>; elements
对象放到缓存中,不再有用的时候,一直存在内存中,最好使用WeakHashMap缓存。有必要的时候,可以采用定时任务去清空缓存条目。
3、监听器和其他回调
如果你在实现的是客户端注册回调却没有显式地取消注册的API,除非你采取某些动作,否则它们就会积聚。确保回调立即被当作垃圾回收的最佳方法是只保存它们的弱引用(weak reference),例如,只将它们保存成WeakHashMap中的键。
(八)、避免使用终结和清空方法
1、Java本身就有垃圾回收机制,不要自己尝试去调回收方法,会影响性能损失(破坏回收算法的调度),还有可移植性问题。
2、Java不会回收非内存资源,我们通常使用try-finally块来显式管理这些资源,比如文件操作,socket连接等。
(九)、优先使用try-with-resources而不是try-finally
1、资源释放(旧写法)
static String firstLineOfFile(String path) { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(path)); return bufferedReader.readLine(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (null != bufferedReader) { bufferedReader.close(); } } catch (IOException e) { e.printStackTrace(); } } return ""; }2、采用try-with-resources写法,代码简洁
static String firstLineOfFile(String path, String defaultVal) { try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } catch (IOException e) { return defaultVal; } } 3、try-with-resource子句可以使用必须关闭资源轻松编写正确的代码,而使用try-finally子句几乎是不可能做到的。