`
rensanning
  • 浏览: 3548793 次
  • 性别: Icon_minigender_1
  • 来自: 大连
博客专栏
Efef1dba-f7dd-3931-8a61-8e1c76c3e39f
使用Titanium Mo...
浏览量:38151
Bbab2146-6e1d-3c50-acd6-c8bae29e307d
Cordova 3.x入门...
浏览量:607316
C08766e7-8a33-3f9b-9155-654af05c3484
常用Java开源Libra...
浏览量:682345
77063fb3-0ee7-3bfa-9c72-2a0234ebf83e
搭建 CentOS 6 服...
浏览量:89356
E40e5e76-1f3b-398e-b6a6-dc9cfbb38156
Spring Boot 入...
浏览量:401858
Abe39461-b089-344f-99fa-cdfbddea0e18
基于Spring Secu...
浏览量:69695
66a41a70-fdf0-3dc9-aa31-19b7e8b24672
MQTT入门
浏览量:91723
社区版块
存档分类
最新评论

Java 8 之 Lambda表达式

    博客分类:
  • Java
阅读更多
Java 8历时2年8个月,这次升级是继Java 5之后对Java一次脱胎换骨的变化。在Java 8的新特性中很多都是围绕Lambda表达式而提供的,Lambda表达式也将使热衷于OOP(Object-Oriented Programming)的Java程序员体会到FP(Functional Programming)的强大。Java 8的Lambda表达多少借鉴了Scala的Lambda(Scala使用「=>」Java8使用「->」),和纯正FP的Haskell还是有很大差别。

(1)历史来由

①关于Java7/Java8
Java 8的很多新特性按照预定都应该包含在Java 7中,但是由于对Project Lambda和Project Jigsaw的争论一直没有达成共识,Java 7一直无法发布。2010年9月Java平台首席架构师Mark Reinhold在他的Blog上提出2个方案
  • A:所有功能都包含到Java 7中,发布推迟到2012年中旬
  • B:不包含Project Lambda和Project Jigsaw等几个项目Java 7在2011年中旬发布,这几个项目推迟到2012年中旬发布的Java 8中
博客的评论基本上都赞成方案B。2010年的JavaOne上Mark Reinhold正式决定采用方案B。之后2011年7月Java 7正式发布。

2012年7月 Mark Reinhold再次发文称Project Jigsaw将不会包含在Java 8中而得推迟到Java 9中,由此一来Java 8的主要特性就是Project Lambda。

2012年下旬->2013年下旬->2014年3月 Java 8的发布也是不断跳票。Project Coin、Collection Literals、Swing Date Picker等也被推迟到Java 9,而把Date & Time API、Nashorn等纳入Java 8中。

2014年3月18日 Java 8带着“即使有Bug也要发布”的节奏,历时2年8个月终于发布了。JavaTM SE 8 Release Contents

②关于Project Lambda
2005年,Java 6发布前很多人提议在Java中引入闭包Closure,先是Gilad Bracha、Neal Gafter、James Gosling、Peter van der Ahé做了一个Java闭包的提案,叫BGGA(以他们名字的首字母命名)、后来改名Closures for the Java Programing Language。关于这个提案在Java社区掀起了很到争论,Neal Gafter和Joshua Bloch争论最为有名。

除BGGA外,Java闭包的实现也有很多其他的方案,比如:Joshua Bloch、Doug Lea、Bob Lee提出了CICE(Concise Instance Creation Expresions)。还有一个提案是FCM(First Class Methods)。CICE并不是要在Java中引入闭包而是对匿名类做一个简化写法的提案(现在最终的Project Lambda也是很接近CICE)。

2008年在java.net做了一个在线调查,大概2000人参与回答,大部分人投给了BGGA或者干脆不引入闭包。

2008年11月,Mark Reinhold在 Devoxx 发布Java 7中不会引入闭包,从而才终止了这场争论。但是1年后的2009年11月Mark Reinhold同样是在 Devoxx 发布Java 7中要引入简单的闭包。基于此,2009年12月作为OpenJDK的子项目Project Lambda开始启动。



为什么2008年终止在Java 7中引入闭包会在2009年再次提出?
答案是:CPU多核化的趋势。无论是PC还是SmartPhone,CPU的多核化在急速发展,所以软件的并行处理也要跟得上。

Java中虽然可以通过Thread来并行处理,但是Java 5的Concurrency Utilities的处理粒度更大,而Java 7的Fork/Join Framework并行粒度更细。Java的for循环采用外部迭代(程序员自己写代码),需要转成内部迭代(由Java类库迭代)的并行化,而很多语言都已经支持内部迭代。虽然Java可以借助匿名类来实现,但是写法很繁琐,所以需要简化匿名类的写法。

2009年Project Lambda成立后,Mark Reinhold提出了一个原案Straw-Man Proposal。在这个稻草人提议中Mark Reinhold并没有使用以前争论不休的闭包,而是采用了Lambda表达式。基于此草案不断演化才得到了现在Java8的Lambda表达式。JSR 335: Lambda Expressions for the Java™ Programming Language

接口的变化:
开始决定使用SAM(Single Abstract Method)来作为接口,SAM指只有一个方法的抽象类或接口。但函数型的引入又激起了争论,后来只限于接口,所以很少人再说SAM,而是引入了函数式接口的概念。

写法的变化:
#(参数) { 函数体 } -> (参数) -> { 函数体 }
Collections.xxxx() -> Stream API

实现的变化
匿名类 ->Java 7 引入的 InvokeDynamic命令动态生成Class

Project Lambda是一个漫长的过程,能够最终成行已经不易,看看这些人的名字,他们都是Java界的大神,尤其Doug Lea为Java并发做出了不可磨灭的贡献。

(2)Lambda表达式

λ:希腊字母表中排序第十一位的字母,英语名称为Lambda。最早出现是用于计算的λ演算(lambda calculus),后来被函数式编程语言广泛采用。

Lambda表达式可以理解成为是一个能够作为参数传递的匿名函数Object,他没有名字,但有参数列表、有函数体、有返回类型、可以抛出异常。它的类型,叫做“目标类型(target type)”Java8中就是“函数接口(functional interface)”。

语法:
引用
(parameters) -> expression
(parameters) -> statement
(parameters) -> { statements; }


举例:
引用
() -> Math.PI * 2.0
(int i) -> i * 2
(String s) -> s.length()
(int i0, int i1) -> i0 + i1
(int x, int y) -> { return x + y; }


①省略类型
(int x, int y) -> { return x + y; };
(x, y) -> { return x + y; };

***不能只省略一部分类型,比如:(int x, y) -> { return x + y; }; // NG

②1个参数可以省略括号
(String text) -> { System.out.println(text); };
(text) -> { System.out.println(text); };
text -> { System.out.println(text); };

***但是不能带类型,比如:String text -> { System.out.println(text); }; // NG

③函数体多行时需要大括号
(int i) -> {
    int prod = 1;
    for(int n = 0; n < 5; n++) prod *= i;
    return prod;
};


④函数体只有一行的话可以省略大括号
text -> System.out.println(text);

***assert语句不能省略带括号,比如: s -> { assert !s.isEmpty(); };
***return语句不能省略带括号,比如:(x, y) -> return x -y; // NG

⑤只有一行代码而且有返回值的可以省略return,会返回该行代码计算结果
(x, y) -> { return x -y; };
(x, y) -> x -y;

***return要和大括号一起省略,比如:(x, y) -> { x - y; }; // NG

⑥没有参数没有返回值的空函数
() -> {}; 


⑦Scala等使用下划线做占位符,Java8中不可以
(_) -> System.out.println(_); // NG


⑧用于Lambda的变量不可变
int portNumber = 1337;
Runnable r = () -> System.out.println(portNumber); // OK

// 编译错误
// Local variable portNumber defined in an enclosing scope must be final or effectively final
int portNumber = 1337;
Runnable r = () -> System.out.println(portNumber); // NG
portNumber = 1338;

// 通过数组实现
final int[] wrappedNumber = new int[] { 1337 };
Runnable r = () -> System.out.println(wrappedNumber[0]); // OK
wrappedNumber[0] = 1338;


⑨其他
  • 一个λ表达式可以有多个目标类型(函数接口),只要函数匹配成功即可。但需注意一个λ表达式必须至少有一个目标类型。
  • 一个λ表达式可以被当做Object使用,需要赋值给一个函数接口,然后再赋值给一个Object。

(3)Lambda和匿名类区别
this:匿名类this取得是自己,Lambda取得是所在的外部类。
public class LambdaTest {
    public LambdaTest() {
        Function func1 = new Function() {
            @Override
            public void func() {
                System.out.println("Anon Class: " + this.getClass());
            }
        };
        Function func2 = () -> System.out.println("Lambda Exp.: " + this.getClass());
    }
}

****但是很少需要在lambda中使用this

(4)用于何处
Lambda可以传递给任何希望是函数式接口的地方。

(5)运行机制
Java 7引入了invokedynamic指令,它是一个JVM指令,允许动态语言在run-time时动态绑定。Java 8的Lambda表达式并不是匿名类的语法糖,它不会在编译的时候生成类似于匿名类的xxx$1.class,而是在运行的时候使用invokeDynamic指令。对于一条Lambda表达式在class里边会包含一个invokedynamic命令和一个静态方法。运行时会使用LambdaMetafactory#metafactory做成一个Lambda$1的内部类再调用该函数式接口的实例。在运行时生成class,就是避免class太多影响加载速度,像Stream那样的到处是Lambda。



比如遍历List:
Arrays.asList("a", "b", "c").forEach(x -> System.out.println(x));


编译后的Class内容:




也可以接住异常堆栈信息看看Lambda是怎么执行的:
String[] datas = new String[]{""};
Arrays.asList(datas).stream().forEach(name -> check(name));

public static int check(String s) {
    if (s.equals("")) {
        throw new IllegalArgumentException();
    }
    return s.length();
}


引用
Exception in thread "main" java.lang.IllegalArgumentException
    at com.rensanning.java8.lambda.Test.check(Test.java:14)
    at com.rensanning.java8.lambda.Test.lambda$0(Test.java:9)
    at com.rensanning.java8.lambda.Test$$Lambda$1/518248.accept(Unknown Source)
    at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    at com.rensanning.java8.lambda.Test.main(Test.java:9)


参考:
http://www.oracle.com/events/us/en/java8/index.html
http://www.lambdafaq.org/
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html
http://www.dreamsyssoft.com/java-8-lambda-tutorial/index.php
http://www.slideshare.net/bitter_fox/java8-launch
http://www.slideshare.net/miyakawataku/lambda-meets-invokedynamic
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
http://www.slideshare.net/mariofusco/fp-in-java-project-lambda-and-beyond
http://www.journaldev.com/2389/java-8-features-for-developers-lambdas-functional-interface-stream-and-time-api
  • 大小: 1.8 KB
  • 大小: 3.1 KB
  • 大小: 8.3 KB
  • 大小: 48.1 KB
分享到:
评论
2 楼 rensanning 2015-07-02  
Function这里用的可能不恰当,但只是个示例,具体是Runnable 无参无返回;Supplier 无参有返回;Function 有参有返回。
1 楼 JimmyLincole 2015-07-02  
Function func2 = () -> System.out.println("Lambda Exp.: " + this.getClass());

这一句应该是有问题的
一个是参数,一个是返回值

相关推荐

    Java8的lambda表达式

    Java8的Lambda表达式是Java语言的一次重大更新,它引入了函数式编程的概念,极大地简化了处理匿名函数的方式,特别是在处理集合和并发操作时。Lambda表达式使得代码更加简洁、易读,同时也提升了程序的执行效率。在...

    java8 lambda表达式学习总结

    1. **类型推断**:Java 8 可以自动推断Lambda表达式的参数类型,因此在许多情况下,我们无需显式声明类型。 2. **捕获外部变量**:Lambda 表达式可以访问和修改其定义范围内的 final 或基本类型的局部变量。 3. **...

    java8lambda表达式Demo

    Java 8 是一个重要的Java平台版本,因为它引入了许多新特性,其中最显著的就是Lambda表达式。Lambda表达式是函数式编程的关键元素,它允许我们以更简洁、更易读的方式编写代码,特别是在处理集合和并发任务时。在这...

    Java 8 lambda表达式

    Java 8 的引入,尤其是Lambda表达式,对Java语言产生了深远的影响,它为Java开发者带来了更简洁、更灵活的编程方式。Lambda表达式是函数式编程的核心元素,它允许我们将函数作为方法参数传递,或者将代码块当作数据...

    Java8的Lambda表达式

    Java 8引入了Lambda表达式,这是一种简洁的编写代码的方式,可以将代码块作为参数传递给方法,或者作为赋值给变量的对象。Lambda表达式为Java增加了函数式编程的能力,使代码更加简洁和灵活。在Java 8中,Lambda...

    Java8之lambda表达式基本语法

    Java8之lambda表达式基本语法 Java8中引入的lambda表达式是一种非常强大的语言特性,它可以使我们的代码变得更加简洁、灵活和高效。lambda表达式可以看作是一个匿名函数,可以作为参数传递给方法,也可以直接作为...

    java8中的Lambda表达式

    Java 8 中的 Lambda 表达式是语言的重大更新,它引入了函数式编程的概念,使得代码更加简洁、易读。Lambda 表达式的主要目的是简化处理匿名内部类的情况,尤其是当这些类只需要一个方法时。 在传统的 Java 编程中,...

    【Java8】Lambda表达式 和 Stream API 详解笔记.zip

    【Java8】Lambda表达式 和 Stream API 是Java编程语言中的两个重要创新,它们极大地提升了代码的简洁性和可读性,特别是在处理集合数据时。这里我们将深入探讨这两个特性,并结合实际示例来理解它们的工作原理。 ...

    JAVA 8 Lambda表达式-Lambda Expressions.rar

    Java 8 的 Lambda 表达式是 Java 编程语言的重大革新,它引入了一种新的函数式编程概念,使得代码更加简洁、可读性更强。Lambda 表达式允许我们将函数作为一个方法参数,或者把函数作为方法返回值,极大地简化了处理...

    JavaLambda表达式和匿名类.pdf

    Java 8 引入了Lambda表达式,这是对传统编程方式的一大革新,它极大地简化了函数式编程,尤其是在处理集合和并发操作时。Lambda表达式是Java 8中的一种语法糖,它允许开发者以更简洁的方式定义无状态、无副作用的...

    java8-lambda表达式的基础使用.pdf

    Java 8 中的 Lambda 表达式是 Java 8 中最流行最常用的功能特性之一。它将函数式编程概念引入 Java,函数式编程的好处在于可以帮助我们节省大量的代码,非常方便易用,能够大幅度的提高我们的编码效率。 Lambda ...

    java8之lambda表达式用法总结

    Java8之lambda表达式用法总结 lambda 表达式是 Java8 中的一种新的语法特性,它允许开发者以简洁的方式表示可传递的匿名函数。Lambda 表达式的基本语法是 `(parameters) -&gt; expression` 或 `(parameters) -&gt; { ...

    java lambda 表达式(语言篇和类库篇)

    Java 8的`java.time`包引入了新的日期和时间API,其中很多操作也支持Lambda表达式,如`LocalDateTime.now().filter(date -&gt; date.getDayOfWeek() == DayOfWeek.SATURDAY)`。 5. **CompletableFuture**: `...

    Java lambda表达式和JVM字节码功能详解.pdf

    Java Lambda表达式是Java 8引入的一个重要特性,它极大地简化了函数式编程风格的实现。Lambda表达式允许我们将函数作为一个值传递,就像传递其他数据类型一样。这在处理集合、事件驱动编程以及多线程等场景下尤其...

    2_Lambda表达式.zip

    Lambda表达式是Java编程语言中的一个关键特性,自Java 8开始引入,它极大地简化了函数式编程,尤其是在处理集合数据时。Lambda表达式的主要目的是为了创建匿名函数,即没有名字的函数,它可以被当作一个值传递给方法...

    精通lambda表达式 Java多核编程

    关于Java中lambda的表达式,Java多核编程,清华大学(出版)

    Java8新特性之Lambda表达式和Optional类

    Java 8 新特性之 Lambda 表达式和 Optional 类 Java 8 是 Java 语言的最新版本之一,它引入了许多新的特性,包括 Lambda 表达式和 Optional 类,这些特性极大地提高了 Java 语言的编程效率和可读性。下面我们将详细...

Global site tag (gtag.js) - Google Analytics