java1.8 lambda表达式 函数式编程 闭包

来源:互联网 发布:阿里云测试培训 编辑:程序博客网 时间:2024/05/16 05:29

java1.8出来好久一直没怎么关注。这段时间公司的项目数据处理,需要频繁操作集合,用for遍历集合做计算,感觉很费劲,而且有大量重复代码。可读性也不高。这时候想到java1.8新特性之一:函数式编程

一、函数式接口 (functional interface)

@FunctionalInterfaceinterface DoSomeThing {    int getAge(int a, int b);    static void getName() {        System.out.println("函数式接口的静态方法");    }    default void getAge() {        System.out.println("函数式接口的默认方法");    }}
@FunctionalInterface 可以不用加该注解,编译的时候,对于只有一个抽象方法的接口,默认就是函数式接口。

如果一个方法接受一个函数式接口作为参数,那么我们可以传入以下类型作为参数:

  • 匿名内部类(Anonymous Inner Class)(Java的以前版本中经常使用的方式,在Java 8中不再被推荐
  • Lambda表达式
  • 方法或者构造器的引用(Method or Constructor Reference

二、闭包(closure)(回顾)

lambda表达式大量用到了闭包和函数回调,java1.8之前不支持显性闭包,要实现代码片段的传递,只能通过内部类的方式,模拟闭包。

闭包简而言之就是 含有状态的函数。

在java语言中,闭包的应用:一个代码段被用来做为方法的参数.
java中没有直接使用某个方法做为另一个方法的参数的,java使用匿名内部类来模拟这种情况。


比如一个二元函数 f _x,y,x,y是函数内部使用的变量,在只给定 一个参数 x = 7 的情况下, x 已经绑定,但是y还是自由的,这个时候 f(7, y) 就相当于含有一个私有变量(x=7)的函数了。当再给定另外一个变量 y 的值就可对函数完整的求值。所以函数中 有的参数是绑定的,有的参数自由的,这样的机制称为闭包。

闭包的价值在于可以作为函数对象或者匿名函数,持有上下文数据,作为第一级对象进行传递和保存。闭包中的部分变量没有在引用者的作用域内声明,对于引用者这些变量就是自由变量。java中能够保存方法的变量指的就是普通的对象。Java最常用的闭包实现办法(内部类+接口)。通俗点讲:内部类的方法既能引用宿主的私有变量,又能传入主动调用者的变量(包括 指向对象(该对象可以抽象出接口:自定义回调函数)的变量),该内部类也可抽象出接口便于扩展。内部类的模拟闭包机制还实现了窥内的效果。

由于闭包上下文中有引用指向了内部类的宿主,所以宿主对象在没有其他引用的情况下也不会被销毁,只有该闭包中的回调函数执行完,才会被GC回收。

 [在A作用域中使用的变量x(A一般为主线程的方法,主动调用者),却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量],比如fun(x,y){},x和y是函数自己定义的,就不是自由变量,如果x是使用其他函数定义的,就是自由变量


总结:了解完闭包之后,我们知道在java1.8中不需要用内部类的方式实现闭包。

Lambda表达式会被编译器转换成相应函数式接口的一个实例,它表达式提供了一个上下文环境,既能引用该实例作用域的变量,又可以引用主程序所在作用域的所有变量。这种效果就是闭包,该实例中的变量就是自由变量。

闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会徒增内存消耗


http://blog.csdn.net/hnust_xiehonghao/article/details/46326997


根据groovy中的闭包来理解

一个groovy闭包就像一个代码块或者方法指针,他是定义然后执行的一段代码,但是他有一些特性:隐含变量,支持自由变量,支持currying 。

我们先来看看一些例子:

1def clos = { println "hello!" }
2 
3println "Executing the Closure:"
4clos() //prints "hello!"

在上面的例子中”hello!”是因为调用clos()函数才打印出来的,而不是在定义的时候打印出来的。

参数

闭包的参数在->之前列出,比如:

1def printSum = { a, b -> print a+b }
2printSum( 57 //prints "12"

如果闭包的参数是少于2个的话,那么 ->是可以省略的。

Parameter notes

A Closure without -> , i.e. {} , is a Closure with one argument that is implicitly named as ‘it’. (see below for details) In some cases, you need to construct a Closure with zero arguments, e.g. using GString for templating, defining EMC Property etc. You have to explicity define your Closure as { -> } instead of just { }

You can also use varargs as parameters, refer to the Formal Guide for details. A JavaScript-style dynamic args could be simulated, refer to the Informal Guide.

自由变量

闭包能引用在参数列表中没有列出的变量,这些变量成为自由变量,他们的作用范围在他们定义的范围内:

1def myConst = 5
2def incByConst = { num -> num + myConst }
3println incByConst(10// => 15

另外一个例子:

1def localMethod() {
2 def localVariable = new java.util.Date()
3 return println localVariable }
4}
5 
6def clos = localMethod()
7 
8println "Executing the Closure:"
9clos() //prints the date when "localVariable" was defined

隐式变量

it

如果你有一个闭包但是只有一个参数,那么你可以省略这个参数,比如:

1def clos = { print it }
2clos( "hi there" //prints "hi there"