一. 常量&變量
1.1 當(dāng)成員變量值無需改變時,盡量定義為靜態(tài)常量
在類的每個對象實(shí)例中敬辣,每個成員變量都有一份副本,而成員靜態(tài)常量只有一份實(shí)例。
反例
public class HttpConnection {
private final long timeout = 5L;
...
}
正例
public class HttpConnection {
private static final long TIMEOUT = 5L;
...
}
1.2 盡量使用基本數(shù)據(jù)類型碌更,避免自動裝箱和拆箱
Java 中的基本數(shù)據(jù)類型double、float洞慎、long痛单、int、short劲腿、char旭绒、boolean,分別對應(yīng)包裝類Double焦人、Float挥吵、Long、Integer花椭、Short忽匈、Character、Boolean矿辽。 JVM支持基本類型與對應(yīng)包裝類的自動轉(zhuǎn)換丹允,被稱為自動裝箱和拆箱郭厌。裝箱和拆箱都是需要CPU和內(nèi)存資源的,所以應(yīng)盡量避免使用自動裝箱和拆箱雕蔽。
反例
Integer sum = 0;
int[] values = ...;
for (int value : values) {
sum += value; // 相當(dāng)于result = Integer.valueOf(result.intValue() + value);
}
正例
int sum = 0;
int[] values = ...;
for (int value : values) {
sum += value;
}
1.3 如果變量的初值會被覆蓋折柠,就沒有必要給變量賦初值
反例
List<UserDO> userList = new ArrayList<>();
if (isAll) {
userList = userDAO.queryAll();
} else {
userList = userDAO.queryActive();
}
正例
List<UserDO> userList;
if (isAll) {
userList = userDAO.queryAll();
} else {
userList = userDAO.queryActive();
}
1.4 盡量使用函數(shù)內(nèi)的基本類型臨時變量
在函數(shù)內(nèi),基本類型的參數(shù)和臨時變量都保存在棧(Stack)中萎羔,訪問速度較快液走;對象類型的參數(shù)和臨時變量的引用都保存在棧(Stack)中,內(nèi)容都保存在堆(Heap)中贾陷,訪問速度較慢缘眶。在類中,任何類型的成員變量都保存在堆(Heap)中髓废,訪問速度較慢巷懈。
反例
public final class Accumulator {
private double result = 0.0D;
public void addAll(@NonNull double[] values) {
for(double value : values) {
result += value;
}
}
...
}
正例
public final class Accumulator {
private double result = 0.0D;
public void addAll(@NonNull double[] values) {
double sum = 0.0D;
for(double value : values) {
sum += value;
}
result += sum;
}
...
}
1.5 盡量不要在循環(huán)體外定義變量
在老版JDK中,建議“盡量不要在循環(huán)體內(nèi)定義變量”慌洪,但是在新版的JDK中已經(jīng)做了優(yōu)化顶燕。通過對編譯后的字節(jié)碼分析,變量定義在循環(huán)體外和循環(huán)體內(nèi)沒有本質(zhì)的區(qū)別冈爹,運(yùn)行效率基本上是一樣的涌攻。反而,根據(jù)“ 局部變量作用域最小化 ”原則频伤,變量定義在循環(huán)體內(nèi)更科學(xué)更便于維護(hù)恳谎,避免了延長大對象生命周期導(dǎo)致延緩回收問題 。
反例
UserVO userVO;
List<UserDO> userDOList = ...;
List<UserVO> userVOList = new ArrayList<>(userDOList.size());
for (UserDO userDO : userDOList) {
userVO = new UserVO();
userVO.setId(userDO.getId());
...
userVOList.add(userVO);
}
正例
List<UserDO> userDOList = ...;
List<UserVO> userVOList = new ArrayList<>(userDOList.size());
for (UserDO userDO : userDOList) {
UserVO userVO = new UserVO();
userVO.setId(userDO.getId());
...
userVOList.add(userVO);
}
1.6不可變的靜態(tài)常量憋肖,盡量使用非線程安全類
不可變的靜態(tài)常量因痛,雖然需要支持多線程訪問,也可以使用非線程安全類岸更。
反例
public static final Map<String, Class> CLASS_MAP;
static {
Map<String, Class> classMap = new ConcurrentHashMap<>(16);
classMap.put("VARCHAR", java.lang.String.class);
...
CLASS_MAP = Collections.unmodifiableMap(classMap);
}
正例
public static final Map<String, Class> CLASS_MAP;
static {
Map<String, Class> classMap = new HashMap<>(16);
classMap.put("VARCHAR", java.lang.String.class);
...
CLASS_MAP = Collections.unmodifiableMap(classMap);
}
1.7 不可變的成員變量鸵膏,盡量使用非線程安全類
不可變的成員變量,雖然需要支持多線程訪問怎炊,也可以使用非線程安全類谭企。
反例
@Service
public class StrategyFactory implements InitializingBean {
@Autowired
private List<Strategy> strategyList;
private Map<String, Strategy> strategyMap;
@Override
public void afterPropertiesSet() {
if (CollectionUtils.isNotEmpty(strategyList)) {
int size = (int) Math.ceil(strategyList.size() * 4.0 / 3);
Map<String, Strategy> map = new ConcurrentHashMap<>(size);
for (Strategy strategy : strategyList) {
map.put(strategy.getType(), strategy);
}
strategyMap = Collections.unmodifiableMap(map);
}
}
...
}
正例
@Service
public class StrategyFactory implements InitializingBean {
@Autowired
private List<Strategy> strategyList;
private Map<String, Strategy> strategyMap;
@Override
public void afterPropertiesSet() {
if (CollectionUtils.isNotEmpty(strategyList)) {
int size = (int) Math.ceil(strategyList.size() * 4.0 / 3);
Map<String, Strategy> map = new HashMap<>(size);
for (Strategy strategy : strategyList) {
map.put(strategy.getType(), strategy);
}
strategyMap = Collections.unmodifiableMap(map);
}
}
...
}
二. 對象&類
2.1 禁止使用JSON轉(zhuǎn)化對象
JSON提供把對象轉(zhuǎn)化為JSON字符串、把JSON字符串轉(zhuǎn)為對象的功能评肆,于是被某些人用來轉(zhuǎn)化對象债查。這種對象轉(zhuǎn)化方式,雖然在功能上沒有問題糟港,但是在性能上卻存在問題。
反例
List<UserDO> userDOList = ...;
List<UserVO> userVOList = JSON.parseArray(JSON.toJSONString(userDOList), UserVO.class);
正例
List<UserDO> userDOList = ...;
List<UserVO> userVOList = new ArrayList<>(userDOList.size());
for (UserDO userDO : userDOList) {
UserVO userVO = new UserVO();
userVO.setId(userDO.getId());
...
userVOList.add(userVO);
}
2.2 采用Lambda表達(dá)式替換內(nèi)部匿名類
對于大多數(shù)剛接觸JDK8的同學(xué)來說院仿,都會認(rèn)為Lambda表達(dá)式就是匿名內(nèi)部類的語法糖秸抚。實(shí)際上速和, Lambda表達(dá)式在大多數(shù)虛擬機(jī)中采用invokeDynamic指令實(shí)現(xiàn),相對于匿名內(nèi)部類在效率上會更高一些剥汤。
反例
List<User> userList = ...;
Collections.sort(userList, new Comparator<User>() {
@Override
public int compare(User user1, User user2) {
Long userId1 = user1.getId();
Long userId2 = user2.getId();
...
return userId1.compareTo(userId2);
}
});
正例
List<User> userList = ...;
Collections.sort(userList, (user1, user2) -> {
Long userId1 = user1.getId();
Long userId2 = user2.getId();
...
return userId1.compareTo(userId2);
});
2.3 盡量指定類的final修飾符
為類指定final修飾符颠放,可以讓該類不可以被繼承。如果指定了一個類為final吭敢,則該類所有的方法都是final的碰凶,Java編譯器會尋找機(jī)會內(nèi)聯(lián)所有的final方法。內(nèi)聯(lián)對于提升Java運(yùn)行效率作用重大鹿驼,具體可參見Java運(yùn)行期優(yōu)化欲低,能夠使性能平均提高50%。
反例
public class DateHelper {
...
}
正例
public final class DateHelper {
...
}
注意:使用Spring的AOP特性時畜晰,需要對Bean進(jìn)行動態(tài)代理砾莱,如果Bean類添加了final修飾,會導(dǎo)致異常.