背景:
閱讀新聞
10個(gè)實(shí)用的但偏執(zhí)的Java編程技術(shù)
[日期:2015-08-31]
來源:碼農(nóng)網(wǎng)
作者:小峰
[字體:大 中 小]
在沉浸于編碼一段時(shí)間以后(比如說我已經(jīng)投入近20年左右的時(shí)間在程序上了),你會(huì)漸漸對(duì)這些東西習(xí)以為常。因?yàn)?你知道的……
任何事情有可能出錯(cuò),沒錯(cuò),的確如此。
這就是為什么我們要采用“防御性編程”,即一些偏執(zhí)習(xí)慣的原因。下面是我個(gè)人認(rèn)為的10個(gè)最有用但偏執(zhí)的Java編程技術(shù)。一起來看一看吧:
1.將String字符串放在最前面
為了防止偶發(fā)性的 異常,我們通常將String放置在equals()函數(shù)的左邊來實(shí)現(xiàn)字符串比較,如下代碼:
// Bad
if (variable.equals("literal")) { ... }
// Good
if ("literal".equals(variable)) { ... }
這是隨便用腦子想想就可以做的事,從Bad版本的代碼改寫表達(dá)式到Good版本的代碼,這中間并不會(huì)丟失任何東西。歡迎不同的觀點(diǎn)…
2.不要相信早期的JDK API
在Java早期,編程是一件非常痛苦的事情。那些API仍然很不成熟,也許你已經(jīng)碰到過下面的代碼塊:
String[] files=file.list();
// Watch out
if (files !=null) {
for (int i=0; i < files.length; i++) {
...
}
}
看上去很偏執(zhí)?也許吧,但請(qǐng)看Javadoc:
如果這個(gè)虛擬路徑不表示一個(gè)文件夾目錄,則此方法返回null。否則將會(huì)返回一個(gè)字符串?dāng)?shù)組,每一個(gè)字符串表示目錄中的文件或文件夾。
對(duì),沒錯(cuò)。我們可以添加一些校驗(yàn):
if (file.isDirectory()) {
String[] files=file.list();
// Watch out
if (files !=null) {
for (int i=0; i < files.length; i++) {
...
}
}
}
3.不要相信“-1”
我知道這是偏執(zhí)的,但Javadoc中對(duì) String.indexOf()方法明確指出:對(duì)象內(nèi)第一次出現(xiàn)指定字符的位置索引,如果為-1則表示該字符不在字符序列中。
所以使用-1是理所當(dāng)然的,對(duì)嗎?我說不對(duì),請(qǐng)看以下代碼:
// Bad
if (string.indexOf(character) !=-1) { ... }
// Good
if (string.indexOf(character) >=0) { ... }
誰知道呢。也許到時(shí)候他們改變了編碼方式,對(duì)字符串并不區(qū)分大小寫,也許更好的方式是返回-2?誰知道呢。
4.避免意外賦值
是的。這種事情也許經(jīng)常會(huì)發(fā)生。
// Ooops
if (variable=5) { ... }
// Better (because causes an error)
if (5=variable) { ... }
// Intent (remember. Paranoid JavaScript:===)
if (5===variable) { ... }
所以你可以將比較常量放置在左側(cè),這樣就不會(huì)發(fā)生意外賦值的錯(cuò)誤了。
5.檢查Null和Length
無論如何,只要你有一個(gè)集合、數(shù)組等,請(qǐng)確保它存在,并且不為空。
// Bad
if (array.length > 0) { ... }
// Good
if (array !=null && array.length > 0) { ... }
你并不知道這些數(shù)組從哪里來,也許是來自早期版本的JDK API,誰知道呢。
6.所有的方法都是final的
你也許會(huì)告訴我你的開/閉原則,但這都是胡說八道。我不相信你(正確繼承我這個(gè)父類的所有子類),我也不相信我自己(不小心繼承我這個(gè)父類的所有子類)。所以對(duì)于那些意義明確的方法要嚴(yán)格用final標(biāo)識(shí)。
// Bad
public void boom() { ... }
// Good. Do九度快排系統(tǒng) https://www.190seo.comn't touch.
public final void dontTouch() { ... }
7.所有變量和參數(shù)都是final
就像我說的。我不相信我自己(不要意外覆蓋我的值)。話雖如此,我不相信我自己的是因?yàn)椤?/p>

…這就是為什么所有的變量和參數(shù)都是final的原因。
// Bad
void input(String importantMessage) {
String answer="...";
answer=importantMessage="LOL accident";
}
// Good
final void input(final String importantMessage) {
final String answer="...";
}
8.重載時(shí)不要相信泛型
是,它可以發(fā)生。你相信你寫的超級(jí)好看的API,它很直觀,隨之而來的,一些用戶誰只是將原始類型轉(zhuǎn)換成Object類型,直到那該死的編譯器停止發(fā)牢騷,并且突然他們會(huì)鏈接錯(cuò)誤的方法,以為這是你的錯(cuò)誤。
看下面的代碼:
// Bad
void bad(T value) {
bad(Collections.singletonList(value));
}
void bad(List values) {
...
}
// Good
final void good(final T value) {
if (value instanceof List)
good((List>) value);
else
good(Collections.singletonList(value));
}
final void good(final List values) {
...
}
因?yàn)?你知道……你的用戶,他們就像
// This library sucks
@SuppressWarnings("all")
Object t=(Object) (List) Arrays.asList("abc");
bad(t);
相信我。這一切我都看到過。包括下面的

這種偏執(zhí)還是不錯(cuò)的。
9.總是在Switch語句的Default中拋出異常
Switch語句……它們其中一個(gè)可笑的語句我不知道該對(duì)它敬畏還是哭泣,但無論如何,既然我們堅(jiān)持用switch,那我們不妨將它用得完美,看下面的代碼:
// Bad
switch (value) {
case 1: foo(); break;
case 2: bar(); break;
}
// Good
switch (value) {
case 1: foo(); break;
case 2: bar(); break;
default:
throw new ThreadDeath("That'll teach them");
}
當(dāng)value==3時(shí),將會(huì)出現(xiàn)無法找到的提示,而不會(huì)讓人不知所謂。
10.Switch語句帶花括號(hào)
事實(shí)上,switch是最邪惡的語句,像是一些喝醉了或者賭輸了的人在寫代碼一樣,看下面的例子:
// Bad, doesn't compile
switch (value) {
case 1: int j=1; break;
case 2: int j=2; break;
}
// Good
switch (value) {
case 1: {
final int j=1;
break;
}
case 2: {
final int j=2;
break;
}
// Remember:
default:
throw new ThreadDeath("That'll teach them");
}
在switch語句中,每一個(gè)case語句的范圍只有一行語句,事實(shí)上,這些case語句甚至不是真正的語句,他們就像goto語句中的跳轉(zhuǎn)標(biāo)記一樣。
結(jié)論
偏執(zhí)編程看起來似乎不可思議,有時(shí),因?yàn)榇a經(jīng)常被證明是更詳細(xì)一點(diǎn),但并不是需求需要。你可能會(huì)想,“哦,這是絕不會(huì)發(fā)生的”,但正如我所說。經(jīng)過20年左右的時(shí)間編程,你不希望只修復(fù)這些愚蠢的bug,因?yàn)榫幊陶Z言是如此的陳舊的和有缺陷的。因?yàn)槟阒馈?/p>
現(xiàn)在到你了!什么是你在編程最偏執(zhí)的怪癖?
本文永久更新鏈接地址:http://www.linuxidc.com/Linux/2015-08/122523.htm

八成Java開發(fā)者解答不了的問題
Java程序性能優(yōu)化之代理模式
相關(guān)資訊
Java編程 Java編程技術(shù)
Java 老矣,尚能飯否? (今 19:38)
Java 并發(fā)編程中使用 ReentrantLoc (12/05/2015 22:49:19)
Java:過去、未來的互聯(lián)網(wǎng)編程之王 (07/31/2015 14:50:02)
Java編程基本概念 (03月07日)
for(int a:i)在Java 編程中的使用 (08/24/2015 07:29:34)
Java編程思想學(xué)習(xí)筆記——泛型 (07/04/2015 13:46:39)
本文評(píng)論
查看全部評(píng)論 (0)
表情: 
姓名:
匿名
字?jǐn)?shù)
同意評(píng)論聲明
評(píng)論聲明
尊重網(wǎng)上道德,遵守中華人民共和國(guó)的各項(xiàng)有關(guān)法律法規(guī)
承擔(dān)一切因您的行為而直接或間接導(dǎo)致的民事或刑事法律責(zé)任
本站管理人員有權(quán)保留或刪除其管轄留言中的任意內(nèi)容
本站有權(quán)在網(wǎng)站內(nèi)轉(zhuǎn)載或引用您的評(píng)論
參與本評(píng)論即表明您已經(jīng)閱讀并接受上述條款
最新資訊
Java 老矣,尚能飯否?
Google 再次從官方商店下架偽裝成合法程序
一銘桌面操作系統(tǒng)4.0 SP1安裝使用初體驗(yàn)
Opus 1.2發(fā)布,開源免專利費(fèi)音頻編解碼器
Java中抽象類的定義和使用
Java實(shí)現(xiàn)內(nèi)部類
C語言如何分離一個(gè)數(shù)的高低位,如何將兩個(gè)
C語言之鞍點(diǎn)的查找
C語言實(shí)現(xiàn)牛頓迭代法解方程
Android編譯系統(tǒng)產(chǎn)品線(基于友善之臂
背景:
閱讀新聞
Java程序性能優(yōu)化之代理模式
[日期:2015-08-31]
來源:Linux社區(qū)
作者:kimoyoyo21
[字體:大 中 小]
代理模式的用處很多,有的是為了系統(tǒng)安全,有的是為了遠(yuǎn)程調(diào)用,這里我們,主要探討下由于程序性能優(yōu)化的延遲加載。
首先我們來看下代理模式設(shè)計(jì)
先首先簡(jiǎn)單闡述下什么叫代理模式吧
代理設(shè)計(jì)模式有一個(gè)接口,另外還有真實(shí)主題類和代理類,真實(shí)類和代理類都實(shí)現(xiàn)了接口,代理類和真實(shí)主題類是關(guān)聯(lián)和聚合關(guān)系。客戶端與接口關(guān)聯(lián)。
代理分為靜態(tài)代理和動(dòng)代態(tài)代理所謂靜態(tài)代理是為真實(shí)主題手動(dòng)創(chuàng)建一個(gè)代理,而動(dòng)態(tài)代理則是jvm在運(yùn)行時(shí)運(yùn)用字節(jié)碼加載技術(shù)自動(dòng)創(chuàng)建一個(gè)代理,并不用關(guān)心接口和真是主題類
具體如何實(shí)現(xiàn)
哦,對(duì)了差點(diǎn)忘了。代理模式到底是怎樣優(yōu)化程序的,我們具體來看下。
客戶端測(cè)試代碼如下:
public class TestDynamicProxy {
public static void main(String[] args) {
IDBQuery iy=JdkDBqueryHandler.createJdkProxy();
System.out.println(iy.request());
}
}
Ps:客戶端與接口關(guān)聯(lián)
代理實(shí)現(xiàn)和邏輯處理類如下:
import java.lang.reflect.*;
public class JdkDBqueryHandler implements InvocationHandler{
IDBQuery real=null;
public Object invoke(Object object, Method method ,Object[] args ) {
if(real==null) {
real=new DBQuery();
}
return real.request();
}
public static IDBQuery createJdkProxy() {
IDBQuery jdkProxy=(IDBQuery)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{IDBQuery.class},new JdkDBqueryHandler());
return jdkProxy;
}
}
Ps:代理實(shí)現(xiàn)和邏輯處理類是實(shí)現(xiàn)延遲加載的關(guān)鍵代碼
當(dāng)客戶端開始加載時(shí)會(huì)加載到代碼實(shí)現(xiàn)和邏輯處理類并創(chuàng)建代理實(shí)例,但并不會(huì)初始化真實(shí)主題類。只有當(dāng)調(diào)用iy.request()方法時(shí)才會(huì)執(zhí)行代理實(shí)現(xiàn)和邏輯處理類的invoke()方法并加載并初始化真實(shí)主題類。這樣才實(shí)現(xiàn)了延遲加載,減少系統(tǒng)初始化時(shí)間,提高用戶體驗(yàn)。在一定程度上也可以節(jié)約內(nèi)存空間,避免內(nèi)存空間浪費(fèi),(因?yàn)橛玫臅r(shí)候才記載初始化的嘛,不用也開辟內(nèi)存空間那不是浪費(fèi)了嘛)
這里另外附上接口類和真實(shí)主題類的代碼,方便大家測(cè)試
接口類
public interface IDBQuery {
String request();
}
真實(shí)主題類
public class DBQuery implements IDBQuery {
public DBQuery() {
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
public String request() {
return "request coming";
}
}
以上是jdk自帶的動(dòng)態(tài)代理實(shí)現(xiàn) 另外還有較流行的CGLIB動(dòng)態(tài)代理,javaassist動(dòng)態(tài)代理
這里我先介紹一下CGLIB動(dòng)態(tài)代理。CGLIB動(dòng)態(tài)代理和jdk的動(dòng)態(tài)代理非常的相似,我們來看下具體的代碼
客戶端代碼如下:
public class TestDynamicProxy {
public static void main(String[] args) {
IDBQuery iy=CglibDbQueryInterceptor.createCglibProxy();
System.out.println(iy.request());
}
}
這里不過多解釋,看完上面的例子相信大家都明白了
代理實(shí)現(xiàn)和邏輯處理類如下
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibDbQueryInterceptor implements MethodInterceptor{
IDBQuery real=null;
public Object intercept(Object args0,Method arg1,Object[] args2,MethodProxy args3)throws Throwable {
if(real==null) {
real=new DBQuery();
}
return real.request();
}
public static IDBQuery createCglibProxy() {
Enhancer eh=new Enhancer();
eh.setCallback(new CglibDbQueryInterceptor());//指定切入器,定義代理類邏輯
eh.setInterfaces(new Class[]{IDBQuery.class});//指定接口
IDBQuery proxy=(IDBQuery)eh.create();//創(chuàng)建代理實(shí)例
return proxy;
}
}
Jdk 的動(dòng)態(tài)代理和 CGLIB 實(shí)現(xiàn)動(dòng)態(tài)代理大致都要指定代理類邏輯和代理接口這是共性
真實(shí)主題類和接口和上例一樣,不再貼了
JavaAssist 的動(dòng)態(tài)代理有兩種實(shí)現(xiàn)方法,一種使用代理工廠,一種使用動(dòng)態(tài) java 代碼生成字節(jié)碼
這里就直接貼代碼了:
圖片上傳失敗~~~
Ps: 以上實(shí)例方法在在邏輯處理類中處理類 , 真實(shí)主題類和接口和上面例子相同
代理工廠指定接口后生成代理類對(duì)象,代理類對(duì)象再指定處理邏輯。
大致三者都相似, javaAssist 動(dòng)態(tài) java 代碼生成字節(jié)碼就不介紹了,趕覺較麻煩
另有 ASM 動(dòng)態(tài)代理實(shí)現(xiàn)起來比較復(fù)雜,也不介紹。
本文永久更新鏈接地址:http://www.linuxidc.com/Linux/2015-08/122524.htm

10個(gè)實(shí)用的但偏執(zhí)的Java編程技術(shù)
Linux 下C語言編程庫文件處理與Makefile編寫
相關(guān)資訊
Java代理模式
對(duì)Java代理模式的理解 (今 10:30)
Java中的代理模式 (01月26日)
Java動(dòng)態(tài)代理模式(從現(xiàn)實(shí)生活角度 (12/22/2016 08:37:59)
Java設(shè)計(jì)模式之代理模式詳述 (09月15日)
Java代理模式之動(dòng)態(tài)代理 (01月02日)
Java靜態(tài)代理模式(從現(xiàn)實(shí)生活角度 (12/22/2016 08:29:12)
本文評(píng)論
查看全部評(píng)論 (0)
表情: 
姓名:
匿名
字?jǐn)?shù)
同意評(píng)論聲明
評(píng)論聲明
尊重網(wǎng)上道德,遵守中華人民共和國(guó)的各項(xiàng)有關(guān)法律法規(guī)
承擔(dān)一切因您的行為而直接或間接導(dǎo)致的民事或刑事法律責(zé)任
本站管理人員有權(quán)保留或刪除其管轄留言中的任意內(nèi)容
本站有權(quán)在網(wǎng)站內(nèi)轉(zhuǎn)載或引用您的評(píng)論
參與本評(píng)論即表明您已經(jīng)閱讀并接受上述條款
最新資訊
對(duì)Java代理模式的理解
pnp4nagios的安裝
MySQL的SQL_MODE
Oracle Linux 7.4 安裝 Oracle 12C
Jenkins服務(wù)器搭建指南-官方文檔翻譯整理
傳 Google 將提供取代兩階段認(rèn)證的「進(jìn)階防
Google Photos 可以讓網(wǎng)速慢的地方也能分享
微軟終于放棄自家音樂服務(wù),原 Groove
三星也加入 Windows MR 設(shè)備戰(zhàn)團(tuán)
微軟收購了 AltspaceVR 虛擬現(xiàn)實(shí)社交平臺(tái)