碼農(nóng)必備干活:Java編碼——高效代碼匯總小技巧

一. 常量&變量

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)致異常.

# 鏈接 Java程序員福利"常用資料分享"

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凄鼻,一起剝皮案震驚了整個濱河市腊瑟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌块蚌,老刑警劉巖闰非,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異峭范,居然都是意外死亡财松,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門虎敦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來游岳,“玉大人,你說我怎么就攤上這事其徙∨咂龋” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵唾那,是天一觀的道長访锻。 經(jīng)常有香客問我,道長闹获,這世上最難降的妖魔是什么期犬? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮避诽,結(jié)果婚禮上龟虎,老公的妹妹穿的比我還像新娘。我一直安慰自己沙庐,他們只是感情好鲤妥,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布佳吞。 她就那樣靜靜地躺著,像睡著了一般棉安。 火紅的嫁衣襯著肌膚如雪底扳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天贡耽,我揣著相機(jī)與錄音衷模,去河邊找鬼。 笑死蒲赂,一個胖子當(dāng)著我的面吹牛阱冶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凳宙,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼熙揍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了氏涩?” 一聲冷哼從身側(cè)響起届囚,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎是尖,沒想到半個月后意系,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饺汹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年蛔添,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兜辞。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡迎瞧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出逸吵,到底是詐尸還是另有隱情凶硅,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布扫皱,位于F島的核電站足绅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏韩脑。R本人自食惡果不足惜氢妈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望段多。 院中可真熱鬧首量,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至生百,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間柄延,已是汗流浹背蚀浆。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搜吧,地道東北人市俊。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像滤奈,于是被迫代替她去往敵國和親摆昧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容