2013年7月30日 星期二

Java NIO - Buffer基本function介紹flip()、rewind()、clear()、compact()、mark()、reset()


參考:Java NIO Buffer
搭配此範例圖參考:

Write data to a Buffer:
  1. Write data from a Channel into a Buffer:
    int bytesRead = inChannel.read(buf); //read into buffer.
  2. 自行使用put()之類的方式寫入
    buf.put(127);
Reading data from a Buffer:
  1. Read data from the buffer into a channel.
     
    //read from buffer into channel.
    int bytesWritten = inChannel.write(buf);
    
  2. 自行使用get()之類的方式讀取:
     
    byte aByte = buf.get();
    
  • flip()
    將Butter由write mode轉變為read moode,並將
    (1)limit設為當前position位置
    (2)position reset to 0
  • rewind()
    將position設定回0,但limit保持不變,因此可重新read所有的資料

  • clear()與compact():
  • clear()
    將position設定回0,limit設定至capacity,然而Buffer中資料並不是真的被清除,只是將這些mark改變,讓我們可以有足夠的空間重新寫入資料。但是請注意,雖然資料沒有被清除,但是因為mark被重置了,因此unread的資料將無法再次被讀取,若目前尚有未讀取資料但又需要在讀取之前write data,則可使用compact()代替clear()
  • compact()

  • mark()與reset():
  • mark():使用mark()則可將目前的position做標記(mark)
  • reset():將position 設定回之前所設定的標記(mark)處
buffer.mark();
//call buffer.get() a couple of times, e.g. during parsing.
buffer.reset();  //set position back to mark.

equals()與compareTo():


  • equals():滿足以下條件則2個buffer代表equals
    (1)type相同(char、byte、int etc..)
    (2)剩餘的【未讀】buffer大小(byte)相同,
    (3)剩餘的【未讀】buffer內容皆相同
    如上所述,equals()只比較剩餘【未讀】的buffer內容,並非整個buffer的內容
  • compareTo():與equals()相同,只比較剩餘的【未讀】buffer內容,通常做為排序使用;符合以下的情況代表【smaller】:
    (1)
    (2)所有的內容皆相同,但擁有較少的內容(?)

2013年7月27日 星期六

Java NIO - ByteBuffer基本屬性介紹 capacity、limit、position


參考:Java NIO Buffer

Once you need to read the data, you need to switch the buffer from writing mode into reading mode using the flip() method call

Once you have read all the data, you need to clear the buffer, to make it ready for writing again. You can do this in two ways: By calling  or by calling compact().

  1. clear() :clears the whole buffer
  2. compact():only clears the data which you have already read. Any unread data is moved to the beginning of the buffer, and data will now be written into the buffer after the unread data.
ByteBuffer實際上操作方式為:先write再read

三個ByteBuffer屬性(可參考下面的圖來理解):
The meaning of position and limit depends on whether the Buffer is in read or write mode. Capacity always means the same, no matter the buffer mode.




  1. capacity
    代表ByteBuffer的容量大小,一但滿了除非將他清空或是read,不然無法繼續寫入資料
  2. position
    1. write mode:起始時position index為0,隨者每一次寫入資料position位置都會變動,如寫了1byte則postion會index+1,index最多不能超過capacity -1
              read mode:當使用flip()將操作模式由write改為read,position會自動被reset至0,然               後隨者每一次read資料量不同position位置將會自動前進
  1. limit
  2.          write mode:代表共可寫入多少資料量,在此模式中香等於capacity      
             read mode:代表共有多少資料量可讀取,當使用flip()將操作模式由write改為read,
             limit會被設置於position的目前所在位置
建立一個ByteBuffer使用allocate:
ByteBuffer buf = ByteBuffer.allocate(48);
其中的int參數就是代表欲建立的capacity大小。


相關function使用方式待續....

2013年7月20日 星期六

Java IO: Exception Handling - 不安全的IO Exception處理(2) - 使用try-with-resources

參考:Try-with-resources in Java 7  、 try-with-resources

請注意這個機制只有java 7後才適用

繼上篇,我們這次來看看java7的新機制(同樣是參考文章後的心得形式,若需詳細請直接連入上方參考文章連結)。


先假設下面的code:
 

public class TryWithResource implements AutoCloseable {

 private FileInputStream _input;

 public void doIt() throws WrapperException, FileNotFoundException {
  _input = new FileInputStream("datasheet/file.txt");
  throw new WrapperException("doIt has an Exception!!!");
 }

 @Override
 public void close() throws IOException, WrapperException {
  _input.close();
  throw new WrapperException("close has an Exception!!!");
 }
 }

以下列方式呼叫使用:
 
 public static void withoutTryWithResources() throws WrapperException {
  TryWithResource tt = new TryWithResource();
  try {
   tt.doIt();
  } catch (Exception ex) {
   throw new WrapperException(ex);
  } finally {
   try {
    tt.close();
   } catch (IOException e) {
    throw new WrapperException(e);
   }
  }
 }
 public static void main(String[] args) {
  try {
   withoutTryWithResources();
  } catch (WrapperException wex) {
   wex.printStackTrace();
  }
 }

會有以下結果:
Exception in thread "main" java.lang.IndexOutOfBoundsException
exception.WrapperException: close has an Exception!!!
 at exception.failsave.TryWithResource.close(TryWithResource.java:12)
 at exception.failsave.TryWithResource.withoutTryWithResources(TryWithResource.java:32)
 at exception.failsave.TryWithResource.main(TryWithResource.java:49)

(上述的exception 行號每人都會不一樣)
執行流程如下:

  1. doIt()
  2. throw new WrapperException("doIt...")
  3. first catch(Exception ex) block
  4. finally block
  5. close()
  6. throw new WrapperException("close...")

最始祖的exception為應該為doIt()中出現的,但如同前一篇所說,始祖exception會被吃掉,因此,到了步驟6原先的始祖exception(步驟2)就消失了,這造成我們難以在第一時間發現最根本的問題點,因此我們可以使用java7的新機制,修改如下:

 
 public static void withResources() throws WrapperException {
  try (TryWithResource tt = new TryWithResource()) {
   tt.doIt();
  } catch (Exception e) {
   throw new WrapperException(e);
  }
 }

 public static void main(String[] args) {
  try {
//   withoutTryWithResources();
   withResources();
  } catch (WrapperException wex) {
   wex.printStackTrace();
  }
 }

而這次的exception 顯示為:
exception.WrapperException: exception.WrapperException: doIt has an Exception!!!
 at exception.failsave.TryWithResource.withResources(TryWithResource.java:43)
 at exception.failsave.TryWithResource.main(TryWithResource.java:50)
Caused by: exception.WrapperException: doIt has an Exception!!!
 at exception.failsave.TryWithResource.doIt(TryWithResource.java:15)
 at exception.failsave.TryWithResource.withResources(TryWithResource.java:41)
 ... 1 more
 Suppressed: exception.WrapperException: close has an Exception!!!
  at exception.failsave.TryWithResource.close(TryWithResource.java:21)
  at exception.failsave.TryWithResource.withResources(TryWithResource.java:42)
  ... 1 more

(再一次提醒,exception中的行號每人不同)
上述流程為:
  1. doIt()
  2. throw new WrapperException("doIt...")
  3. immediately call close() 
  4. close()
  5. Suppressed:throw new WrapperException("close...")  
  6. throw WrapperException("doIt...") (step 2)

不僅少了很多恐怖的try catch跟finally還很清楚地馬上就知道始祖exception問題處。
注意其中的Suppressed: exception.WrapperException: close has an Exception!!!(步驟5)
由於使用了try-with-resources機制,因此後面發生在close()中的exception就會被suppress(壓制)。

而try-with-resources機制也可以同時使用多個:
 
private static void printFileJava7() throws IOException {

    try(  FileInputStream     input         = new FileInputStream("file.txt");
          BufferedInputStream bufferedInput = new BufferedInputStream(input)
    ) {

        int data = bufferedInput.read();
        while(data != -1){
            System.out.print((char) data);
    data = bufferedInput.read();
        }
    }
}

如果發生了問題,則destructor (就是呼叫close())的順序為反向的:

  1. bufferedInput.close()
  2. input.close()

另外還有一個限制,使用在try-with-resources都必須在try(...)中宣告,而不能使用下列方式:
 
private static void printFileJava7() throws IOException {
   FileInputStream     input = null;
   BufferedInputStream bufferedInput = null;
    try(  input         = new FileInputStream("file.txt");
          bufferedInput = new BufferedInputStream(input)
    ) {

        int data = bufferedInput.read();
        while(data != -1){
            System.out.print((char) data);
    data = bufferedInput.read();
        }
    }
}


因此只要implement AutoCloseable 這個interface,除了原生java的class以外,自己實作的class也同樣可以享受try-with-resources 的好處呢!

以後解決這種惱人的io問題總算有解了!!exception handling真是個很重要的課題阿!!該去買文章作者的kindle電子書了Java Exception Handling
話說好便宜阿作者真是佛心來者...

Java IO: Exception Handling - 不安全的IO Exception處理

參考:Fail Safe Exception Handling

其實這篇等於是把參考文章直接以自己說法再寫一次當作心得筆記,想看詳細的話看上述參考文章比較妥當


處理IO時常常發生個惱人的問題,假設下列code:
 
public class WrapperException extends Exception {

 public WrapperException(IOException e) {
  super(e);
 }
}

 
InputStream input = null;

  try{

    input = new FileInputStream("myFile.txt");

    //do something with the stream

  } catch(IOException e){
    throw new WrapperException(e);
  } finally {
    try{
     input.close();
    } catch(IOException e){
       throw new WrapperException(e);
    }
  }

假設"myFile.txt"這個檔案並不存在,那麼上述Code執行如下:

  1. throw java.io.FileNotFoundException() (at FileInputStream() constructor)
  2. catch(IOException e) block,rethrow WrapperException
  3. finally block
  4. 由於input未初始化成功,因此再次被finally中的try catch捕捉,然而這次拋出的為NullPointerException
因此上述的exception顯示如下:

Exception in thread "main" java.lang.NullPointerException
 at exception.FailSaveException.failSave(FailSaveException.java:30)
 at exception.FailSaveException.main(FailSaveException.java:15)

原先造成exception的始祖,最該被拋出的FileNotFoundException()就這樣默默的被吃掉了....
解決方式是:在finally的input.clode中加入null check:
if(input != null) 
   input.close();

然而讓我們假設另一個情況:
  假設檔案存在,input順利被建立,但在try catch中處理內容時因為某些原因再度造成io exception,此時順序會變為:

  1. throw some IOException in first try catch block
  2. first try catch catch it ,rethrow WrapperException
  3. finally block
  4. rethrow WrapperException again.....if input.close() also error
然而要是執行到步驟3時,input.close()又再次因為某些不知明原因,再度throw IOException,則就會多了步驟4,再一次的,最關鍵的始祖IOException又被吃掉(步驟1)!!
(上述假設無example code,推測是因為很難馬上弄出個簡單的input.close()也出問題的範例)
而為了解決上述問題,讓我們這些苦命developer可以在第一時間就發現始祖exception,Java 7帶來了一個叫 try-with resource的機制。

詳情請見下篇介紹XD

2013年7月19日 星期五

hsqldb - 如何擴展沒有的FUNCTION以適應其他sql ?

參考:src_jrt_routines

寫Test的時候遇到一個問題,我想在我的SQL Query中使用 LEN()這個mssql function:

 
  SELECT LEN(str) FROM TABLE where name='123'

然而由於寫Test時使用的並非mssql而是使用hsqldb,hsqldb並不支援LEN(),
而是使用LENGTH(),如果將我的SQL Query改為 LENGTH(),在正式上線時又會遇到
MS-SQL並沒有LENGTH()的問題....因此該怎麼做比較好呢??

原來hsqldb有擴展function的機制,就是為了預防這個問題的產生:

  1. create一個擴展的java class如下(注意function一定得為static,詳細使用對應的參數型別請參考上述參考頁):
  2.  
    package util.extend.mssql;
    
    public class MSSql {
     public static int len(String str) {
      return str.length();
     }
    }
    
  3. 並於實際執行有用到LEN的SQL Query的地方之前,使用下列SQL Query
     
          CREATE FUNCTION  len(str VARCHAR(20000))
            RETURNS INT 
     LANGUAGE JAVA DETERMINISTIC NO SQL
     EXTERNAL NAME 'CLASSPATH:util.extend.mssql.MSSql.len'
    

  4. 以上若完成,執行test,應該就能成功囉
這機制真是太方便了!!!

p.s話說回來完全找不到相關的中文討論阿....是說寫Test的人真的很少還是高手都直接找英文了呢....0rz...網路上查到的方式Create alias也是過時的方式,害我花了不少時間找...

2013年7月14日 星期日

android - layout (暫時存放)

[Android]Android Layout元件

[Android] layout_weight的妙用-讓View的大小以百分比率顯示(proportionate size)

mssql - 刪除或編輯現有資料時出現 "沒有刪除任何資料列。 嘗試刪除資料列3時發生問題....."


參考:資料重複無法修改或刪除
今天使用ms-sql時遇到個問題,刪除某些現有的資料列與編輯,都會出現下列錯誤:

沒有刪除任何資料列。
嘗試刪除資料列3時發生問題。
錯誤來源:Microsoft VisualStudio.DataTools。
錯誤訊息:已更新或刪除的資料列值不會使資料列成為唯一,而是會修改多個資料列(2個資料列)。

解答是:應該要設定PK,這樣在編輯/刪除全部相同的資料列時,資料庫才不會因為無法識別修改而產生錯誤