2014年6月28日 星期六

關於java,android,lucene開發的一些事....

以下是個人學習java的一些記錄,隨時會增減修改。

使用grouplayout,JSplitPane的比例亂掉

JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
splitPane_2.setRightComponent(tabbedPane);

paneT1 = new JScrollPane();
paneT2 = new JPanel();


tabbedPane.addTab("簡要", paneT1);
tabbedPane.addTab("全文", paneT2);
GridBagLayout gbl_paneT2 = new GridBagLayout();
gbl_paneT2.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0};
gbl_paneT2.rowHeights = new int[]{0, 0, 0};
gbl_paneT2.columnWeights = new double[]{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
gbl_paneT2.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
paneT2.setLayout(gbl_paneT2);

在JTabbedPane 中有兩個tab paneT1及pantT2, paneT1內只包含一個JScrollPane,內含JList, paneT2包含兩個JButton及一個含JScrollPane的JTextArea。paneT1因為只有一個JList所以沒有特別使用佈局(layout),而paneT2一開始先放一個JPanel,再考慮用grouplayout作佈局,可是不知怎麼的,一放上去以後,原來整個JSplitPane的比例就變的很tricky,整個比例都亂掉了,後來改用GridBagLayout才正常,原因...目前不知。。。


JScrollPane 為何用setViewportView,而不用add來加入物件

scrollPane_1.setViewportView(textArea_1);

Q:JscrollPane.setviewportview與JscrollPane.add之間的差異
當我們想要把展示的東西放在panel內,我們只需用add方法將其添加到panel,但我們為什麼不能添加一個table或textArea到ScrollPane中,而必須調用(呼叫)setviewportview的方法? 而不用add()方法呢?

A:基本上,你不應該使用JScrollPane#add 。

JScrollPane連接到一個JViewport ,JScrollPane用這個來顯示添加到view視圖中的任何組件(元件)(如textarea, table, list等)。
setViewportView是一個方便的方法,用來顯示滾動窗格(scrollpane)內容的一部分,它就像一個窗戶一樣,只能看到窗外世界的一部分,或像是照像機的觀景窗,所以add的方法,實際上在JScrollPane中並不代表任何意義。add只是單純將物件加入容器內。

rgZsh.gif

關於valueChanged執行兩次的情況


model = new DefaultTableModel(){
public boolean isCellEditable(int row, int column) {
return false;
}
};

lstModel = new DefaultListModel();
list = new JList(lstModel);

list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent arg0) {
if (arg0.getValueIsAdjusting()) {
// The mouse button has not yet been released
return;
}
int idx=list.getSelectedIndex();
ss.moveCaret(2,idx,textArea_1);
//arg0.getLastIndex();
}
});


getValueIsAdjusting在按下滑鼠時,即使未放開滑鼠就已經執行,當放開滑鼠時,還會再執行一次,所以會造成執行兩次的情況,增加下面這一段是為了避免執行兩次的狀況發生。
if (arg0.getValueIsAdjusting()) {
// The mouse button has not yet been released
return;
}


利用ArrayList來處理java不固定長度的陣列

如果一開始不能確定陣列要給多少長度,而是要跑完一段長長的作業,才能知道陣列長度。可用ArrayList來代替一般的陣列,如下用add的方法,隨時加入元素到ArrayList中,不必事先決定陣列的長度。非常方便。但是要注意加入的元素最好是int, long 等單純的型別,如果在ArrayList中放入陣列,要很小心。因為放入陣列到arraylist事實上是放入該陣列的位址。它真實的值是指向別的地方。有可能發生意想不到的情況。我曾經發生一次誤用的情況,但因當時未記錄,現在也無法回想當時的情況,只能提醒自己小心。


ArrayList bl = new ArrayList();
ArrayList el = new ArrayList();

int b,e;
Pattern pattern = Pattern.compile(str);
Matcher matcher = pattern.matcher(textString);

int count = 0;
while(matcher.find()) {
b=matcher.start();
e=matcher.end();
String s=textString.substring(b-50,100+e);
lst.addElement(s);
count++;
System.out.println("found: " + count + " : "
+ matcher.start() + " - " + matcher.end());
bl.add(b);
el.add(e);
}

/*for (ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.doc(scoreDoc.doc);
*/

hitCollects=new int[bl.size()][2];
maxHit=bl.size();
for(int i=0;i<bl.size();i++){
hitCollects[i][0]=(int)bl.get(i);
hitCollects[i][1]=(int)el.get(i);
}

curHit=0;
return hitCollects;



正則表達式 -group 用法


Pattern p = Pattern.compile("(.+)\\*$");
Matcher m = p.matcher(str);
if (m.find()) {
str=m.group(1)+"file:///D|/w*";
}

以上的效果,如果是 abc* 會換成 abc\\*
group是針對()來說的,group(0)就是指的整個串,group(1) 指的是第一個括號裡的東西,group(2)指的第二個括號裡的東西。 所以上例中group(1) => (.+) => 一個以上的任意字元


str=str.replace("*","file:///D|/w*");
str=str.replace("*","[\\w']*");
以上兩句的區別,第二句包含縮寫符號,匹配ca*t,可以找出can't,第一句不行

str=str.replace("?","file:///D|/w");
將通配字元,轉成正則表示式

正規表示式,如何不區分大小寫

Pattern pattern = Pattern.compile("file:///D|/b%22%2Bstr%2B%22/b");
Pattern pattern = Pattern.compile("file:///D|/b%22%2Bstr%2B%22/b%22%2CPattern.CASE_INSENSITIVE);

正規表示式-\b\B的意義

\b 指的是英文字與空格(不一定是空格,如換行,不是字母的符號等...)的間隙的那個位置,比對英文字的邊界,例如空格 例如 /\bn\w/ 可以比對 "noonday" 中的 'no' ;
/\wy\b/ 可比對 "possibly yesterday." 中的 'ly'

\B 比對非「英文字的邊界」 例如, /\w\Bn/ 可以比對 "noonday" 中的 'on' ,
另外 /y\B\w/ 可以比對 "possibly yesterday." 中的 'ye'

有無加"file:///D|/b"區別
加上的話,b*nd 會比對出 behind, blind,即使是句子的第一個英文字前無空白,仍能正確比對
若不加,b*nd 會比對出behind,blind,hidebrand


如何使用正則表示去除雙引號

Matcher matcher = pattern.matcher(textString);
Pattern p = Pattern.compile("^\\\"(.+)\\\"$");
Matcher m = p.matcher(str);

if (m.find()) {
str = m.group(1);
}



lucene 分詞器的選擇-StandardAnalyzer

關於stop word的問題
使用StandardAnalyzer分詞,會去掉stop word,如on the in a an等,使得像"on record"這樣的phrase search失敗,而只找到record的文件,造成搜尋結果比預期多,且不準確。
改用WhitespaceAnalyzer,也無法改善,且像"alan,"字尾緊跟著","號會找不到,用StandardAnalyze則無問題
SimpleAnalyzer "alan,"可找到,但"on record"還是找不到

解決方法:阻止StandardAnalyzer去除stop word
1)在建立索引時,使用如下命令建立StandardAnalyzer
Analyzer analyzer =
new StandardAnalyzer(Version.LUCENE_48, CharArraySet.EMPTY_SET);
IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_48, analyzer);

2)在搜尋建立QueryParser時,使用如下命令建立StandardAnalyzer
Analyzer analyzer =
new StandardAnalyzer(Version.LUCENE_48, CharArraySet.EMPTY_SET);
QueryParser parser =
new QueryParser(Version.LUCENE_48, where, analyzer);

關於縮寫字及連字符
StandardAnalyzer 找不到縮寫字 如can't , "single-handedly"加雙引號可以找到,不加則當成single handedly 2個字去找,找出很多.


移除java Jtextarea內所有的highlights

public static void removeHighlights(JTextArea textComp) {
Highlighter hilite = textComp.getHighlighter();
Highlighter.Highlight[] hilites = hilite.getHighlights();

for (int i = 0; i < hilites.length; i++) {
//if (hilites[i].getPainter() instanceof MyHighlightPainter) {
hilite.removeHighlight(hilites[i]);
//}
}
}


改變highlight的顏色

Highlighter.HighlightPainter greenPainter =
new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN);
Highlighter h = ta.getHighlighter();

h.addHighlight(hitCollects[curHit][0], hitCollects[curHit][1],
greenPainter);


正則表示式範例

abc\W+([A-Za-z]+\W+)*def
取abc至def間所有英文字的token

\b(\w+\W+){0,3}take(\W+\w+){0,3}\b
以take為中心向前或後最多取10組文數字的token,即使遇到換行符號,仍會往前或往後取,因此不限於只取一行文字
\W是分隔token的符號(除了文數字以外的字元,如空白,標點,換行等...)
\w是文數字及底線
以下為例:
abc def 7678
sdkd dir take much
cat doff place
會取出 7678 sdkd dir take much cat doff

如果用在一個長的文件中,有二個以上的結果,取過的部分,不會再取一次:

bb take cc dd ee take ff gg
\b(\w+\W+){0,2}take(\W+\w+){0,2}\b
第一次取出 [bb take cc dd]
第二次依規則前後最多取二組,應取出 [dd ee take ff gg]
但dd已經在第一次選取時取過了,因此第二次選取只會取出
[ee take ff gg]



coming with you...No.
00350 I need you here to take care of Arendelle.
00351 On my honor.
00352 I leave

表示次數的regex後面,不加或再加上?或+之不同:

光看這樣的說明是無法分出三者不同,以下舉例說明。
Greedy quantifiers
字串 "xfooxxxxxxfoo"
(不加) pattern ".*foo"
結果 xfooxxxxxxfoo
Greedy字面翻譯是貪婪,也就是盡可能的取字串,其實最貪婪的是第三種方法,因為Greedy還會把之後相符的資料留下來,Possessive吃的連骨頭都不剩。

Reluctant quantifiers
字串 "xfooxxxxxxfoo"
(加上?)pattern ".*?foo"
結果 xfoo 和 xxxxxxfoo
Reluctant字面翻譯是勉強,也就是抓最小可能,像這個例子,第一次抓一個x之後發現後面和foo相符,就得第一個結果,然後一直到最後又得到第二個結果。

Possessive quantifiers
字串 "xfooxxxxxxfoo"
(加上+)pattern ".*+foo"
結果 沒有相符合資料,因為所有的資料都與"."比較相符,最後沒有剩下的字串可以和foo做比較,所以沒有符合資料。


java 注意contructor 不必宣告傳回值

public class aaa{....
public aaa(){
}
}

上例中如果寫成public void aaa()會被視為一般函數


宣告建立ArrayList時,先指定型別

ArrayList
ArrayList<Integer> bl = new ArrayList<Integer>();

bl.add(1);
bl.add(2);
bl.add(3);

使用新的for語法
for (int a:bl){
System.out.println(a) //印出123
}

因前面宣告建立ArrayList時,先指定型別為int,則在取出資料時,就不用做型別轉換.如下例1),否刖就要先轉成int,如例2)
1) a = bl.get(i);
2) a = (int) bl.get(i);


netbeans 比對兩個檔案的技巧

先同時開啟兩個要比對的檔案,拖動其中一個檔案的頁籤,往右或往下,待出現方框時放開,則會將兩個檔案分別並排開啟。

getContentPane().invalidate(),getContentPane().validate()的使用

table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent event) {

....程式碼.....

getContentPane().invalidate();
getContentPane().validate();
}

getContentPane().invalidate();=>出錯,只能放在valueChanged的範圍內
getContentPane().validate();
});


繼承關係下的Constructor執行順序

先將所有變數設為內定值。對數值型態來說,其值為0; 對reference來說,其值為null; 對boolean來說,其值為false。
呼叫父類別的constructor。如果子類別Constructor裡沒有指定父類別的Constructor, 則使用父類別沒有參數的Constructor。
執行變數宣告的初始化動作。
執行自己的constructor。

netbeans好用的命令 右鍵->find usages 可跨檔案尋找,用find只能在一個檔案內找

ArrayList<String> strList = new ArrayList<String>();
strList.add("abc");
strList.add("def");
strList.add("ghi");
s="Def";

這種情況下用 int index=strList.indexOf(s) 無法找出正確資料,因無法忽略大小寫

必須改用手工去比對
int index = -1;
for (int i=0;i<strList.size();i++){
if (strList.get(i).equalsIgnoreCase(s)) {
index=i;
break;
}
}

String a="abc";
String b="abc";
a==b 不一定為真,因判斷的是a,b所參考的物件是否相同,並不是值是否相同
應該用a.equals(b)才是判斷值是否相同


使用字串相加 string a="a"+b";效率較差

----
最近看了一個面試題是這樣的:

char 是否能存儲一個中文字符,為什麼?

char類型一般佔用兩個字節,所以能存儲中文字符(一個中文字符佔用兩個字節)。

char a = '中' ;(合法) char a = 'ab' ;(非法的)

所以char類型在內存中佔用兩個字節空間,但是只能表示一個字符。若是只要表示一個字節的字符,可以考慮byte。

byte表示字節,佔用內存一個字節的空間。

byte a = 'a' ;(合法) byte a = '中' ;(非法的,不能存放中文字符)

另外:1 byte = 8 bit (bit就是0和1的一個位數,8bit表示一個字節)

String str = "中" ;

byte[] a = str.getBytes();

System.out.println(a.length); //打印出多長?

result:可能2,3,4.

原因是getBytes()方法會根據當前默認的字符編碼格式獲取字節數組,gbk/gb2312佔2位,utf-8佔3位,unicode佔4位(很多地方看見別人說是佔兩位,但是親測出來的結果是4,求解!)

可以str.getBytes("GBK"),str.getBytes("UTF-8")使用,指定了編碼格式,就不根據默認的取得了。
----
eclipse
'Launching android' has encountered a problem.

An internal error occurred during : "Launching android".

Clicking "details >>" produces an extra line:

Path for project must have only one segment

因為configuration未給名,run->run configurations,選擇一個configuration在project的地方給名字即可
--------
eclipse ctrl+h 可多檔搜尋文字
在logcat的某一項目的第一行,按ctrl+c可複製,如果在第二行就不行
--------

06-18 16:44:42.982: E/AndroidRuntime(3437): java.lang.RuntimeException:
Unable to start activity ComponentInfo{com.example.engandroid/com.example.engandroid.ItemListActivity}:
android.view.InflateException: Binary XML file line #24: Error inflating class fragment


错误信息:

android.view.InflateException: Binary XML file line #8: Error inflating class fragment

http://blog.csdn.net/duguang77/article/details/17579847

下面我总结下此错误出现的原因:

1.XML文件中引入的Fragment路径不对(如下图)

2.在Activity继承Fragment时引入的包名不对

关于什么时候引入android.app.Fragment和
android.support.v4.app.Fragment(向下相容3.0以下)

public class MainActivity extends Activity { // above 3.0
public class MainActivity extends FragmentActivity { // below 3.0


请参考我的另外一篇文章:

点击了解:【android fragment android.support.v4.app.Fragment与android.app.Fragment区别】

06-18 17:46:26.981: E/AndroidRuntime(4193): Caused by: java.lang.IllegalArgumentException:
Binary XML file line #24: Duplicate id 0x7f05003d, tag null, or parent id 0xffffffff with another fragment
for com.example.engandroid.ItemListFragment

The problem is that what you are trying to do shouldn't be done. You shouldn't be inflating fragments inside other fragments. From Android's documentation:

Note: You cannot inflate a layout into a fragment when that layout includes a <fragment>. Nested fragments are only supported when added to a fragment dynamically.

While you may be able to accomplish the task with the hacks presented here, I highly suggest you don't do it. Its impossible to be sure that these hacks will handle what each new Android OS does when you try to inflate a layout for a fragment containing another fragment.

The only Android-supported way to add a fragment to another fragment is via a transaction from the child fragment manager.

---------

<fragment
android:id="@+id/eng_list"
android:name="com.example.engsearcha.EngListFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="@android:layout/list_content" />

<FrameLayout
android:id="@+id/eng_detail_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3" />

以上佈局,如果 android:layout_width="0dp"不設為 0dp,會使得比例變得很不正常

----------
eclipse 使用ctrl+H作search時,如果是選擇?java search,file search,有時因從外部copy檔案進來,未sync會搜尋不到,此時會提示錯誤,從detail中可看到訊息
先在package explorer中refresh即可


setContentView(R.layout.activity_eng_list);中的R.layout.[activity_eng_list]和檔名[activity_eng_list].xml是同步的,用refactor->rename改其中一個地方,另一個也會跟著改
而 activity_eng_list.xml內有一段:
<fragment
android:id="@+id/eng_list"
android:name="com.example.engsearcha.EngListFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="@android:layout/list_content" />
會建立啟動com.example.engsearcha.EngListFragment這一個物件. 這是屬於靜態建立fragment.
----------

setListAdapter(new ArrayAdapter<DummyContent.DummyItem>(getActivity(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1, DummyContent.ITEMS));


android.R.layout.simple_list_item_1:一行text
android.R.layout.simple_list_item_2:一行text較大,一行text較小
android.R.layout.simple_list_item_single_choice:單選
android.R.layout.simple_list_item_multiple_choice:多選按鈕
android.R.layout.simple_list_item_checked:勾選盒
------------

static後面加大括號的含義
static { }
In the Java programming language, a block is a group of lines of code enclosed in curly braces. Blocks serve many purposes in Java--
for instance, control Java keywords such as "while" take a block as an argument. In particular, Java supports "static blocks."
A static block gets executed exactly once per class--rather than once per object created in the class, as would be the case for code
included in a constructor method. You can use static Java blocks to perform one-time tasks when the class in question gets loaded into
memory by the Java Virtual Machine.

static blocks只有在類別被載入時,執行一次,物件被建立時,不會執行
----------

Few days back I came to know about a different way of initializing collections and objects in Java. Although this method of initialization has been there in Java since quite a few years now, very few people actually knows about it or have used it in their code. The technique is called Double Brace Initialization technique in Java.

Let us see first how we will initialize an ArrayList in Java by "normal" way:
List<String> countries = new ArrayList<String>();
countries.add("Switzerland");
countries.add("France");
countries.add("Germany");
countries.add("Italy");
countries.add("India");

Above code snippet first creates an object of ArrayList type String and then add one by one countries in it.

Now check the Double Brace Initialization of the same code:
List<String> countries = new ArrayList<String>() {{
add("India");
add("Switzerland");
add("Italy");
add("France");
add("Germany");
}};


How does this works?

Well, the double brace ( {{ .. }} ) initialization in Java works this way. The first brace creates a new AnonymousInnerClass,
第一個大括號,宣告是一個內部的匿名類別
the second declares an instance initializer block that is run when the anonymous inner class is instantiated.
This type of initializer block is formally called an "instance initializer",
because it is declared withing the instance scope of the class
第二個大括號是一個"instance initializer",當物件被建立時執行(類似constructor)

- "static initializers" are a related concept where the keyword static is placed before the brace that starts the block,
and which is executed at the class level as soon as the classloader completes loading the class .
The initializer block can use any methods, fields and final variables available in the containing scope,
but one has to be wary of the fact that initializers are run before constructors.

If you have not understood the concept, try executing following code and it will make things clear for you.
public class Test {
public Test() {
System.out.println("Constructor called");
}
static {
System.out.println("Static block called");
}

{
System.out.println("Instance initializer called");
}

public static void main(String[] args) {
new Test();
new Test();
}
}
Output:
第一個new Text()執行時:
Static block called
Instance initializer called
Constructor called
第二個new Text()執行時:
Instance initializer called
Constructor called

執行的優先次序:static block->instance initializer->constructor
static block:類別載入時,只執行一次
Instance initializer:物件建立時執行.
Constructor:物件建立時執行

Instance initializer比Constructor好用之處
1)可以處理catch exceptions.
2)如果一個類別有多個constructor,每次可能執行不同的constructor,但是你希望每次都要執行一段程式碼,則你必需每一個constructo重覆寫一段相同的程式碼,執行同一件事,如果寫在Instance initializer裡,就只要寫一次就好.
3)用在內部匿名類別,因為內部匿名類別不能宣告constructor

----------

This seems to explain it well:

"Instance initializers are a useful alternative to instance variable initializers whenever:

initializer code must catch exceptions, or

perform fancy calculations that can't be expressed with an instance variable initializer. You could, of course, always write such code in constructors.

But in a class that had multiple constructors, you would have to repeat the code in each constructor. With an instance initializer,
you can just write the code once, and it will be executed no matter what constructor is used to create the object.
Instance initializers are also useful in anonymous inner classes, which can't declare any constructors at all."

  © Blogger templates Psi by Ourblogtemplates.com 2008

Back to TOP