Java8闭包
闭包在很多语言中都存在,例如C++,C#。闭包允许我们创建函数指针,并把它们作为参数传递,Java编程语言提供了接口的概念,接口中可以定义抽象方法,接口定义了API,并希望用户或者供应商来实现这些方法,很多时候并不是为一些接口创建独立的实现类,我们通过写一个匿名的内部类来写一个内联的接口实现,匿名内部类使用相当的广泛,匿名内部类最常见的场景就是事件处理器了,其次匿名内部类还被用于多线程中,写匿名内部类而不是创建Runable\Callable接口的实现类。
一个匿名内部类就是一个内联的给定接口的实现,这个实现类的对象作为参数传递给一个方法,然后这个方法将在内部调用传递过来的实现类的方法,这种接口叫做回调接口,这个方法叫做回调方法。
匿名内部类很多地方都在使用,在使用的同时存在一些问题
- 复杂- 这些类代码的层级看起来很乱很复杂,称作Vertical Problem 
- 不能访问封装类的非final成员- this关键字变得很迷惑,如果一个匿名类有一个与其封装类相同的成员名称,内部类会覆盖外部的成员变量,在这种情况下,外部成员在匿名类内部是不可见的,甚至不能通过this来访问。 - 实例说明 - public void test() {
 String variable = "Outer Method Variable";
 new Thread(new Runnable() {
 String variable = "Runnable Class Member";
 public void run() {
 String variable = "Run Method Variable";
 System.out.println("->" + variable);
 System.out.println("->" + this.variable);
 }
 }).start();
 }
 输出- ->Run Method Variable 
 ->Runnable Class Member- 这个例子很好的说明了上面的两个问题,而Lambda表达式几乎解决上面的所有问题,我们讨论Lambda表达式之前,让我们来看看Functional Interfaces 
- Funcational Interfaces- 一个只有单个方法的接口,这代表了这个方法的契约。 
 
 The Single method cal exist in the form of multiple abstract methods that are inherited from superinterfaces.But in that case the inherited methods should logically represent a single method or it might redundantly declare a method that is provided by classes like Object,e.g.toString- > interface Runnable{void run();}
 > interface Foo {boolean equals(Object obj);}
 > interface extends Foo{ int compare(String s1,String s2)}
 > interface Comparetor{
 boolean equals(Object obj);
 int compare(T t1,T t2);
 } > interface Foo( int m(); Object clone();- 大多数回调接口都是Functional Interfaces,例如Runable,Callable,Comparetor等等,以前被称作SAM(Single Abstract Method) 
- Lambda- Lambda表达式实际上就是匿名类,只不过他们的结构更轻量,Lambda表达式看起来像方法。他们有一个正式的参数列表和这参数的块体表达式。针对上面的例子进行Lambda改造。
 - public class TestLambdaExpression{- public String variable ="Class level variable"; - public static void main(){- new TestLambdaExpression().test(); - } - public void test() {
 String variable = "Method local Variable";
 new Thread(() {
 public void run() -> {
 System.out.println("->" + variable);
 System.out.println("->" + this.variable);
 }
 }).start();
 }- } 
 输出- ->Method local Variable 
 ->Class level variable- 可以比较一些使用Lambda表达式和使用匿名内部类的区别,我们可以清楚的看出,使用Lambda表达式的方式写匿名内部类解决了变量可见性的问题,Lambda表达式不允许创建覆盖变量。 Lambda表达式的语法包括一个参数列表和“->”,为什么选择这样的语法形式,因为目前C#和Scala中通常都是这样的,也算是遵循了Lambda的通用写法,这样的语法基本上解决了匿名类的复杂性,同时也显得非常的灵活,目标接口类型不是一个表达式的一部分。编译器会帮助推断Lambda expression的类型与周围的环境,Lambda表达式必须有一个目标类型,而它们可以适配任意可能的目标类型,当然类型是一个接口的时候,下面的条件必须满足,才能编译正确。 - 接口应该是一个Funcational interface - 表达式的参数数量和类型必须与Functional interface中声明的一致 - 抛出的异常表达式必须兼容function interface中方法的抛出异常声明 - 返回值类型必须兼容function interface 中方法的返回值类型 - 由于编译器可以通过目标类型的声明中得知参数类型和个数,所以在Lambda表达式中可以省略类型的声明。 - 例如 - Comparetor c = (s1,s2) –> s1.comparteToIgnoreCase(s2); - 而且,如果目标类型中声明的方法只有一个参数,那么小括号也可以不写,例如 - ActionListenr listenr = event –> event.getWhen(); - 一个很明显的问题来了,为什么Lambda不需要指定方法名呢?因为Lambda expression只能用户Functional interface,而functional interface 只有一个方法。当我们确定一个functional interface来创建Lambda表达式的时候,编译器可以感知functional interface中的方法的签名,并且检查给定的表达式是否匹配。Lambda表达式的语法是上下文相关的,但并非在Java8中才出现,Java 7中添加了diamond operators也有这个概念,通过上下文推断类型。 - void invoke (Runable r) {r.run()} - Futrue invoke (Callable c) {return c.compute()} - Future s = invoke (() –> "done");//这个Lambda Expression显然是调用了带有futrue的这个接口 
- 方法引用- 方法引用被用作引用一个方法而不调用它,Lambda表达式允许我们定义一个匿名的方法,并将它作为Functional Inteface的一个实例。方法引用跟Lambda Expression很想,它们都需要一个目标类型,但是不同的方法引用不提供方法的实现,它们引用一个已经存在的类或者对象的方法。 - 1、System::getProperty - 2、"abc"::length - 3、String::length - 4、super::toString - 5、Arraylist::new - 这里引用了一个新的操作符"::"(双冒号)。目标引用或者说接收者被放在提供者和分隔符的后面,这形成了一个表达式,它能够引用一个方法。下面通过一个例子来了解这个操作符。 - 这是一个Employee数组的排序程序 - import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 public class MethodReference {
 public static void main (String[] ar){
 Employee[] employees = {
 new Employee("Nick"),
 new Employee("Robin"),
 new Employee("Josh"),
 new Employee("Andy"),
 new Employee("Mark")
 };
 System.out.println("Before Sort:");
 dumpEmployee(employees);
 Arrays.sort(employees, Employee::myCompare);
 System.out.println("After Sort:");
 dumpEmployee(employees);
 }
 public static void dumpEmployee(Employee[] employees){
 for(Employee emp : Arrays.asList(employees)){
 System.out.print(emp.name+", ");
 }
 System.out.println();
 }
 }
 class Employee {
 String name;
 Employee(String name) {
 this.name = name;
 }
 public static int myCompare(Employee emp1, Employee emp2) {
 return emp1.name.compareTo(emp2.name);
 }
 }- 输出: - Before Sort: Nick, Robin, Josh, Andy, Mark,
- After Sort: Andy, Josh, Mark, Nick, Robin,
 
- 构造方法引用- 先看看实例 - public class ConstructorReference {
 public static void main(String[] ar){
 MyInterface in = MyClass::new;
 System.out.println("->"+in.getMeMyObject());
 }
 }
 interface MyInterface{
 MyClass getMeMyObject();
 }
 class MyClass{
 MyClass(){}
 }- 输出 - ->com.MyClass@34e5307e - 这看起来有点神奇吧,这个接口和这个类除了接口中声明的方法的返回值是MyClass类型的,没有任何关系。这个例子又激起了我心中的另一个问题:怎样实例化一个带参数的构造方法引用?看看下面的程序: - public class ConstructorReference {
 public static void main(String[] ar){
 EmlpoyeeProvider provider = Employee::new;
 Employee emp = provider.getMeEmployee("John", 30);
 System.out.println("->Employee Name: "+emp.name);
 System.out.println("->Employee Age: "+emp.age);
 }
 }
 interface EmlpoyeeProvider{
 Employee getMeEmployee(String s, Integer i);
 }
 class Employee{
 String name;
 Integer age;
 Employee (String name, Integer age){
 this.name = name;
 this.age = age;
 }
 }- 输出是: - ->Employee Name: John 
 ->Employee Age: 30
- Default Method- Java8中将会引入一个叫做默认方法的概念,早期的Java版本的接口拥有非常的严格的接口,接口包含了一些抽象方法的声明,所有非抽象的实现类必须要提供所有这些抽象方法的实现,甚至是这些方法没有用或者不合适出现在一些特殊的实现类中。在即将到来的Java 版本中,允许我们在接口中定义方法的默认实现。 - public class DefaultMethods {
 public static void main(String[] ar){
 NormalInterface instance = new NormalInterfaceImpl();
 instance.myNormalMethod();
 instance.myDefaultMethod();
 }
 }
 interface NormalInterface{
 void myNormalMethod();
 void myDefaultMethod () default{
 System.out.println("-> myDefaultMethod");
 }
 }
 class NormalInterfaceImpl implements NormalInterface{
 @Override
 public void myNormalMethod() {
 System.out.println("-> myNormalMethod");
 }
 }- 输出 - -> myDefaultMethod - 在这个例子中,ParentInterface 定义了两个方法,一个是正常的,一个是有默认实现的,子接口只是简单的反了过来,给第一个方法添加了默认实现,给第二个方法移除了默认实现。 - 设想一个类继承了类 C ,实现了接口 I ,而且 C 有一个方法,而且跟I中的一个提供默认方法的方法是重载兼容的。在这种情况下,C中的方法会优先于I中的默认方法,甚至C中的方法是抽象的时候,仍然是优先的。 - public class DefaultMethods {
 public static void main(String[] ar){
 Interfaxe impl = new NormalInterfaceImpl();
 impl.defaultMethod();
 }
 }
 class ParentClass{
 public void defaultMethod() {
 System.out.println("->ParentClass");
 }
 }
 interface Interfaxe{
 public void defaultMethod() default{
 System.out.println("->Interfaxe");
 }
 }
 class NormalInterfaceImpl extends ParentClass implements Interfaxe{
 }- 输出: - -> ParentClass - 第二个例子是,实现了两个不同的接口,但是两个接口中都提供了相同的具有默认实现的方法的声明。在这种情况下,编译器将会搞不清楚怎么回事,实现类必须选择两个的其中一个实现。这可以通过如下的方式来使用super来搞定。 - public class DefaultMethods {
 public static void main(String[] ar){
 FirstInterface impl = new NormalInterfaceImpl();
 impl.defaultMethod();
 }
 }
 interface FirstInterface{
 public void defaultMethod() default{
 System.out.println("->FirstInterface");
 }
 }
 interface SecondInterface{
 public void defaultMethod() default{
 System.out.println("->SecondInterface");
 }
 }
 class NormalInterfaceImpl implements FirstInterface, SecondInterface{
 public void defaultMethod(){
 SecondInterface.super.defaultMethod();
 }
 }- 输出 - ->SecondInterface
Java8闭包的更多相关文章
- Java8函数接口实现回调及Groovy闭包的代码示例
		本文适用于想要了解Java8 Function接口编程及闭包表达式的筒鞋. 概述 在实际开发中,常常遇到使用模板模式的场景: 主体流程是不变的,变的只是其中要调用的具体方法. 其特征是: Begi ... 
- Java8-Function使用及Groovy闭包的代码示例
		导航 定位 概述 代码示例 Java-Function Groovy闭包 定位 本文适用于想要了解Java8 Function接口编程及闭包表达式的筒鞋. 概述 在实际开发中,常常遇到使用模板模式的场 ... 
- Java8的新特性以及与C#的比较
		函数式接口 VS 委托 在C中,可以使用函数指针来存储函数的入口,从而使得函数可以像变量一样赋值.传递和存储,使得函数的调用变得十分灵活,是实现函数回调的基础.然而函数指针不存在函数的签名信息,甚至可 ... 
- JAVA8 十大新特性详解
		前言: Java8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章, 例如Playing with Java ... 
- java8新特性全面解析
		在Java Code Geeks上有大量的关于Java 8 的教程了,像玩转Java 8--lambda与并发,Java 8 Date Time API 教程: LocalDateTime和在Java ... 
- Java8新特性【转】
		地址:http://ifeve.com/java-8-features-tutorial/ 1.简介 毫无疑问,Java 8是自Java 5(2004年)发布以来Java语言最大的一次版本升级,Ja ... 
- java8 新特性
		[转载]:http://www.importnew.com/11908.html 本文由 ImportNew - 刘 家财 翻译自 javacodegeeks.欢迎加入翻译小组.转载请见文末要求. 编 ... 
- lambda表达式和闭包
		lambda表达式和闭包 熟悉的Javascript或者Ruby的同学,可能对另一个名词:闭包更加熟悉.因为一般闭包的示例代码,长得跟lambda差不多,导致我也在以前很长一段时间对这两个概念傻傻分不 ... 
- Java8 Lamdba表达式  001
		在一个已经存在的编程语言里非常少有对现有的生态系统起重大影响的新特性.Lambda表达式对于Java语言就是这样的意义的存在.简单来说,Lambda表达式提供了便利的方式去创建一个匿名的功能.提供了一 ... 
随机推荐
- 准备上线,切换到master分支,报错
			切换到master分支,准备上线,把上次上线sourceTree保存的修改拉出来: 运行,报错了: stackOverflow一搜说要删除旧的: 我show in finder 把他删了,然后双击安装 ... 
- oauth基本流程和原理
			组装loginurl->去第三方登录验证->回调callbackurl+code(票据)->本地根据code+appid+appkey组装url隐式curl获取用户信息->完成 ... 
- 个人理解java的继承
			java的类是属于单继承的.在继承这一块上我本来有一个很大的误区,就是觉得父类中private定义的成员无法被继承.直到网上的大神给我指出private是可以被继承的,会在内存中,只是在子类的对象中不 ... 
- iOS开发UI篇—iPad和iPhone开发的比较
			一.iPad简介 1.什么是iPad 一款苹果公司于2010年发布的平板电脑 定位介于苹果的智能手机iPhone和笔记本电脑产品之间 跟iPhone一样,搭载的是iOS操作系统 2.iPad的市场情况 ... 
- 五子棋AI清月连珠开源
			经过差不多两年的业余时间学习和编写,最近把清月连珠的无禁手部分完善得差不多了.这中间进行了很多思考,也有很多错误认识,到现在有一些东西还没有全面掌握,所以想通过开源于大家共同交流. 最近一直发表一些五 ... 
- 转:PostgreSQL Cheat Sheet
			PostgreSQL Cheat Sheet CREATE DATABASE CREATE DATABASE dbName; CREATE TABLE (with auto numbering int ... 
- java 关键字查询时的转义操作
			/** * mysql模糊查询时,如果查询关键字本身包含_和%,需要转义 * * @param queryKey 查询关键字 * @return 转义字符 */ private String conv ... 
- An error occurred while processing an SVN command
			今天在使用SmartSVN的时候,遇到这个问题,反复几次,也没有得到解决,而且进入了死循环,一直在提示这个消息,即使在cleanup之后. 百度了一番之后,找到了解决办法: 把出错的文件在本地删除掉, ... 
- 【转载】Mysql 查看连接数,状态
			转载地址:http://blog.csdn.net/starnight_cbj/article/details/4492555 命令: show processlist; 如果是root帐号,你能看到 ... 
- django学习遇到的问题解决方式
			1.django.core.exceptions.ImproperlyConfigured: The TEMPLATE_DIRS setting must be a tuple. Please fix ... 
