2010年1月10日 星期日

[Java] 小心 substring 的 memory leak

這個內容並不是我自己發現的,剛好在 PTT 的 Java 版中看到某位高手所說得!其實,我是今天才知道有這回事!
簡單的來說,假設我們有一段程式碼:

public class SubstringMemoryLeak {
    
    private String str = new String(new byte[10000]);

    public String substring() {
        return this.str.substring(0, 2);
    }
    /**
     * @param args
     */
    public static void main(String[] args) {
        List<String> substringList = new ArrayList<String>(10000);
        for (int i=0, n=10000; i<n; i++) {
            substringList.add(new SubstringMemoryLeak().substring());
        }
    }

}

如果執行上面的程式碼,你就會出現 Exception:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.lang.StringCoding$StringDecoder.decode(StringCoding.java:133)
    at java.lang.StringCoding.decode(StringCoding.java:173)
    at java.lang.StringCoding.decode(StringCoding.java:185)
    at java.lang.String.(String.java:570)
    at java.lang.String.
(String.java:593)
    at silver8250.tools.SubstringMemoryLeak.
(SubstringMemoryLeak.java:8)
    at silver8250.tools.SubstringMemoryLeak.main(SubstringMemoryLeak.java:19)


但是如果將 substring() method 修改成:


public String substring() {
    return new String(this.str.substring(0, 2));
}
神奇的事情發生了!程式竟然可以如願的執行!問題出現在哪?上面的程式碼最主要是建立一堆很佔記憶體的 String 物件,然後取其中的一小段!重點就在於 String 的 substring() method 的實做方式。
首先,String 物件在記憶體中會以 char array 方式呈現,當我們每次建立一個 String 時,記憶體就會長出一塊 char array 來存放。String class 有一個 non-public constructor:

String (int offset, int count, char[] value)

當我們使用 substring 時,實際是用這個 constructor 來完成,也就是原先建立很佔記憶體的 String 物件並不會縮小,而是保持原來的 char array 所佔的大小。所以 Java 的 GC 就無法對此 char array 進行回收的動作。所以使用 substring() method 對字串內容來說,我們看到的是部份的,但是在記憶體中卻是佔有原先的大小!

後來,我們改用 new String() constructor 來包裝 substring 的內容,這就會讓 Java 重新建一個 char array 來放置 substring 的內容,相對的,所佔得記憶體就小了,而且原先較大的 char array 就沒有任何 reference ,所以 GC 就可以直接回收了!

老實說,這種情況可能不太常見,至少對我來說啦!我對於 String 的建立都會盡量改用 StringBuffer 物件,這樣不僅可以提供較好得效能,對於記憶體的利用也比較不會有問題!

與大家分享之~

2009年11月21日 星期六

[Eclipse] 好用的 Task List

哇~好久沒有寫文章了!最近實在太忙碌了!不過忙碌之中也發現一些好用的技巧可以提供工作的效率喔!這也許你已經知道了,但容許我在說一次!

正式開始工作後才發現,使用者需求如雪片般飛來,在加上手邊又有很多系統要弄,一堆事情夾雜在一起就會發現,修了這個系統卻忘了另一個系統要改哪些,導致工作效率就下降了~荷包就跟著縮水,年終相對減少,經濟壓力就變大....扯太多了!

有太多工作要作,我們可以用傳統的紙筆來紀錄,那...紙髒了、掉了、濕了、字看不清楚了...工作效率就下降了~...進入一種無窮迴圈!接下來提供的方法也許不是最好,不過對我來說卻很方便 - Task List,先說好以下的前提是:針對程式碼的部份~

當我們使用 Eclipse 編輯程式時,我們可以寫註解(廢話~),不過有一些註解對於 Eclipse 來說是有特別處理的,例如:TODO、FIXME 等。當我要開始修改或開發某些程式片段前,我都會先註記 TODO,也就 class 之前或 method 之前加上 //TODO ,當某個程式我現在沒時間思考問題點在哪,但是就是有問題時,我就會註記 //FIXME ,這樣的紀錄 Eclipse 可以幫我們整理出來 workspace 中所有 project 的註記,這樣我們就可以很快的回想自己的工作清單,從 Window -> Show View -> Others 來開啟 Tasks View,如右圖:


從 Tasks View 中我們可以看到一堆已經被註記的工作清單,如左圖。直接對 task 點兩下就可以直接開啟對應的程式碼片段,這樣我們就可以很容易的紀錄我們之前是作到哪了!

這工具對我來說挺不錯用的!尤其在工作越來越多的時候更是一個好得工作利器!與大家分享之~

2009年10月11日 星期日

[Struts2] Other UI Tags

在前兩篇的文章中,我們提到了許多的 UI tags,包含基本的Collection-based,在這裡我將一些比較不屬於前兩種,但是也是有用的 tags 加以介紹,這應該算是 bonus!以下將介紹三種 tags:1) Label tag、2) Hidden tag 與 3) Double Select tag。

1) Label Tag
Label tag 主要是用來顯示某項資料,並且讓顯示的結果與其他的 UI tags 有相同的格式,也就是以同樣的 theme 來顯示,雖然我們可使用 property tag 來幫助我們顯示,不過這樣就無法與其他 UI tags 使用相同的 theme 了!
在使用 Label tag 時,我們只需要設定 name 與 label attributes 就可以簡單的將 data 帶出!不過因為 Label tag 只是顯示資料,所以資料只會被帶出,不會被帶入!以下就是簡單的例子:
<s:label name="user.name" label="Your Name" />

由於 Label tag 的使用是非常簡單的,我們就不再多說了!

2) Hidden Tag
Hidden tag 的使用也很簡單,此 tag 最主要是希望將某些資料被 form 送出但不要讓使用者知道,在某些情況下是很好用的,例如我們希望使用者填寫 form 的時間不要超過 10 分鐘,我們可以使用 Hidden tag 來紀錄時間,當使用者送出該表單時,後端在將目前時間與 Hidden tag 所送來的時間進行判斷。
由於 Hidden tag 使用方式容易,以下就舉一個例子示範:
<s:hidden name="timestamp" />

3) Double Select Tag

Double Select Tag 算是一個很神奇的 UI tag,因為他提供了一種很特別的功能。讓我們想像一個情況,當我們在註冊某個網站時,我們應該常常會遇到要填寫住址,比較好得網站會給我們兩個下拉選單,一個選擇縣市,另一個則是顯示該縣市對應的鄉鎮市區!對於 programmers 來說,要達到這樣的功能,不外乎採用的是 Javascript 的技術,不過是 synchronize 或 asynchronize,我們都要依靠 Javascript 的幫助,但是有時候我們又不擅長撰寫 Javascript,所以 Double Select tag 就因應而生。
Double Select tag 提供了兩個下拉選單,第一個選擇後,第二個選單會根據第一個選單的選擇來產生第二個選單的內容,就如同我在上面所描述的情況一樣!對於 Double Select tag 來說,list, listKey 與 listValue attributes 就相同於 Select tag 的使用,只是 Double Select tag 多了以下的一些 attributes:




























AttributeTypeDescription
doubleNameString儲存第二個下拉選單的選擇值
doubleListCollection-based第二個下拉選單
doubleListKeyString第二個下拉選單所產生 option 的 key
doubleListValueString第二個下拉選單所產生 option 的顯示

除了原先在 Select tag 中我們就使用過得 list, listKey 與 listValue 之外,所有想要設定 Double Select tag 的第二個下拉選單,attributes 的開頭都是以 double 為首。上面中比較重要的是 doubleName attribute,因為他是必填的選項,doubleName attribute 的目的在於儲存使用者選擇第二個下拉選單的內容,就如同 name attribute 是儲存第一個下拉選單的結果一樣。
那我們要如何讓第二個下拉選單可以動態呢?有兩種方法,第一種是將第二個下拉選單,透過 OGNL 方式寫在 double select tag 中:
<s:doubleSelect name="first"
list="beanList"
listKey="beanId" listValue="beanValue"

doubleName="second"
doubleList="%{top.beanId==1?{'1.1','1.2'}:{'2.1','2.2'}}"
/>
這種方式就必須將第二個下拉選單的內容寫死在頁面上,如果我們需要增加不同的內容,就會顯得礙手礙腳!除非內容很單純,也不會有太多的變化,否則我是不太建議使用這樣的方式來作。第二種方式就顯得有彈性了,我們將第二個下拉選單到 Action 中取得,剩下的就交由 Struts2 framework 幫我們用 javascript 來自動切換:
<s:doubleSelect name="first"
list="beanList"
listKey="beanId" listValue="beanValue"

doubleName="second"
doubleList="nextList(top.beanId)"
doubleListKey="nextId"
doubleListValue="nextValue"
/>
這種方式就代表我們的 Action 中有一個 nextList() method,接受 beanId 的資料型態。也就是如果 beanId 是一個 String,則此 method 就會是 nextList(String next)。當然,我們在這裡回傳的第二個下拉選單內容是以一個 List 來包裝一堆的 JavaBean。透過 nextList,我們可以根據不同的 parameter 內容來回應不一樣的下拉選單內容,達到動態的效果。
如果你仔細觀察就會發現,double select 看似有 AJAX 的動態取內容的效果,其實卻不然,當 double select tag 被執行時,framework 會先迭代 list (也就是第一個下拉選單的內容),並且逐一取得所有的第二個下拉選單內容,再將這些內容組織到 javascript 中!也就是如果第一個下拉選單中有 10 個項目,那我們的 nextList() method 就會先被呼叫 10 次!
另外,讓我們回到上面的範例中,你應該有發現 OGNL 中的 top 關鍵字吧!這是用來儲存第一個下拉選單所選到的物件,就如同我們的範例,我們每一個物件都是一個 JavaBean,所以我們就可以用 OGNL 的特性,將 bean 中的 property 傳遞給 nextList() method!

在這裡我介紹了三個很特殊,但不一定常用到的 tags,Struts2 framework 提供了很多種神奇的 tags,讓 programmer 可以很容易的撰寫出複雜的表單畫面,不過關方網站的說明實在是很少,所以要使用這些 tags 的代價就是必須自己先 survey 過!

P.S. 這篇內容原本要在 8/11 完成,沒想要拖了整整 2 個月,中間歷經了當兵,現在又忙於工作,閒暇之餘趕緊完成~希望大家多多指教~

2009年7月29日 星期三

[Struts2] Collection-based UI Tags

除了之前比較簡單的 UI tags 之外,Struts2 framework 當然也會提供一些比較複雜的 tags,不然就無法符合使用者的需求了!在這裡我們將會介紹三種以 Collection 為基礎的 UI tags:1) select tag、2) radio tag 與 3) checkbox list tag。

這裡所謂的 Collection-based 就是在 Java 端的 property 是以 Collection 為主,如 List、Map 等,而這些 property 要如何在頁面上顯示,就是這裡的重點了!同樣的,在這裡我只會介紹每個 tag 特殊的 attributes,而共用的 attributes 就請參考 Simple UI Tags 的共同 attributes。

1) Select Tag
Select Tag 對於 Collection-based UI Tags 來說,應該是最常使用到的 tag!因為下拉式選單是最常見到的顯示方式,下面是最簡單的範例:
<s:select name="user.name" list="{'Silver','Brian','Mike'}" />

我們使用到 OGNL 的 List 型態,並且由 OGNL 幫我們快速建立。name attribute 就是該選單選到的值要被儲存到的目標 property,而 list 則是我們要顯示在頁面的 Collection-based 物件。以下就是 select tag 的 attributes:
















































AttributeTypeDescription
listCollection-based type, List, Map, Array or Iterator用來產生 select tag 的 option list
listKeyString根據 list attribute 中,指定 property 用來產生 option tag 的 key
listValueString根據 list attribute 中,指定 property 用來產生 option tag 的 value
headerKeyString類似於 listKey,產生在 Collection 之前
headerValueString類似於 listValue,產生在 Collection 之前
emptyOptionBoolean指定是否自動產生空的 option 在 header 之前
multipleBoolean是否可以多重選擇
sizeInteger指定一次顯示的筆數,會有 scroll bar 輔助多餘的 option


上述的 attributes 中,比較需要注意的是 list, listKey 與 listValue 這三個,list 是用來設定我們要顯示的 Collection-based property,在這裡要注意的是 list attribute 的型態只能接受 Collection, Array, List, Map 與 Iterator,如果型態不對就會出現錯誤!另外,listKey 則是根據 list 中所存放物件的某個 property,例如:
private List<UserBean> userList;

userList 中存放了一堆的 UserBean 物件,每個 UserBean 物件都有 name 與 age 的 property,那我們的 select tag 撰寫成:
<s:select list="userList" listKey="age" listValue="name" />

就是指定每一個 select 之下的 option 都會以 UserBean 物件中的 age 作為 key (也就是作為 option tag 中的 value attribute),而 name property 則為 option 顯示的內容。也就會變成如下:
<select>

<option value="10">Silver</option>
<option value="24">Su</option>
<option value="50">Jason</option>

</select>

從上面的結果我們也可以知道,我們的 userList 中存有三個 UserBean 物件。

而比較特別的是 headerKey 與 headerValue 這兩個 attributes,就目前為止我也搞不清楚這兩個 attributes 有什麼特別的用處,如果我們指定的 list 物件中需要增加一項資料,但我們不想動到 list 物件,那我們可以使用 headerKey 與 headerValue 來增加一項 option。而 emptyOption attribute 則是指定我們是否需要 Struts2 framework 幫我們自動產生一個空白的 option。size attribute 則是用來指定一次顯示的數量,如果我們不指定就會是一次顯示一項,這樣會比較像是下拉式選單,如果顯示數量大於 1 又小於 list 的總數量,則會多了上下的 scroll bar 幫助我們選擇。

這幾個 attribute 中比較有趣的是 multiple,以往的下拉式選單都是多選一,如果我們指定 multiply="true",選單就可以呈現多選,在不指定 size attribute 之下,多選的選單就會將整個 list 展開。如果我們採用多選的選單,選單送出的 property (也就是 name attribute 所只到的 property) 必須是一個 Collection-based property,這點應該很直觀,既然可以多選,就表示我們需要用 Collection-based 物件來接收,否則就失去多選的意義了!

2) Radio Tag
使用 radio tag 就如同使用 select tag 一樣,只是少了許多 attributes 可以使用罷了:























AttributeTypeDescription
listCollection-based type, List, Map, Array or Iterator用來產生 select tag 的 option list
listKeyString根據 list attribute 中,指定 property 用來產生 radio 的 key
listValueString根據 list attribute 中,指定 property 用來產生 radio 的 value


由於使用的方式大同小異,所以我就不舉例了!而要注意的是,radio tag 一定是單選,所以 name attribute 指到的 property 可以是 primitive type 或 Collection-based type。

3) Checkbox List Tag
使用 checkboxlist tag 跟 select 也是類似,只是要注意的是,不要將 checkbox 與 checkboxlist 搞混了!checkbox 是單選,checkboxlist 是多選!而 checkboxlist 提供的 attributes 有:























AttributeTypeDescription
listCollection-based type, List, Map, Array or Iterator用來產生 select tag 的 option list
listKeyString根據 list attribute 中,指定 property 用來產生 checkbox 的 key
listValueString根據 list attribute 中,指定 property 用來產生 checkbox 的 value


不過在這裡要注意的是,因為 checkboxlist 一定是多選,所以 name attribute 指到的 property 一定是要 Collection-based type。

最後我想探討的是如何將 list 的選項初始化,由於 name attribute 是指定該元件在表單送出後的目的地,如果我們要讓某個 select tag 中的 option 被預先選起來,我們就要在相對應的 property 事先給予值,例如我們有一個 select tag 如下:
<s:select name="myFavorite" list="favoriteList"
listKey="key" listValue="value" />
這個 select tag 的目的地是 myFavorite property,如果我們希望 list 中某個 option 先被選起來,我們就將 favoriteList 物件中的該項目的 key 填入 myFavorite property,這樣 Struts2 framework 就會幫我們選起該 option 了!總之記得,資料怎麼來就怎麼去!

2009年7月16日 星期四

[Struts2] Simple UI Tags

之前我們介紹了一些 tags,主要都是輔助 programmers 完成頁面上資料的存取,在這裡我將開始描述關於顯示在頁面上與使用者互動的表單 (form)。不過,我先簡介一些共同有的 attributes,因為這些 attributes 如果在介紹 tag 時重複敘述,感覺過於累贅!

共同 attributes

共同的 attributes 就是所有的 tags 都會擁有的,為了之後將重點放在各個 tags 上,我們就將這些 attributes 分開來介紹,這裡要注意的是,如果某個 attribute 的 type 屬於 String,那就表示該 attribute 的 value 只能接受字串,如果想要將 OGNL expression language 寫入,就必須在 expression 加上 %{} 符號 - %{ expression } - 這樣 Struts2 framework 就可以正確解析 OGNL 了!如果該 type 屬於 Object,那你就可以大方的將 OGNL expression 置入,無須加上 %{} 符號了!

































































AttributeTypeDescription
nameString用來設定 form 元件,並且會依照 name 所設定的值,將其對應到 Action 中的 property
valueObject用來設定 form 元件中所包含的值
keyStringi18n 用
labelString設定某個 form 元件顯示的字串
labelpositionString設定 label 顯示的位置:left 或 top
requiredBoolean如果設定為 true,則該 form 元件的 label 會出現 * 符號
idString相同於 HTML 的 id 屬性,通常用於 java script 與 CSS
cssClassString相同於 HTML 的 css 屬性
cssStyleString相同於 HTML 的 style 屬性
disabledBoolean相同於 HTML 的 disabled 屬性
tabindexString相同於 HTML 的 tabindex 屬性


Simple UI tags


上面描述的是共同的 attribute,以下將介紹一些 UI 相關並基礎的 tags,對於共同的 attribute 就不會重複提及。

1) Head Tag
對於任何的 HTML 或 JSP 來說,要產生一個網頁通常都是以 <head> 開頭,對於 Struts2 提供的 <head> 來說,卻不同於一般的 HTML head tag,如果你試過 Struts2 提供的 head tag,你應該會發現,tag 本身並不作任何事情,而是在網頁中默默的幫我們加入一些檔案連結,這些檔案的連結目的在於支援其他的 tag 完成設定。在使用 Struts2 提供的 head tag 時,一定要放置於 HTML 的 head tag 之下,否則自動產生的檔案連結會放到不正確的位置而導致無法使用某些功能!
Struts 的 head tag 本身並沒有其他的 attribute 需要設定,我們可以簡單的使用:

<s:head />

這樣的撰寫就會自動幫我們產生一些檔案的連結。

2) Form Tag
Form tag 對於 UI 來說是最重要的 tag,因為他是所有 UI tag 的上層元件,如果對於 HTML 熟悉的話,form tag 的使用應該不會陌生,而且我們之前就看過蠻多的範例了!下表是一些 form tag 的 attributes (除了共同 attributes 之外):









































AttributeTypeDescription
actionString指定該 form 送出的目標 Action
namespaceString目標 Action 的 namespace,預設值是目前的 namespace
methodString相同於 HTML 的 method attribute,預設值是 POST
targetString相同於 HTML 的 target attribute
enctypeString若要使用檔案上傳,則填入 multipart/form-data
validateBoolean設定該 form 是否使用 javascript 驗證,當使用 Validation Framework 時,此 attribute 要設定為 true,驗證功能才能正常運作

在上述眾多 attributes 中,最重要的莫過於 action 了!因為他主導整個 form 的目標 action,在這裡設定 action attribute 時要注意,我們無須填入 .action 的縮寫,因為 form 元件會幫我們完成,如果目標的 action 與現在是相同的 namespace,我們就無須填寫 namespace,否則我們就需要 namespace attribute 幫助我們找到 Action。每當 form 元件被執行時會有以下三種可能發生的狀況:
  1. 如果 action attribute 沒有被設定,則 form 的目標就會指向目前的 Action
  2. 如果有指定 action attribute,form 就會根據 Action 的位置配合上 namespace 來設定目標。如果 namespace 沒有被指定,就會使用目前的 namespace。當我們在設定 action attribute 時,我們無須加上 .action 的延伸網址
  3. 如果 action attribute 所指定的值不屬於一個 Action,form 元件的目標就會直接將該值作為目標。這種情況下,我們就需要自己加上延伸網址 (如:.jsp, .html 等),並且我們的相對位址需要以 / 作為開頭,例如:/myApp/b.jsp。另外要注意的是,如果我們採用此種方法,即使我們指定 namespace attribute,form 元件也會自動忽略!
3) Textfield Tag
這個 tag 對於你來說也是無可避免的!因為沒有此 tag,你就無法取得使用者的資料,所以這個 tag 也算是最常使用的!不過要注意的是 textfield tag 的 name 與 value attribute,一般來說,我們無需要指定 value attribute,因為我們只需要指定 name attribute 讓 OGNL 幫我們去 ActionContext 中取得對應的值來填入,當然,我們也可以填寫 value attribute,但是要注意的是,如果我們自己有填寫 value attribute,那 name 指定的 OGNL 所取到的值就不會顯示在 textfield tag 上了,這點要注意喔!以下是一些 textfield tag 的 attributes:


























AttributeTypeDescription
maxlengthString指定 textfield 的可輸入最大長度
readonlyBoolean如果設定為 true,則該 textfield 就無法輸入字串
sizeStringtextfield 的長度

4) Password Tag
這個 tag 跟 textfield 幾乎是一樣的,不過當使用者輸入字串時,所有的文字都會被包裝成其他的符號,以防資料外洩!這個 tag 的使用其實跟 textfield 是相同的,所以我就不多說了!以下是 password tag 的 attributes:































AttributeTypeDescription
maxlengthString指定 textfield 的可輸入最大長度
readonlyBoolean如果設定為 true,則該 textfield 就無法輸入字串
sizeStringtextfield 的長度
showPasswordBololean使否將 OGNL 取到的值顯示在 value 中,預設 false

上面列出的 attributes 中,幾乎跟 textfield 是一樣的,不過多了一個 showPassword attribute,這個 attribute 是讓我們設定是否要將 name attribute 中指定的 OGNL 取到的值顯示,在這裡我所謂的顯示不是大剌剌的用文字方式顯示,當然是有被遮蔽的顯示,不過從原始碼中還是可以看到原來的值,所以 showPassword attribute 預設值為 false,為的就是不要產生一些 security issues 來困擾 programmers,在這裡我也建議你不要將此 attribute 設定為 true!

5) Textarea Tag
同樣的,textarea 從開發角度上來說,與 textfield 並沒有太大的差別,主要就是提供使用者多行的輸入欄位!以下就是一些 textarea tag 的 attributes:































AttributeTypeDescription
colsInteger指定 textarea 的行數
rowsInteger指定 textarea 的列數
readonlyBoolean如果設定為 true,則該 textarea 就無法輸入字串
wrapString相同於 HTML 的 wrap attribute

6) Checkbox Tag
這裡的 checkbox 元件如果你認為跟 HTML 的 checkbox 一樣的話,那你就錯了!因為在 Struts2 提供的 checkbox 元件是一個單一 HTML 的 checkbox,這是什麼意思呢?一般的 HTML checkbox 提供了多個選項讓使用者選擇零或多個,但是這裡的 checkbox 只提供使用者一個選項,也就是選或不選。所以這個 checkbox 不同於 HTML 的 checkbox。這個 checkbox 只提供 Boolean 的功能,也就是說其對應的 property 一定要是一個 boolean property,如果要像 HTML 提供的 checkbox 有相同功能的話,要改使用 checkboxlist tag,現在不會提到!
以下是 checkbox tag 的 attribute:





















AttributeTypeDescription
fieldValueString這裡所填寫的 value 是真正會被傳送到 Action 中的值,主要是 true 或 false,預設值為 true
valueString這裡是用來判斷此 checkbox 是否會被勾選

看到上面的 attribute 你一定會感到很奇怪,value attribute 已經是共同的 attribute 了,為何在這裡還會在重新點出呢?原因就在於 checkbox 元件還有一個 fieldValue 這會與 value attribute 搞混!所以在這裡要特別點名。
fieldValue attribute 中的值代表當此 form 被送出後,fieldValue 中填寫的值會真正被送到 Action 中對應的 property,而 value attribute 只是用來判斷此 checkbox 是否需要被勾選。當 OGNL 取得 ValueStack 中的值,會將此值寫入 value attribute 中 (任何一個元件都是這樣),使用者可以看到此 checkbox 是否有被選起來。所以 fieldValue 與 value attribute 之間不要弄混了!
另外,checkbox 所指定的 name attribute,其對應到的 property 需要是一個 boolean 型態,否則會無法運作!

在這裡列出了六種簡單的 UI tag 給你參考,這裡列出的都是針對單一的 property,之後我將介紹關於 Collection-based 相關的 UI tags。