3/27/2014
4:11:00 PM 0

JavaScript this 用法

JavaScript 是個 prototype based 的語言,有些觀念與物件導向不太相同,this 的用法就是其中一例,在 JavaScript 中, this 代表指向呼叫該函式的物件, 也就是函數的擁有者,而且在程式執行過程中 this 不可被重新指派
  1. global context 中的 this
  2. global context 中的 this 指向 global object, 若在瀏覽器中執行 this 指向 window 物件
    console.log(this === window);//true
    
  3. 一般函式中的 this
  4. 當我們使用 function func1(){} 的方式宣告函數時, 函數的擁有者是 global object, 所以 this 指向 global object
    function func1() { return this; }
    var obj = { func1 : func1 };//建立物件與函式的連結
    obj.func1 === this.func1;//true
    obj.func1() === obj;//函式內的 this 指向呼叫該函式的物件
    func1() === this;//指向 global object
    func1() === window;//true
    
  5. 巢狀函式(nested function) 中的 this
  6. function func2() {
        function func3() {
            return this;
        }
        return func3();
    }
    var obj = { func2 : func2 };
    func2() === this;//true
    obj.func2() === obj;//false
    obj.func2() === this;//true
    
    使用巢狀函式被呼叫時,this 是指向 global object, 這是要特別留意的地方,如果 func3 想取得 func2 的 this,可利用參數傳遞或 closure 的方式解決
    • 參數傳遞
    • var obj = {
          func2: function() {
              function func3(that) {
                  return that;
              }
              return func3(this);
          }
      }
      obj.func2() === obj;//true
      
    • closure
    • var obj = {
          func2: function() {
              var that = this;
              function func3() {
                  return that;
              }
              return func3();
          }
      }
      obj.func2() === obj;//true
      
  7. call & apply 中的 this
  8. 在JavaScript中,函式是Function的實例,Function 中有 call & apply function,可以讓使用者決定this的參考對象
    var o1 = {};
    var o2 = {};
    function func4() { return this; }
    func4.call(o1) === o1; //true
    func4.apply(o2) == o2;//true
    
    複習一下 call 和 apply 的差別,兩者的差別在於傳遞參數的方法不同
    call是一個一個指定參數, examlple :
    func.call(obj,"1","2","3")
    apply的第二個參數是陣列, examlple :
    func.apply(obj,["1", "2", "3"])
  9. constructor 中的 this
  10. 若將函式當作建構式來用,內部的 this 則指向 new 所產生的新物件
    function Employee(name, department) {
        this.name = name;
        this.department = department;
    }
    var e1 = new Employee('Albert', 'accounting');
    console.log(e1.name);
    
    利用 new 運算子建立物件,類似於下面的寫法
    var e1 = (function(){
        var _new = { constructor: Employee, __proto__: Employee.prototype };
        _new.constructor();
        return _new;
    })();
    
    如果對 prototype 的用法不熟悉可參考 Javascript Prototype Chain
參考 : The “this” Keyword
3/26/2014

Eclipse 正式支援 Java 8

Java 8 已於 2014/3月18 發布 , Eclipse 4.4 從 I20140318-0830 這個版本開始正式支援 Java 8

Eclipse Project 4.4.0 頁面 : http://projects.eclipse.org/projects/eclipse/releases/4.4.0

Eclipse Project 下載頁面 : http://download.eclipse.org/eclipse/downloads/

Eclipse 4.3 的使用者也可透過安裝 feature patch 的方式來支援 Java 8 新功能
https://wiki.eclipse.org/JDT/Eclipse_Java_8_Support_For_Kepler
3/19/2014
1:24:00 PM 0

Fibonacci numbers (斐波那契數列)

義大利數學家 Fibonacci 所發明,他描述兔子生長的數目時用上了這數列,假設兔子每個月都會生產小兔子,如此不停的繁衍,且兔子永不死去 此數列常在程式演算法的教科書中出現,數列的解法有很多種,以下列出幾個簡單的 Java 程式解法

簡單表達式
F0 = 0
F1 = 1
Fn = Fn-1 + Fn-2

遞迴解法
public long fib(int n) {
    if (n < 2) return n;   
    else return fib(n - 1) + fib(n - 2);
}
迴圈解法
public long fib(int n) {
    if (n < 2)
        return n;

    long x = 0L;
    long y = 1L;
    long temp = 0L;

    for (int i = 2; i <= n; i++) {
        temp = y;
        y = x + y;
        x = temp;
    }
    return y;
}
Fork / Join 解法
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

public class Fibonacci extends RecursiveTask<Long> {

    private final int n;

    Fibonacci(int n) {
        this.n = n;
    }

    @Override
    public Long compute() {
        if (n < 2) return (long) n;

        final Fibonacci f1 = new Fibonacci(n - 1);
        final Fibonacci f2 = new Fibonacci(n - 2);
        f1.fork();
        return f2.compute() + f1.join();
    }
 
    public static void main(String[] args) {
        final ForkJoinTask<Long> fjt = new Fibonacci(Integer.parseInt(args[0]));
        new ForkJoinPool().execute(fjt);
        try {
            System.out.println(fjt.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}
Memoization 解法
記憶前幾次計算過的結果,避免重覆的計算,藉此來提高運算速度
import java.util.HashMap;
import java.util.Map;

public class Fibonacci {

    private static Map<Integer, Long> cache = new HashMap<>();

    public static long fib(int n) {
        if (n < 2) return n;
        return cache.computeIfAbsent(n, k -> Math.addExact(fib(k - 1), fib(k - 2)));
    }

    public static void main(String args[]) {
        fib(Integer.parseInt(args[0]));
    }
}
參考 :
http://en.wikipedia.org/wiki/Fibonacci_number
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-11.html#%_sec_1.2.2
3/12/2014
6:04:00 PM 0

GoDaddy 設定將 domain.com 轉址到 www.domain.com

  1. 首先使用個人帳號登入
  2. 在 Products 管理畫面上, 展開 DOMAINS 的下拉表格, 按下 Launch 按鈕
  3. 修改 Domain Settings 內的 Forwarding 設定
  4. 按下 Add one now
  5. 輸入 Forwarding to 的網址
  6. 按下 Save 設定完成
  7. 完成後的畫面如下, 稍後片刻設定才會生效
3:48:00 PM 0

Java 8 Functional Interface

Java 8 新增了 lambda expression 的新概念, 如果要將 method 當作參數傳遞, 就要先定義所需的函式介面(Functional Interface)

什麼是函式介面呢? 簡而言之就是 interface 中, 只定義了一個可被 implement 的抽象 method

Java 內建的函式介面有很多,像是 java.lang.Runnable, java.util.concurrent.Callable, java.util.Comparator,這些 interface 的共同點就是只定義了一個抽象 method, 因為只定義了一個抽象 method, 當在程式中使用 lamdba expression 時, 編譯器自然知道是 implement interface 中的哪個 method

Java8 新增了一個 annotation : @FunctionalInterface, 如果在一個不是 functional interface 的 interface 用這個 annotation, compiler 就會顯示警告,使用方法如下
@FunctionalInterface
public interface TestFunctionalInterface {
    void test1();
}
若加入 void test2(); 則會發生錯誤

Java 8 的 API 文件上說明了建立 functional interface 的原則 => "a functional interface has exactly one abstract method"
只要符合上述原則,下面的例子使用了 default method 仍然是一個有效的 functional interface
@FunctionalInterface
public interface SubFunctionalInterface extends TestFunctionalInterface {
    default public void test2() {
        System.out.println("test2");
    }
}
Java 8 定義了許多通用函式介面, 置放於 java.util.function package 中, 開發者可視狀況需求使用所需的 interface
3/05/2014
5:46:00 PM 0

Java ThreadLocal

ThreadLocal 的用途 : ThreadLocal 是在多執行緒中儲存變數值的方式,當不同 thread 共用 ThreadLocal 實例,可設定和讀取屬於自身 Thread 的變數值而不相互干擾,用 thread local variable 來稱呼它或許更為恰當,其概念正好與 singleton 相反

ThreadLocal 提供 3 個 public method 與 1 個 protected method
T get()
protected  T initialValue()
void remove()
void set(T value)
ThreadLocal 內部儲存值的方式, 其實是利用到 thread 實例中的 threadLocals 實例變數(instance variable),threadLocals 是個類似於 HashMap 的物件, ThreadLocal 將自身實例當作 key, 將 set 的值設定到 threadLocals 物件參考中

ThreadLocal set method source code
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);//reference to t.threadLocals
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);//t.threadLocals = new ThreadLocalMap(this, value);
}
ThreadLocal set 的資料實際上是儲存於 thread instance 中, 這樣做的好處是當該 thread instance 被 GC 後 ThreadLocal 儲存的參考也跟著消失了,不會有記憶體洩漏(memory leak)的問題

ThreadLocal example:
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThreadLocal {

    private final static ThreadLocal<Date> endDate = new ThreadLocal<Date>() {
        @Override
        protected Date initialValue() {
            return new Date();
        }
    };

    public static void main(String[] args) {
        final ExecutorService exec = Executors.newCachedThreadPool();
        final Runnable task = () -> { //Java lambda expression
            try {
                TimeUnit.SECONDS.sleep((int) Math.rint(Math.random() * 10));
            } catch (final InterruptedException e) {

                e.printStackTrace();
            }

            System.out.printf("Thread Completed: %1$d : %2$tF %2$tT%n", Thread
                    .currentThread().getId(), TestThreadLocal.endDate.get());
        };

        for (int i = 0; i < 10; i++) {
            exec.execute(task);
        }

        exec.shutdown();
    }
}
3/04/2014

解決更新 Java 版本後 Applet 無法執行的問題

在過去的 Web 上使用 Java Applet 是相當受歡迎的的技術之一,但 Applet 與一般的 Java 應用程式不同,瀏覽器必需加入 Java Plug-In 才可在瀏覽器上正確執行
如果最近你在 Windows 上做了 Java Update,升級完後卻發現原本可正常瀏覽的 Applet 卻無法執行,可檢查以下設定
  1. 設定 Applet 的 Java Runtime 版本
    • 開啟 Java 控制面板
    • 開始 > 設定 > 控制台 > Java, 點擊 Java icon 就可以開啟 Java 控制面板, 如果在 Windows 控制台中找不到可以到 JRE 的安裝目錄下尋找 javacpl.exe 並執行 (ex: Java\jre7\bin\javacpl.exe)
    • 指定 Java Runtime 版本
      Java 控制面板 > Java 頁籤 > 檢視 按鈕 > 依需求勾選已啟用欄位
      Applet 執行時可從 console 觀察 Applet 執行時所使用的 JRE 版本
  2. 設定 Java 安全性
    在 Java 7 之後, Java 控制面板在安全性設定方面做了增加
    Java 6 安全頁籤 Java 7 安全頁籤
    • 檢查在瀏覽器中啟用 Java 內容,此選項是否勾選
    • 使用新增例外網站功能,新版本的安全設定更加嚴謹,執行 Applet 時,如果出現 "您的安全設定值已封鎖自行簽署的應用程式,使其無法執行" 的訊息,可加入例外清單,降低安全性限制 (加入例外清單前請確認是否為信任網站)
  3. 啟用瀏覽器 Plug-in
    Java 控制面板 > 進階 > 瀏覽器的預設 Java

  4. 使用 x86 版本的 JDK 或 JRE
    部分舊版程式只支援 x86 的版本,因此在安裝 JDK 或 JRE 時儘量選擇 x86 的版本