*尽量不要创建对象,最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。重用方式既快速,又流行。如果对象是不可变的,它就始终可以被重用。
反面例子:
String s = new String(“啪啪啪”); //Don’t do this!
改进版本:
String s = “啪啪啪”;
*对于同时提供了静态工厂方法和构造器的不可变类,通常可以使用静态工厂方法而不是构造器,以避免创建不必要的对象。
例如,静态工厂方法Boolean.valueOf(String)几乎总是优先于构造器Boolean(String)。构造器在每次被调用的时候都会创建一个新的对象,而静态工厂方法则从来不要求这样做,实际上也不会这样做。
*`package com.czgo.effective;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtilBad {
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”;
public static Connection getConnection() {
Connection conn = null;
try {
// 1.加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
// 2.获得数据库的连接
conn = DriverManager.getConnection(URL, UNAME, PWD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}`
该类提供的getConnection方法获取JDBC数据库连接对象,每次调用该方法都会新建一个conn实例,而我们知道在平时的开发中数据库连接对象往往只需要一个,也不会总是去修改它,没必要每次都去新创建一个连接对象,每次都去创建一个实例不知道程序会不会出现什么意外情况,这个我不知道,但有一点是肯定的,这种方式影响程序的运行性能,增加了Java虚拟机垃圾回收器的负担。我们可以对它进行改进。
改进版本:
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 {
// 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;
}
}
*使用EntrySet替代KeySet遍历Map
*不要在循环中使用try…catch
*不要让public方法中有太多的形参
public方法即对外提供的方法,如果给这些方法太多形参的话主要有两点坏处:
① 违反了面向对象的编程思想,Java讲求一切都是对象,太多的形参,和面向对象的编程思想并不契合
② 参数太多势必导致方法调用的出错概率增加
*不要将数组声明为public static final,因为这毫无意义,这样只是定义了引用为static final,数组的内容还是可以随意改变的,将数组声明为public更是一个安全漏洞,这意味着这个数组可以被外部类所改变。
*及时关闭流
*及时清除不再需要的会话
*由于JVM的有其自身的GC机制,不需要程序开发者的过多考虑,从一定程度上减轻了开发者负担,但同时也遗漏了隐患,过分的创建对象会消耗系统的大量内存,严重时会导致内存泄露,因此,保证过期对象的及时回收具有重要意义。JVM回收垃圾的条件是:对象不在被引用;然而,JVM的GC并非十分的机智,即使对象满足了垃圾回收的条件也不一定会被立即回收。所以,建议我们在对象使用完毕,应手动置成null。
*当复制大量数据时,使用System.arraycopy()命令。
*乘法和除法,用移位操作替代乘法操作可以极大地提高性能。
*使用多目运算替代简单if…else逻辑判断
*不要在循环体中实例化变量
例子:
import java.util.Vector;
public class LOOP {
void method (Vector v) {
for (int i=0;i < v.size();i++) {
Object o = new Object();
o = v.elementAt(i);
}
}
}
更正:
在循环体外定义变量,并反复使用
import java.util.Vector;
public class LOOP {
void method (Vector v) {
Object o;
for (int i=0;i
*StringBuffer 的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再 丢弃旧的数组。在大多数情况下,你可以在创建 StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。
例子:
public class RSBC {
void method () {
StringBuffer buffer = new StringBuffer(); // violation
buffer.append ("hello");
}
}
更正:
为StringBuffer提供寝大小。
public class RSBC {
void method () {
StringBuffer buffer = new StringBuffer(MAX);
buffer.append ("hello");
}
private final int MAX = 100;
}
*如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。static? local?还是实例变量?访问静态变量和实例变量将会比访问局部变量多耗费2-3个时钟周期。
例子:
public class USV {
void getSum (int[] values) {
for (int i=0; i < value.length; i++) {
_sum += value[i]; // violation.
}
}
void getSum2 (int[] values) {
for (int i=0; i < value.length; i++) {
_staticSum += value[i];
}
}
private int _sum;
private static int _staticSum;
}
更正:
如果可能,请使用局部变量作为你经常访问的变量。
你可以按下面的方法来修改getSum()方法:
void getSum (int[] values) {
int sum = _sum; // temporary local variable.
for (int i=0; i < value.length; i++) {
sum += value[i];
}
_sum = sum;
}
*基于接口的设计通常是件好事,因为它允许有不同的实现,而又保持灵活。只要可能,对一个对象进行instanceof操作,以判断它是否某一接口要比是否某一个类要快。
例子:
public class INSOF {
private void method (Object o) {
if (o instanceof InterfaceBase) { } // better
if (o instanceof ClassBase) { } // worse.
}
}
class ClassBase {}
interface InterfaceBase {}
*采用在需要的时候才开始创建的策略。
例如:
String str="abc";
if(i==1){
list.add(str);
}
应修改为:
if(i==1){
String str="abc";
list.add(str);
}