SlideShare a Scribd company logo
Java SE 8 的 Lambda 連鎖效應
 - 語法、風格與程式庫
林信良
   http://openhome.cc
caterpillar@openhome.cc
議程
• 一級函式與 λ 演算
• JDK8 的 Lambda 語法
• 介面預設方法(Default method)
• 擴充的 Collection 框架
• 函數式風格的可能性
一級函式與 λ 演算




             第十一個希臘字母
             物理上的波長符號
             放射學的衰變常數
             線性代數的特徵值
             λ 演算
             ….
一級值
• 值(Value)可指定給變數
• 一級(First-class)值可傳給函式或從函式中傳回
                物件

                     函式?



      基本型態           運算式?
一級函式
• 有些語言中函式是一等公民(First-class citizen)
 – 高階函式(High order function)

              function doSome(param) {
                  // 作些事
              }

              var doSome = function(param) {
                  // 作些事
              };
一級函式
• 有些語言中函式是一等公民(First-class citizen)
 – 高階函式(High order function)

               function doSome(param) {
                   // 作些事
               }

               var doSome = function(param) {
                   // 作些事
               };


        doOther(function(param) {
                 function(param)
            // 作些事 // 作些事
        });      };
一級函式
• 有些語言中函式是一等公民(First-class citizen)
 – 高階函式(High order function)

                function doSome(param) {
                    // 作些事
                }

                var doSome = function(param) {
                    // 作些事
                };

      function doAction(opt) {
          return function(param) {
              // 作些事 作些事
                     //
          };     };
      };
What is


           http://en.wikipedia.org/wiki/Lambda
           In programming languages such as
           Lisp and Python, lambda is an
           operator used to denote
           anonymous functions or closures




/lambda/
λ 演算(Lambda calculus)
• 每個表達式(Expression)代表具單一參數函數
• 參數本身亦可接受具有單一參數的函式
• f(x) = x * 2 可匿名地表示為 …

        λ x. x * 2
        x -> x * 2
λ 演算(Lambda calculus)
• 如果要套用 x 為 2
  (x -> x * 2)(2)
  = 2 * 2
  = 4
• g(y) = y -1 代入 f(x) 匿名地表達為…
  (y -> y - 1)(x -> x * 2)
  = x -> x * 2 - 1
λ 演算(Lambda calculus)
• 多參數的函數可使用單參數函數套用而成
 (x, y) -> x * x + y * y
 = x -> (y -> x * x + y * y)

•若x為2而y為3
(x -> (y -> x * x + y * y))(2)(3)
= (y -> 2 * 2 + y * y)(3)
= 4 + 3 * 3
= 4 + 9
= 13
λ 演算(Lambda calculus)
• 可用來表現任何可計算函數
• 可使用函數實現控制結構(如 if、forEach等)
• 一個小型通用語言
  butThat = cond->fv->tv->
         (cond or fv) and (cond and tv)

  butThat(true)(10)(20)
   = (true or 10) and (true and 20)
   = true and 20
   = 20
一級函式與 λ 演算
• 不同語言提供不同程度的 Lambda 表達式支援
(x -> x * 2)(2)


             function(x) {
                 return x * 2;
             }(2);
一級函式與 λ 演算
• JDK8 前存在 Lambda 語法類似品
 – 匿名內部類別(Anonymous inner class)

• 定義單一抽象方法(Single abstract method)介
面模擬一級函式

 interface Func<P, R> {
     R apply(P p);
 }
一級函式與 λ 演算
• 使用匿名內部類別來表示 x         -> x * 2
new Func<Integer, Integer>() {
    public Integer apply(Integer x) {
        return x * 2;
    }
};
一級函式與 λ 演算
• 設計 compose(f, g)        達成 g(f(x)) 的函數組合
static <A, B, C> Func<A, C> compose(
            final Func<A, B> f, final Func<B, C> g) {
    return new Func<A, C>() {
                public C apply(A x) {
                    return g.apply(f.apply(x));
                }
           };
}
一級函式與 λ 演算
• f(x) = x + 2 而 g(y) = y * 3
• h(x) = g(f(x))
compose(
    new Func<Integer, Integer>() {
        public Integer apply(Integer x) {
            return x + 2;
        }
    },
    new Func<Integer, Integer>() {
        public Integer apply(Integer y) {
            return y * 3;
        }
    }
);
JDK8 的 Lambda 語法




        λ
JDK8 的 Lambda 語法
  • 使用 JDK8 的 Lambda 語法來表示 x                   -> x * 2
    (Integer x) -> x + 2


  • 設計 compose(f,          g) 達成 g(f(x)) 的函數組合
static <A, B, C> Func<A, C> compose(Func<A, B> f, Func<B, C> g) {
    // 忽略.apply 就是 x -> g(f(x))
    return x -> g.apply(f.apply(x));
}

  • f(x) = x + 2 、 g(y) = y * 3、h(x) = g(f(x))
   compose((Integer x) -> x + 2, (Integer y) -> y * 3)
JDK8 的 Lambda 表示式
•   (type parameter) -> function_body

    – 單一運算式
      (int x, int y) -> x + y

      () -> 42


    – 陳述區塊
      (String s) -> { System.out.println(s); }
函式介面(Functional interface)
• 單一抽象方法的介面
 public interface Runnable {
     void run();
 }
 public interface Comparator<T> {
     int compare(T o1, T o2);
 }

 public interface Callable<V> {
     V call() throws Exception
 }
目標定型(Target typing)
• 目標型態與環境(Context)有關
 – 目標型態可用於類型推斷(Type inference)
Runnable r = () -> { out.println("later"); };
Comparator<String> c = (s1, s2) -> s1.compareTo(s2);
Collections.sort(lists, (s1, s2) -> -s1.compareTo(s2));



• 獨立於型態的Lambda 表示式
Callable<String> c = () -> "done";
PrivilegedAction<String> a = () -> "done";
不只是語法蜜糖
• 語彙範圍(Lexical scoping)
    – Lambda 語法本體中的名稱與包裹環境相同
public class Hello {
  Runnable r1 = () -> { out.println(this); }
  Runnable r2 = () -> { out.println(toString()); }

    public String toString() { return "Hello, world!"; }

    public static void main(String... args) {
      new Hello().r1.run();
      new Hello().r2.run();
    }
}
不只是語法蜜糖
• 變數捕捉(Variable capture)
 – 與 final 等效的區域變數不需要 final
Callable<String> helloCallable(String name) {
  String hello = "Hello";
  return () -> (hello + ", " + name);
}

• 編譯錯誤...
int sum = 0;
list.forEach(e -> { sum += e.size(); });

• 建議...
int sum = list.map(e -> e.size())
              .reduce(0, (a, b) -> a + b);
方法參考(Method reference)
 • 類別靜態方法
public class Person {
  ...
  public static int compareByAge(Person a, Person b) { ... }
  public static int compareByName(Person a, Person b) { ... }
}

Person[] people = ...
// Arrays.sort(people, (a, b) -> a.getAge() – b.getAge());
Arrays.sort(people, Person::compareByAge);

interface Block<T> { void run(T arg); }
Block<Integer> b1 = System::exit;   // void   exit(int status)
Block<String[]> b2 = Arrays::sort; // void    sort(Object[] a)
Block<String> b3 = MyProgram::main; // void   main(String... args)
Runnable r = MyProgram::main;       // void   main(String... args)
方法參考(Method reference)
• 特定物件實例方法
public class ComparisonProvider {
    public int compareByName(Person p1, Person p2) { ... }
    public int compareByAge(Person p1, Person p2) { ... }
}
...
ComparisonProvider comparisonProvider = ...;
Arrays.sort(people, comparisonProvider::compareByName);



• 實例方法中可帶物件狀態
  – 相當於讓 Lambda 語法帶有狀態(Closure 的替代?)
方法參考(Method reference)
• 任意類別的實例方法
List<String> names = Arrays.asList("Justin", ...);

Collections.sort(names,
                (s1, s2) -> s1.compareToIgnoreCase(s2));

Collections.sort(names, String::compareToIgnoreCase);
方法參考(Method reference)
• 讓 Lambda 語法的目標類型可以變換
Callable<String> c = () -> "done";
PrivilegedAction<String> a = c::call;
建構式參考(Constructor reference)
• 像是特殊的靜態方法參考:
 SocketFactory factory = SocketImpl::new;
介面預設方法(Default method)
介面預設方法(Default method)
• JDK8 前實作介面以實現多個規格的繼承來源
  – 捨棄繼承多個實作來源的可能性,規避了多重繼承下實
    作衝突等問題
public class Ball implements Comparable<Ball> {
  public boolean notEquals(Ball that) {
     return this.radius - that.radius;
  }
  // 底下都是根據notEquals()實作
  public boolean lessThan(Ball that) {
     return this.notEquals(that) < 0;
  }
  public boolean lessOrEquals(Ball that) {
     return this.lessThan(that) || this.notEquals(that) == 0;
  }
  public boolean greaterThan(Ball that) {
     return !this.lessOrEquals(that);
  } ...
介面預設方法(Default method)
• JDK8 介面可以是根據抽象的共用實作
public interface Comparable<T> {
  boolean notEquals(T that);

  boolean lessThan(T that) default {
     return this.notEquals(that) < 0;
  }
  boolean lessOrEquals(T that) default {
     return this.lessThan(that) || this.notEquals(that) == 0;
  }
  boolean greaterThan(T that) default {
     return !this.lessOrEquals(that);
  } ...
介面預設方法(Default method)
• JDK8 可以實作具有預設方法的介面
public class Ball implements Comparable<Ball> {
  public boolean notEquals(Ball that) {
     return this.radius - that.radius;
  } ...

• 實作可能發生衝突..
 interface Robot implements Artist, Gun {
   void draw() default { Artist.super.draw(); }
 }
介面預設方法(Default method)
• 擴充既有程式庫以搭配 Lambda 語法
 – 僅在介面中新增方法定義?
 – 使用靜態方法?像是 Collections.filter(…)?
 – 獨立的新 API?像是 Collection2 框架?
 interface Iterator<E> {
   boolean hasNext();
   E next();
   void remove();

     void skip(int i) default {
       for (; i > 0 && hasNext(); i--) next();
     }
 }
擴充的 Collection 框架
• 高階函式
 – 可讀性
 – 簡潔性
 – 導入新的抽象層

• 以迭代為例…
 for(Ball b : balls) {
     b.setColor(RED);
 }

 balls.forEach(b -> { b.setColor(RED); });
擴充的 Collection 框架
• 匿名類別作不到嗎?
– 想分離關切點,但又帶入新的關切點
 balls.forEach(new Block<Ball> {
     public void apply(Ball ball) {
         ball.setColor(RED);
     }
 });



• 傳入 Lambda 表示式,而非傳入不想要的雜訊
擴充的 Collection 框架
• 為什麼是 Collection 框架?
• 許多問題都是資料處理問題…
 – 關聯式資料通常就是待處理資料群集…

• filter、map、fold 等是處理資料時的高階抽象
 –   過濾一組資料
 –   將一組資料對應至另一組資料
 –   逐一取得資料計算單一結果
 –   …
擴充的 Collection 框架
• 管線化(Piped)操作
int sum = names.filter(s -> s.length() < 3)
               .map(s -> s.length())
               .reduce(0, (sum, len) -> sum + len);


int sum = names.filter(s -> s.length() < 3)
               .map(s -> s.length())
               .sum();
擴充的 Collection 框架
• 管線化(Piped)操作
blocks.filter(b -> b.getColor() == BLUE)
      .forEach(b -> { b.setColor(RED); });


List<Block> blue = blocks.filter(b -> b.getColor() == BLUE)
                         .into(new ArrayList<>());


Set<Box> blueBlock = blocks.filter(b -> b.getColor() == BLUE)
                           .map(b -> b.getContainingBox())
                           .into(new HashSet<>());
擴充的 Collection 框架
• 延遲(Laziness)
 int sum = blocks.filter(b -> b.getColor() == BLUE)
                 .map(b -> b.getWeight())
                 .sum();



• 捷徑(short-circuiting)
 Block firstBlue = blocks.filter(b -> b.getColor() == BLUE)
                         .getFirst();
擴充的 Collection 框架
• 共用的函式介面(java.util.functions)
 – Predicate
   – boolean test(T t)
 – Block
   – void apply(T t);
 – Mapper
   – U map(T t)
 – ...
擴充的 Collection 框架
• 已實作 filter、map 與 fold 的細節
 –   循序?
 –   遞迴?
 –   共用資料結構?
 –   平行化?

• 可以用更高階的抽象來處理資料
 int sum = blocks.parallel()
                 .filter(b -> b.getColor() == BLUE)
                 .map(b -> b.getWeight())
                 .sum();
全部放在一起
for (Method m : enclosingInfo.getEnclosingClass().getDeclaredMethods()) {
     if (m.getName().equals(enclosingInfo.getName()) ) {
         Class<?>[] candidateParamClasses = m.getParameterTypes();
         if (candidateParamClasses.length == parameterClasses.length) {
             boolean matches = true;
             for(int i = 0; i < candidateParamClasses.length; i++) {
                 if (!candidateParamClasses[i].equals(parameterClasses[i])) {
                     matches = false;
                     break;
                 }
             }

             if (matches) { // finally, check return type
                 if (m.getReturnType().equals(returnType) )
                     return m;
             }
         }
    }
}

throw new InternalError("Enclosing method not found");
全部放在一起
Method matching =
  Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
  .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
  .filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
  .filter(m -> Objects.equals(m.getReturnType(), returnType))
  .getFirst();

if (matching == null)
    throw new InternalError("Enclosing method not found");
return matching;
全部放在一起
List<Album> favs = new ArrayList<>();
for (Album a : albums) {
    boolean hasFavorite = false;
    for (Track t : a.tracks) {
        if (t.rating >= 4) {
            hasFavorite = true;
            break;
        }
    }
    if (hasFavorite)
        favs.add(a);
}

Collections.sort(favs, new Comparator<Album>() {
                           public int compare(Album a1, Album a2) {
                                return a1.name.compareTo(a2.name);
                           }});
全部放在一起
List<Album> sortedFavs =
  albums.filter(a -> a.tracks.anyMatch(t -> (t.rating >= 4)))
        .sortedBy(a -> a.name)
        .into(new ArrayList<>());
函數式風格的可能性
函數式風格的可能性
• Lambda 語法在原語言中提供小型通用語言
• 在某些問題領域…
 – 提供以 λ 演算解題的可能性

• Java 在函數式程式設計(Functional
Parogramming)的可能性?
函數式風格的可能性
• 費式數的定義
 { F0 = 0, F1 = 1, Fn = Fn-1 + Fn-2 }


• 指令式程式設計(Imperative programming)?
 int fib(int n) {
     int a = 1; int b = 1;
     for(int i = 2; i < n; i++) {
         int tmp = b; b = a + b; a = tmp;
     }
     return b;
 }
函數式風格的可能性
• 函數式程式設計?
 int fib(int n) {
     if(n == 0 || n == 1) return n;
     else return fib(n - 1) + fib(n - 2);
 }


• 使用 Haskell
 fib 0 = 0
 fib 1 = 1
 fib n = fib (n-1) + fib (n-2)
函數式風格的可能性
• 函數式語言的特徵               fib 0 = 0
                         fib 1 = 1
–   一級函式                 fib n = fib (n-1) + fib (n-2)
–   Immutable            sum [] = 0
–   Lazy evaluation      sum (x:xs) = x + sum xs
–   Pattern match
                         {2 * x | x ∈ {1, 2..100}}
–   List comprehension
                         [2 * x | x <- [1, 2..100]]
–   Curried function
                         f x y = x + y
                         g y = f 1 y
函數式風格的可能性
• JDK8 有多少函數式風格的特性?
– 直接支援 Lambda 語法
– 使用 final 變數強制 Immutable
– 以 API 封裝複雜細節達到…
  – 延遲求值
  – 模式匹配
  – List comprehension
  – Partially applied 與 Curried function
函數式風格的可能性
 • 以 API 封裝複雜細節,留下函數式外觀給使用者
   – Functional Java(functionaljava.org)
     – 目的就是為了讓 Java 實現函數式風格
     – 主要針對 JDK5 以上
     – 使用匿名內部類別繼承抽象類別
  final Array<String> a = array("Hello", "There", "what");
  final boolean b = a.exists(new F<String, Boolean>() {
      public Boolean f(final String s) {
          return fromString(s).forall(isLowerCase);
      }
  });

boolean b = a.exists(s -> fromString(s).forall(isLowerCase));
函數式風格的可能性
• 以 API 封裝複雜細節,留下函數式外觀給使用者
– Guava(code.google.com/p/guava-libraries)
  – 主要目的並非為了讓 Java 實現函數式風格
  – 主要針對 JDK5 以上
  – 使用匿名內部類別實作介面
函數式風格的可能性
 • Guava 目前不鼓勵函數式風格
Multiset<Integer> lengths = HashMultiset.create(
  FluentIterable.from(strings)
    .filter(new Predicate<String>() {
        public boolean apply(String string) {
          return CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string);
        }
     })
    .transform(new Function<String, Integer>() {
        public Integer apply(String string) {
          return string.length();
        }
     }));

Multiset<Integer> lengths = HashMultiset.create(
  FluentIterable.from(strings)
    .filter(s -> CharMatcher.JAVA_UPPER_CASE.matchesAllOf(s))
    .transform(s -> s.length())
));
總結
• λ 語法為 Java 提供了小型通用語言,在某些問題
領域,提供 λ 演算解題的可能性
• 除 JDK 程式庫將搭配 λ 語法演化,開放原始碼如
Functional Java、Guava 等也將呈現不同風格
• 新的抽象層將平行化、函數式等實作予以封裝,
簡潔的表述能力,使開發者進一步思索 map、
filter、fold 等問題的基本形式
參考資料
•   State of the Lambda v4
    – http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html

•   State of the Lambda: Libraries Edition
    – http://cr.openjdk.java.net/~briangoetz/lambda/collections-
       overview.html

•   Project Lambda
    – http://openjdk.java.net/projects/lambda/

•   Lambda calculus
    – http://en.wikipedia.org/wiki/Lambda_calculus

•   Functional Programming for Java Developers
    – http://shop.oreilly.com/product/0636920021667.do

•   APIO讲稿——函数式编程
    – http://www.byvoid.com/blog/apio-fp/
感謝 Orz
林信良
http://openhome.cc
caterpillar@openhome.cc

More Related Content

PDF
Java 8 與 retrolambda
PDF
千呼萬喚始出來的 Java SE 7
PDF
Java 開發者的函數式程式設計
PDF
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
PPT
Java SE 8 技術手冊第 12 章 - Lambda
PPT
Scala function-and-closures
PDF
functional-scala
PDF
如何在 Java App 中導入 Scala
Java 8 與 retrolambda
千呼萬喚始出來的 Java SE 7
Java 開發者的函數式程式設計
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
Java SE 8 技術手冊第 12 章 - Lambda
Scala function-and-closures
functional-scala
如何在 Java App 中導入 Scala

What's hot (20)

PPTX
Introduction to Basic Haskell Components (In Chinese)
PDF
Java8 lambda
PDF
Ecmascript
PDF
Execution
PPTX
Javascript share
PPTX
Ecma script edition5-小试
PPT
Hi Haskell
PDF
Use Lambdas in Android
PDF
潜力无限的编程语言Javascript
PDF
Haskell Foundations
PPT
Java SE 8 技術手冊第 10 章 - 輸入輸出
PPT
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
PDF
深入淺出 Web 容器 - Tomcat 原始碼分析
PPT
Java SE 8 技術手冊第 15 章 - 通用API
PPT
Introduction to C++ over CLI
PPTX
3, operators
PDF
Clojure简介与应用
PPTX
5, initialization & cleanup
PPTX
ES5 introduction
PDF
OOP in C - Virtual Function (Chinese Version)
Introduction to Basic Haskell Components (In Chinese)
Java8 lambda
Ecmascript
Execution
Javascript share
Ecma script edition5-小试
Hi Haskell
Use Lambdas in Android
潜力无限的编程语言Javascript
Haskell Foundations
Java SE 8 技術手冊第 10 章 - 輸入輸出
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
深入淺出 Web 容器 - Tomcat 原始碼分析
Java SE 8 技術手冊第 15 章 - 通用API
Introduction to C++ over CLI
3, operators
Clojure简介与应用
5, initialization & cleanup
ES5 introduction
OOP in C - Virtual Function (Chinese Version)
Ad

Viewers also liked (20)

PDF
Java Web 程式之效能技巧與安全防護
PDF
JDK8 Functional API
PDF
Servlet & JSP 教學手冊第二版 - 第 7 章:使用 JSTL
PDF
Servlet & JSP 教學手冊第二版 - 第 5 章:Servlet 進階 API、過濾器與傾聽器
PDF
Servlet & JSP 教學手冊第二版 - 第 6 章:使用 JSP
PDF
Servlet & JSP 教學手冊第二版 - 第 11 章:簡介 JavaMail
PDF
Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫
PDF
Java SE 7 技術手冊投影片第 06 章 - 繼承與多型
PDF
Servlet & JSP 教學手冊第二版 - 第 8 章:自訂標籤
PDF
Servlet & JSP 教學手冊第二版 - 第 10 章:Web 容器安全管理
PDF
Servlet & JSP 教學手冊第二版 - 第 12 章:從模式到框架
PDF
Java SE 7 技術手冊投影片第 04 章 - 認識物件
PDF
Servlet & JSP 教學手冊第二版 - 第 4 章:會話管理
PDF
Servlet & JSP 教學手冊第二版 - 第 2 章:撰寫與設定 Servlet
PDF
Java SE 7 技術手冊投影片第 05 章 - 物件封裝
PDF
Servlet & JSP 教學手冊第二版 - 第 3 章:請求與回應
PDF
Java SE 7 技術手冊投影片第 03 章 - 基礎語法
PDF
Java SE 7 技術手冊投影片第 07 章 - 介面與多型
PDF
Java SE 7 技術手冊投影片第 13 章 - 視窗程式設計
PDF
Java SE 7 技術手冊投影片第 02 章 - 從JDK到IDE
Java Web 程式之效能技巧與安全防護
JDK8 Functional API
Servlet & JSP 教學手冊第二版 - 第 7 章:使用 JSTL
Servlet & JSP 教學手冊第二版 - 第 5 章:Servlet 進階 API、過濾器與傾聽器
Servlet & JSP 教學手冊第二版 - 第 6 章:使用 JSP
Servlet & JSP 教學手冊第二版 - 第 11 章:簡介 JavaMail
Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫
Java SE 7 技術手冊投影片第 06 章 - 繼承與多型
Servlet & JSP 教學手冊第二版 - 第 8 章:自訂標籤
Servlet & JSP 教學手冊第二版 - 第 10 章:Web 容器安全管理
Servlet & JSP 教學手冊第二版 - 第 12 章:從模式到框架
Java SE 7 技術手冊投影片第 04 章 - 認識物件
Servlet & JSP 教學手冊第二版 - 第 4 章:會話管理
Servlet & JSP 教學手冊第二版 - 第 2 章:撰寫與設定 Servlet
Java SE 7 技術手冊投影片第 05 章 - 物件封裝
Servlet & JSP 教學手冊第二版 - 第 3 章:請求與回應
Java SE 7 技術手冊投影片第 03 章 - 基礎語法
Java SE 7 技術手冊投影片第 07 章 - 介面與多型
Java SE 7 技術手冊投影片第 13 章 - 視窗程式設計
Java SE 7 技術手冊投影片第 02 章 - 從JDK到IDE
Ad

Similar to Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫 (20)

PPTX
那些函數語言Tutorial沒有教我的事
PPTX
Learn Haskell The Easy Way
PDF
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
PDF
JCConf 2024 - Java 22 & 23 新功能介紹
PPTX
180518 ntut js and node
PDF
Java functional api
PDF
JCConf 2023 - 深入淺出 Java 21 功能
PDF
Lambda演算与邱奇编码
PDF
Clojure and FP
PPT
SCJP ch18
PDF
nodeMCU IOT教學02 - Lua語言
PDF
nodeMCU IOT教學02 - Lua語言
PDF
CH12:Lambda
PDF
張逸 - 研究所 / 轉學考計算機概論 、公職計算機概要 - 程式語言 - 試閱版
PPTX
2014 Java Developer Day會後分享 Java Functional API
PPT
SCJP ch08
PDF
JavaScript 快速跳坑指南
PDF
Java SE 7 技術手冊投影片第 09 章 - Collection與Map
PDF
Hadoop 0.20 程式設計
PPTX
保哥線上講堂:LINQ 快速上手
那些函數語言Tutorial沒有教我的事
Learn Haskell The Easy Way
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
JCConf 2024 - Java 22 & 23 新功能介紹
180518 ntut js and node
Java functional api
JCConf 2023 - 深入淺出 Java 21 功能
Lambda演算与邱奇编码
Clojure and FP
SCJP ch18
nodeMCU IOT教學02 - Lua語言
nodeMCU IOT教學02 - Lua語言
CH12:Lambda
張逸 - 研究所 / 轉學考計算機概論 、公職計算機概要 - 程式語言 - 試閱版
2014 Java Developer Day會後分享 Java Functional API
SCJP ch08
JavaScript 快速跳坑指南
Java SE 7 技術手冊投影片第 09 章 - Collection與Map
Hadoop 0.20 程式設計
保哥線上講堂:LINQ 快速上手

More from Justin Lin (20)

PPTX
Ch14 簡介 Spring Boot
PPTX
Ch13 整合 Spring MVC/Security
PPTX
Ch12 Spring 起步走
PPTX
Ch11 簡介 JavaMail
PPTX
Ch10 Web 容器安全管理
PPTX
Ch09 整合資料庫
PPTX
Ch08 自訂標籤
PPTX
Ch07 使用 JSTL
PPTX
Ch06 使用 JSP
PPTX
Ch05 Servlet 進階 API、過濾器與傾聽器
PPTX
Ch04 會話管理
PPTX
Ch03 請求與回應
PPTX
Ch02 撰寫與設定 Servlet
PPTX
CH1. 簡介 Web 應用程式
PDF
14. 進階主題
PDF
13.並行、平行與非同步
PDF
12. 除錯、測試與效能
PDF
11. 常用內建模組
PDF
10. 資料永續與交換
PDF
9. 資料結構
Ch14 簡介 Spring Boot
Ch13 整合 Spring MVC/Security
Ch12 Spring 起步走
Ch11 簡介 JavaMail
Ch10 Web 容器安全管理
Ch09 整合資料庫
Ch08 自訂標籤
Ch07 使用 JSTL
Ch06 使用 JSP
Ch05 Servlet 進階 API、過濾器與傾聽器
Ch04 會話管理
Ch03 請求與回應
Ch02 撰寫與設定 Servlet
CH1. 簡介 Web 應用程式
14. 進階主題
13.並行、平行與非同步
12. 除錯、測試與效能
11. 常用內建模組
10. 資料永續與交換
9. 資料結構

Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫

  • 1. Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
  • 2. 林信良 http://openhome.cc caterpillar@openhome.cc
  • 3. 議程 • 一級函式與 λ 演算 • JDK8 的 Lambda 語法 • 介面預設方法(Default method) • 擴充的 Collection 框架 • 函數式風格的可能性
  • 4. 一級函式與 λ 演算 第十一個希臘字母 物理上的波長符號 放射學的衰變常數 線性代數的特徵值 λ 演算 ….
  • 6. 一級函式 • 有些語言中函式是一等公民(First-class citizen) – 高階函式(High order function) function doSome(param) { // 作些事 } var doSome = function(param) { // 作些事 };
  • 7. 一級函式 • 有些語言中函式是一等公民(First-class citizen) – 高階函式(High order function) function doSome(param) { // 作些事 } var doSome = function(param) { // 作些事 }; doOther(function(param) { function(param) // 作些事 // 作些事 }); };
  • 8. 一級函式 • 有些語言中函式是一等公民(First-class citizen) – 高階函式(High order function) function doSome(param) { // 作些事 } var doSome = function(param) { // 作些事 }; function doAction(opt) { return function(param) { // 作些事 作些事 // }; }; };
  • 9. What is http://en.wikipedia.org/wiki/Lambda In programming languages such as Lisp and Python, lambda is an operator used to denote anonymous functions or closures /lambda/
  • 10. λ 演算(Lambda calculus) • 每個表達式(Expression)代表具單一參數函數 • 參數本身亦可接受具有單一參數的函式 • f(x) = x * 2 可匿名地表示為 … λ x. x * 2 x -> x * 2
  • 11. λ 演算(Lambda calculus) • 如果要套用 x 為 2 (x -> x * 2)(2) = 2 * 2 = 4 • g(y) = y -1 代入 f(x) 匿名地表達為… (y -> y - 1)(x -> x * 2) = x -> x * 2 - 1
  • 12. λ 演算(Lambda calculus) • 多參數的函數可使用單參數函數套用而成 (x, y) -> x * x + y * y = x -> (y -> x * x + y * y) •若x為2而y為3 (x -> (y -> x * x + y * y))(2)(3) = (y -> 2 * 2 + y * y)(3) = 4 + 3 * 3 = 4 + 9 = 13
  • 13. λ 演算(Lambda calculus) • 可用來表現任何可計算函數 • 可使用函數實現控制結構(如 if、forEach等) • 一個小型通用語言 butThat = cond->fv->tv-> (cond or fv) and (cond and tv) butThat(true)(10)(20) = (true or 10) and (true and 20) = true and 20 = 20
  • 14. 一級函式與 λ 演算 • 不同語言提供不同程度的 Lambda 表達式支援 (x -> x * 2)(2) function(x) { return x * 2; }(2);
  • 15. 一級函式與 λ 演算 • JDK8 前存在 Lambda 語法類似品 – 匿名內部類別(Anonymous inner class) • 定義單一抽象方法(Single abstract method)介 面模擬一級函式 interface Func<P, R> { R apply(P p); }
  • 16. 一級函式與 λ 演算 • 使用匿名內部類別來表示 x -> x * 2 new Func<Integer, Integer>() { public Integer apply(Integer x) { return x * 2; } };
  • 17. 一級函式與 λ 演算 • 設計 compose(f, g) 達成 g(f(x)) 的函數組合 static <A, B, C> Func<A, C> compose( final Func<A, B> f, final Func<B, C> g) { return new Func<A, C>() { public C apply(A x) { return g.apply(f.apply(x)); } }; }
  • 18. 一級函式與 λ 演算 • f(x) = x + 2 而 g(y) = y * 3 • h(x) = g(f(x)) compose( new Func<Integer, Integer>() { public Integer apply(Integer x) { return x + 2; } }, new Func<Integer, Integer>() { public Integer apply(Integer y) { return y * 3; } } );
  • 19. JDK8 的 Lambda 語法 λ
  • 20. JDK8 的 Lambda 語法 • 使用 JDK8 的 Lambda 語法來表示 x -> x * 2 (Integer x) -> x + 2 • 設計 compose(f, g) 達成 g(f(x)) 的函數組合 static <A, B, C> Func<A, C> compose(Func<A, B> f, Func<B, C> g) { // 忽略.apply 就是 x -> g(f(x)) return x -> g.apply(f.apply(x)); } • f(x) = x + 2 、 g(y) = y * 3、h(x) = g(f(x)) compose((Integer x) -> x + 2, (Integer y) -> y * 3)
  • 21. JDK8 的 Lambda 表示式 • (type parameter) -> function_body – 單一運算式 (int x, int y) -> x + y () -> 42 – 陳述區塊 (String s) -> { System.out.println(s); }
  • 22. 函式介面(Functional interface) • 單一抽象方法的介面 public interface Runnable { void run(); } public interface Comparator<T> { int compare(T o1, T o2); } public interface Callable<V> { V call() throws Exception }
  • 23. 目標定型(Target typing) • 目標型態與環境(Context)有關 – 目標型態可用於類型推斷(Type inference) Runnable r = () -> { out.println("later"); }; Comparator<String> c = (s1, s2) -> s1.compareTo(s2); Collections.sort(lists, (s1, s2) -> -s1.compareTo(s2)); • 獨立於型態的Lambda 表示式 Callable<String> c = () -> "done"; PrivilegedAction<String> a = () -> "done";
  • 24. 不只是語法蜜糖 • 語彙範圍(Lexical scoping) – Lambda 語法本體中的名稱與包裹環境相同 public class Hello { Runnable r1 = () -> { out.println(this); } Runnable r2 = () -> { out.println(toString()); } public String toString() { return "Hello, world!"; } public static void main(String... args) { new Hello().r1.run(); new Hello().r2.run(); } }
  • 25. 不只是語法蜜糖 • 變數捕捉(Variable capture) – 與 final 等效的區域變數不需要 final Callable<String> helloCallable(String name) { String hello = "Hello"; return () -> (hello + ", " + name); } • 編譯錯誤... int sum = 0; list.forEach(e -> { sum += e.size(); }); • 建議... int sum = list.map(e -> e.size()) .reduce(0, (a, b) -> a + b);
  • 26. 方法參考(Method reference) • 類別靜態方法 public class Person { ... public static int compareByAge(Person a, Person b) { ... } public static int compareByName(Person a, Person b) { ... } } Person[] people = ... // Arrays.sort(people, (a, b) -> a.getAge() – b.getAge()); Arrays.sort(people, Person::compareByAge); interface Block<T> { void run(T arg); } Block<Integer> b1 = System::exit; // void exit(int status) Block<String[]> b2 = Arrays::sort; // void sort(Object[] a) Block<String> b3 = MyProgram::main; // void main(String... args) Runnable r = MyProgram::main; // void main(String... args)
  • 27. 方法參考(Method reference) • 特定物件實例方法 public class ComparisonProvider { public int compareByName(Person p1, Person p2) { ... } public int compareByAge(Person p1, Person p2) { ... } } ... ComparisonProvider comparisonProvider = ...; Arrays.sort(people, comparisonProvider::compareByName); • 實例方法中可帶物件狀態 – 相當於讓 Lambda 語法帶有狀態(Closure 的替代?)
  • 28. 方法參考(Method reference) • 任意類別的實例方法 List<String> names = Arrays.asList("Justin", ...); Collections.sort(names, (s1, s2) -> s1.compareToIgnoreCase(s2)); Collections.sort(names, String::compareToIgnoreCase);
  • 29. 方法參考(Method reference) • 讓 Lambda 語法的目標類型可以變換 Callable<String> c = () -> "done"; PrivilegedAction<String> a = c::call;
  • 32. 介面預設方法(Default method) • JDK8 前實作介面以實現多個規格的繼承來源 – 捨棄繼承多個實作來源的可能性,規避了多重繼承下實 作衝突等問題 public class Ball implements Comparable<Ball> { public boolean notEquals(Ball that) { return this.radius - that.radius; } // 底下都是根據notEquals()實作 public boolean lessThan(Ball that) { return this.notEquals(that) < 0; } public boolean lessOrEquals(Ball that) { return this.lessThan(that) || this.notEquals(that) == 0; } public boolean greaterThan(Ball that) { return !this.lessOrEquals(that); } ...
  • 33. 介面預設方法(Default method) • JDK8 介面可以是根據抽象的共用實作 public interface Comparable<T> { boolean notEquals(T that); boolean lessThan(T that) default { return this.notEquals(that) < 0; } boolean lessOrEquals(T that) default { return this.lessThan(that) || this.notEquals(that) == 0; } boolean greaterThan(T that) default { return !this.lessOrEquals(that); } ...
  • 34. 介面預設方法(Default method) • JDK8 可以實作具有預設方法的介面 public class Ball implements Comparable<Ball> { public boolean notEquals(Ball that) { return this.radius - that.radius; } ... • 實作可能發生衝突.. interface Robot implements Artist, Gun { void draw() default { Artist.super.draw(); } }
  • 35. 介面預設方法(Default method) • 擴充既有程式庫以搭配 Lambda 語法 – 僅在介面中新增方法定義? – 使用靜態方法?像是 Collections.filter(…)? – 獨立的新 API?像是 Collection2 框架? interface Iterator<E> { boolean hasNext(); E next(); void remove(); void skip(int i) default { for (; i > 0 && hasNext(); i--) next(); } }
  • 36. 擴充的 Collection 框架 • 高階函式 – 可讀性 – 簡潔性 – 導入新的抽象層 • 以迭代為例… for(Ball b : balls) { b.setColor(RED); } balls.forEach(b -> { b.setColor(RED); });
  • 37. 擴充的 Collection 框架 • 匿名類別作不到嗎? – 想分離關切點,但又帶入新的關切點 balls.forEach(new Block<Ball> { public void apply(Ball ball) { ball.setColor(RED); } }); • 傳入 Lambda 表示式,而非傳入不想要的雜訊
  • 38. 擴充的 Collection 框架 • 為什麼是 Collection 框架? • 許多問題都是資料處理問題… – 關聯式資料通常就是待處理資料群集… • filter、map、fold 等是處理資料時的高階抽象 – 過濾一組資料 – 將一組資料對應至另一組資料 – 逐一取得資料計算單一結果 – …
  • 39. 擴充的 Collection 框架 • 管線化(Piped)操作 int sum = names.filter(s -> s.length() < 3) .map(s -> s.length()) .reduce(0, (sum, len) -> sum + len); int sum = names.filter(s -> s.length() < 3) .map(s -> s.length()) .sum();
  • 40. 擴充的 Collection 框架 • 管線化(Piped)操作 blocks.filter(b -> b.getColor() == BLUE) .forEach(b -> { b.setColor(RED); }); List<Block> blue = blocks.filter(b -> b.getColor() == BLUE) .into(new ArrayList<>()); Set<Box> blueBlock = blocks.filter(b -> b.getColor() == BLUE) .map(b -> b.getContainingBox()) .into(new HashSet<>());
  • 41. 擴充的 Collection 框架 • 延遲(Laziness) int sum = blocks.filter(b -> b.getColor() == BLUE) .map(b -> b.getWeight()) .sum(); • 捷徑(short-circuiting) Block firstBlue = blocks.filter(b -> b.getColor() == BLUE) .getFirst();
  • 42. 擴充的 Collection 框架 • 共用的函式介面(java.util.functions) – Predicate – boolean test(T t) – Block – void apply(T t); – Mapper – U map(T t) – ...
  • 43. 擴充的 Collection 框架 • 已實作 filter、map 與 fold 的細節 – 循序? – 遞迴? – 共用資料結構? – 平行化? • 可以用更高階的抽象來處理資料 int sum = blocks.parallel() .filter(b -> b.getColor() == BLUE) .map(b -> b.getWeight()) .sum();
  • 44. 全部放在一起 for (Method m : enclosingInfo.getEnclosingClass().getDeclaredMethods()) { if (m.getName().equals(enclosingInfo.getName()) ) { Class<?>[] candidateParamClasses = m.getParameterTypes(); if (candidateParamClasses.length == parameterClasses.length) { boolean matches = true; for(int i = 0; i < candidateParamClasses.length; i++) { if (!candidateParamClasses[i].equals(parameterClasses[i])) { matches = false; break; } } if (matches) { // finally, check return type if (m.getReturnType().equals(returnType) ) return m; } } } } throw new InternalError("Enclosing method not found");
  • 45. 全部放在一起 Method matching = Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) .filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses)) .filter(m -> Objects.equals(m.getReturnType(), returnType)) .getFirst(); if (matching == null) throw new InternalError("Enclosing method not found"); return matching;
  • 46. 全部放在一起 List<Album> favs = new ArrayList<>(); for (Album a : albums) { boolean hasFavorite = false; for (Track t : a.tracks) { if (t.rating >= 4) { hasFavorite = true; break; } } if (hasFavorite) favs.add(a); } Collections.sort(favs, new Comparator<Album>() { public int compare(Album a1, Album a2) { return a1.name.compareTo(a2.name); }});
  • 47. 全部放在一起 List<Album> sortedFavs = albums.filter(a -> a.tracks.anyMatch(t -> (t.rating >= 4))) .sortedBy(a -> a.name) .into(new ArrayList<>());
  • 49. 函數式風格的可能性 • Lambda 語法在原語言中提供小型通用語言 • 在某些問題領域… – 提供以 λ 演算解題的可能性 • Java 在函數式程式設計(Functional Parogramming)的可能性?
  • 50. 函數式風格的可能性 • 費式數的定義 { F0 = 0, F1 = 1, Fn = Fn-1 + Fn-2 } • 指令式程式設計(Imperative programming)? int fib(int n) { int a = 1; int b = 1; for(int i = 2; i < n; i++) { int tmp = b; b = a + b; a = tmp; } return b; }
  • 51. 函數式風格的可能性 • 函數式程式設計? int fib(int n) { if(n == 0 || n == 1) return n; else return fib(n - 1) + fib(n - 2); } • 使用 Haskell fib 0 = 0 fib 1 = 1 fib n = fib (n-1) + fib (n-2)
  • 52. 函數式風格的可能性 • 函數式語言的特徵 fib 0 = 0 fib 1 = 1 – 一級函式 fib n = fib (n-1) + fib (n-2) – Immutable sum [] = 0 – Lazy evaluation sum (x:xs) = x + sum xs – Pattern match {2 * x | x ∈ {1, 2..100}} – List comprehension [2 * x | x <- [1, 2..100]] – Curried function f x y = x + y g y = f 1 y
  • 53. 函數式風格的可能性 • JDK8 有多少函數式風格的特性? – 直接支援 Lambda 語法 – 使用 final 變數強制 Immutable – 以 API 封裝複雜細節達到… – 延遲求值 – 模式匹配 – List comprehension – Partially applied 與 Curried function
  • 54. 函數式風格的可能性 • 以 API 封裝複雜細節,留下函數式外觀給使用者 – Functional Java(functionaljava.org) – 目的就是為了讓 Java 實現函數式風格 – 主要針對 JDK5 以上 – 使用匿名內部類別繼承抽象類別 final Array<String> a = array("Hello", "There", "what"); final boolean b = a.exists(new F<String, Boolean>() { public Boolean f(final String s) { return fromString(s).forall(isLowerCase); } }); boolean b = a.exists(s -> fromString(s).forall(isLowerCase));
  • 55. 函數式風格的可能性 • 以 API 封裝複雜細節,留下函數式外觀給使用者 – Guava(code.google.com/p/guava-libraries) – 主要目的並非為了讓 Java 實現函數式風格 – 主要針對 JDK5 以上 – 使用匿名內部類別實作介面
  • 56. 函數式風格的可能性 • Guava 目前不鼓勵函數式風格 Multiset<Integer> lengths = HashMultiset.create( FluentIterable.from(strings) .filter(new Predicate<String>() { public boolean apply(String string) { return CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string); } }) .transform(new Function<String, Integer>() { public Integer apply(String string) { return string.length(); } })); Multiset<Integer> lengths = HashMultiset.create( FluentIterable.from(strings) .filter(s -> CharMatcher.JAVA_UPPER_CASE.matchesAllOf(s)) .transform(s -> s.length()) ));
  • 57. 總結 • λ 語法為 Java 提供了小型通用語言,在某些問題 領域,提供 λ 演算解題的可能性 • 除 JDK 程式庫將搭配 λ 語法演化,開放原始碼如 Functional Java、Guava 等也將呈現不同風格 • 新的抽象層將平行化、函數式等實作予以封裝, 簡潔的表述能力,使開發者進一步思索 map、 filter、fold 等問題的基本形式
  • 58. 參考資料 • State of the Lambda v4 – http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html • State of the Lambda: Libraries Edition – http://cr.openjdk.java.net/~briangoetz/lambda/collections- overview.html • Project Lambda – http://openjdk.java.net/projects/lambda/ • Lambda calculus – http://en.wikipedia.org/wiki/Lambda_calculus • Functional Programming for Java Developers – http://shop.oreilly.com/product/0636920021667.do • APIO讲稿——函数式编程 – http://www.byvoid.com/blog/apio-fp/