April 17, 2014

Project Lambda ၏ ဘာသာရပ်ဆိုင်ရာပြောင်းလည်းမှု့

ပြီးခဲ့သောအခန်းတွင် Project Lambda ၏ Lambda Expression အား ဖော်ပြခဲ့၏။ သို့ရာတွင် Project Lambda ၏ ဘာသာရပ်ပိုင်းဆိုင်ရာပြောင်းလည်းမှု့သည် Lambda Expression တစ်ခုတည်းမဟုတ်။ အခြားသော ဘာသာရပ်ဆိုင်ရာ ပြောင်းလည်းမှု့များကိုလည်း ပြုလုပ်ခဲ့ပါသေးသည်။

ယခုတစ်ခေါက်တွင် Project Lambda ၏ ဘာသာရပ်ပိုင်းဆိုင်ရာပြောင်းလည်းမှု့များ အကြောင်းကို စုစည်း ဖော်ပြသွားပါမည်။

Effective final


Java SE 8 မတိုင်ခင်က Local Variable များအား Anonymous Class အတွင်းမှ ဆက်သွယ် အသုံးပြုနိုင်ရန် final keyword အား အသုံးပြု၍ မပြောင်းလည်းနိုင်အောင် စီမံဖို့လိုအပ်ခဲ့ပါသည်။ သို့ရာတွင် Java SE 8 အရောက်တွင် final keyword အား ရေးသားစရာမလိုအပ်ပဲ၊ ဒီအတိုင်း Anonymous Class အတွင်းမှ အသုံးပြုနိုင်ပါသည်။

final keyword အား မရေးသားထားသော်လည်း local variable အား Anonymous Class နှင့် Lambda Expression အတွင်းမှ ပြုပြင်ပြောင်းလည်း၍မရပါ။ ဤကဲ့သို့  local variable အား Effective final ဟု ခေါ်ဆိုပါသည်။
    public static void main(String[] args) {
        
        int sum = 10;
        
        IntStream.rangeClosed(1, 10).forEach(x -> System.out.println(x + sum));
    }
အထက်ပါအတိုင်း local variable sum အား Lambda Expression အတွင်းမှ final မတပ်ပဲ ခေါ်ယူအသုံးပြုနိုင်ပါသည်။ သို့ရာတွင် ၎င်း local variable အား ပြုပြင်၍မရနိုင်ပေ။ အောက်ပါအတိုင်း ရေးသားပါက Compile လုပ်စဉ်တွင် Error ဖြစ်မည် ဖြစ်သည်။
    public static void main(String[] args) {
        
        int sum = 0;
        
        IntStream.rangeClosed(1, 10).forEach((x) -> sum += x);
    }



Method ခေါ်ဆိုပုံနည်းအသစ်


Java SE 8 အရောက်တွင် Project Lambda ဖြင့် Method ခေါ်ဆိုပုံနည်းအသစ်အား ဖြည့်စွက်ခဲ့ပါသည်။ ဥပမာအားဖြင့် System.out.println အား System.out::println ဟု ရေးသားနိုင်ပါသည်။
    public static void main(String[] args) {
        IntStream.rangeClosed(1, 10).forEach(System.out::println);
    }
Java SE 8 တွင် ထည့်သွင်းခဲ့သော Method ခေါ်ဆိုနည်းသုံးမျိုးရှိပါသည်။

  • Reference To Static Method
  • Reference To Instance Method
  • Reference To Constructor



Reference to static Method


Static Method များအား ခေါ်ဆိုသည့်နည်းလမ်း ဖြစ်ပါသည်။ ခေါ်ဆိုရာတွင် အောက်ပါအတိုင်း ရေးသားရပါသည်။

[Class Name]::[method name]

1 မှ 10 ထိ ကိန်းများပါဝင်သော List အတွင်းမှ ကိန်းများအား နှစ်ဆပြုလုပ်၍ ရိုက်ထုတ်သော ပရိုဂရမ်တစ်ခုကို နမှုနာ အဖြစ်ရေးကြည့်ပါမည်။

Java SE 7 ဖြင့် ရေးခြင်း
package com.dtc.lambda;

import java.util.Arrays;
import java.util.List;

public class Sample {
    
    public static void showDouble(int i) {
        System.out.println(i * 2);
    }

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        for(int i: list) {
            showDouble(i);
        }
    }
}
အထက်ပါအတိုင်း For Statement အား အသုံးပြု၍ ရေးသားရမည်ဖြစ်သည်။

Java SE 8 အရောက်တွင်
package com.dtc.lambda;

import java.util.Arrays;
import java.util.List;

public class Sample {
    
    public static void showDouble(int i) {
        System.out.println(i * 2);
    }

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        list.forEach(Sample::showDouble);
    }
}
အထက်ပါအတိုင်း List တွင်လည်း Inner Iterator ဖြစ်သော forEach method အား အသုံးပြုနိုင်ပြီး၊ ၎င်းအတွင်းတွင် method call နည်း အသစ်ဖြစ်သော System.out::println ဟု ရေးသားနိုင်ပါသည်။ println method ၏ Argument နေရာတွင် အလိုအလျှောက် List အတွင်းရှိ Element များက တစ်ခုစီဝင်ရောက်ပေးသွားမည် ဖြစ်ပါသည်။

အထက်ပါ Method Call နည်းအား Lambda Expression ၏ နေရာတွင်လည်း အစားထိုးအသုံးပြုနိုင်ပါသေးသည်။
package com.dtc.lambda;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

public class Sample {

    public enum Operator {
        ADD, SUBSTRACT, MULTIPLY, DIVIDED;
    }

    @FunctionalInterface
    public static interface Calculator {
        public double calculate(Operator op, Double left, Double right);
    }

    public static double cal(Operator op, Double left, Double right) {
        double result = BigDecimal.ZERO.doubleValue();
        switch (op) {
        case ADD:
            result = left + right;
            break;
        case SUBSTRACT:
            result = left - right;
            break;
        case MULTIPLY:
            result = left * right;
            break;
        case DIVIDED:
            result = left / right;
            break;
        default:
            break;
        }

        return result;

    }

    public static void main(String[] args) {
        
        Calculator c = Sample::cal;
        System.out.println(c.calculate(Operator.ADD, 10.0, 5.0));
        System.out.println(c.calculate(Operator.SUBSTRACT, 10.0, 5.0));
        System.out.println(c.calculate(Operator.MULTIPLY, 10.0, 5.0));
        System.out.println(c.calculate(Operator.DIVIDED, 10.0, 5.0));
    }
}
အထက်ပါအတိုင်း Interface Object အား Lambda Expression ဖြင့်ဖော်ပြလိုသည့်နေရာတွင် Calculator c = Sample::cal ဟု Method Call နည်း အသစ်အား အစားထိုး၍ ဖော်ပြနိုင်ပါသည်။


Reference to Instance Method 


Instance Method များအား ခေါ်ယူအသုံးပြုသည့်အခါတွင် အသုံးပြုရပါသည်။ ရေးသားပုံမှာ အောက်ပါအတိုင်း ဖြစ်ပါသည်။
// Instance Name အား သိရှိသည့်အခါ
[Instance Name]::[method name]
// Instance Name အား မသိသည့်အခါ
[Instance Name]::[method name]
Instance Method အား ခေါ်ယူအသုံးပြုရာတွင် Instance အမည်အားသိရှိနိုင်ခြင်း အပေါ်မှုတည်၍ ရေးသားပုံ ခြားနားပါသည်။ မိမိ၏ Class အတွင်း Declare လုပ်ထားသော Instance များမှာမူ အမည်အားသိရှိနိုင်သောကြောင့် Instance Name အား တိုက်ရိုက်အသုံးပြုနိုင်ပါသည်။ သို့ရာတွင် Instance အဖြစ်မတည်ဆောက်ရသေးသော Instance Method များ၊ သို့မဟုတ် System မှ အလိုအလျှောက်ပံ့ပိုးပေးထားသော System.out ကဲ့သို့သော Instance များမှာမူ အမည်အား မသိနိုင်သောကြောင့် Class Name အား အသုံးပြု၍ ရေးသားနိုင်ပါသည်။
package com.dtc.lambda;

import java.util.Arrays;
import java.util.List;

public class Sample {
    
    public void twice(int i) {
        System.out.println(2 * i);
    }

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Sample sample = new Sample();
        list.forEach(sample::twice);
    }
}
Instance Method Reference နည်းအား Lambda Expression ၏ နေရာတွင်လည်း အစားထိုး၍ ဖော်ပြနိုင်ပါသည်။ နမှုနာထဲတွင် Inner Class Task ၏ execute method အား Lambda Expression ဖြင့် ရေးသားကြည့်ပါမည်။
package com.dtc.lambda;

public class Sample {
    
    class Task<T> {
        public void execute(T t) {
            System.out.println(t);
        }
    }
    
    interface Executor<S, T> {
        public void apply(S s, T t);
    }
    
    public Sample() {
        Executor<Task<String>, String> exe = (task, text) -> task.execute(text);
        exe.apply(new Task<>(), "Hello Java SE 8");
    }

    public static void main(String[] args) {
        new Sample();
    }
}
Sample Constructor အထဲတွင် Executor Interface ၏ Object အား တည်ဆောက်ရာတွင် Lambda Expression ဖြင့် ရေးသားထားပါသည်။

အောက်တွင် အထက်ပါနာ့မှုနာ၏ Lambda Expression ဖြင့် ရေးသားထားသော နေရာအား Instance Method Reference နည်းအသစ်ဖြင့် အစားထိုးရေးသားကြည့်ပါမည်။
package com.dtc.lambda;

public class Sample {
    
    class Task<T> {
        public void execute(T t) {
            System.out.println(t);
        }
    }
    
    interface Executor<S, T> {
        public void apply(S s, T t);
    }
    
    public Sample() {
        Executor<Task<String>, String> exe = Task::execute;
        exe.apply(new Task<>(), "Hello Java SE 8");
    }

    public static void main(String[] args) {
        new Sample();
    }
}



Reference to Constructor


Lambda Expression ၏နေရာတွင် Constructor အား ခေါ်ယူရာ၌ အောက်ပါအတိုင်း ရေးသားနိုင်ပါသည်။
[Class Name]::new
နမှုနာတစ်ခုအား ရေးသားကြည့်ပါမည်။
package com.dtc.lambda;

import java.util.Arrays;
import java.util.List;

public class Sample {
    
    class Shop {
        private List<String> items;
        public Shop(List<String> items) {
            this.items = items;
            System.out.println("Shop has been create.");
        }
        
        public List<String> getItems() {
            return this.items;
        }
    }
    
    interface ShopFactory {
        public Shop createShop(List<String> items);
    }
    
    public Sample() {
        ShopFactory factory = Shop::new;
        factory.createShop(Arrays.asList("Tomato","Eggs"))
            .getItems()
            .forEach(System.out::println);
    }

    public static void main(String[] args) {
        new Sample();
    }
}
အထက်ပါနမှုနာထဲတွင် Sample Comstructor အတွင်း၌ ShopFactory Interface ၏ Object အားတည်ဆောက်ရာတွင် Shop::new ဟု Reference To Constructor အား အသုံးပြုထားပါသည်။ Lambda Expression ဖြင့် ရေးသားမည်ဆိုပါက အောက်ပါအတိုင်း ရေးသားရမည် ဖြစ်သည်။
    public Sample() {
        ShopFactory factory = (items) -> { return new Shop(items);};
        factory.createShop(Arrays.asList("Tomato","Eggs"))
            .getItems()
            .forEach(System.out::println);
    }
Lambda Expression အား ရေးသားရာတွင် ရှည်လျားနေသည့်အပိုင်းအား Method Reference နည်း အသစ်များအား အသုံးပြု၍ ပိုမိုရှင်းလင်းစွာ ရေးသားနိုင်ကြောင်းကို တွေ့ရှိရပါသည်။


ကိုးကား
http://itpro.nikkeibp.co.jp/article/COLUMN/20140324/545382/?ST=develop&P=1

ဆက်ပါဦးမည်၊ လေးစားစွာဖြင့်။
မင်းလွင်

No comments:

Post a Comment