Java8:λ表达式作为实参
来源:互联网 发布:asp连接sql数据库代码 编辑:程序博客网 时间:2024/04/27 21:58
Java8 λ表达式的核心思想是Behavior parameterization(Java 8 in action)或SICP 1.3.1 Procedures as Arguments。本文说明Java8 λ表达式与Scheme的异同,并解释相关的概念。
1.靶子
SICP 1.3.1 Procedures as Arguments,给出的例子:“若干个函数拥有相似的算法或代码结构,请对此加以抽象”:
Scheme代码为:
(define (sum-integers a b) (if (> a b) 0 (+ a (sum-integers (+ a 1) b))))(define (pi-sum a b) (if (> a b) 0 (+ (/ 1.0 (* a (+ a 2))) (pi-sum (+ a 4) b))))
若干个函数可以用Java写出。
清单1package java8.passingCode;/** * 按照SICP 1.3.1的命名sum_integers求代数和,sum_cubes求立方数的代数和,pi求1/(1*3)+1/(5*7)+1/(9*11)+...的某些项的和 * * @author (yqj2065) * @version (0.1) */public class SomeSum{ public static double identity (int x){ return x; } public static double sum_integers(int a,int b){ int sum=0; for(int i =a;i<=b;i++){ sum+=identity(i); } return sum; } public static double cube(int x){ return x*x*x; } public static int sum_cubes(int a,int b){ int sum=0; for(int i =a;i<=b;i++){ sum+=cube(i); } return sum; } /** * the sum of a sequence of terms in the series 1/(1*3)+1/(5*7)+1/(9*11)+... */ public static double item(int x){ return 1.0/(x*(x+2)); } public static double pi(int a,int b){ double sum=0; for(int i =a;i<=b;i+=4){ sum+=item(i); } return sum; } public static void main(String[] a){ System.out.println(sum_cubes(1,10)); System.out.println(sum_integers(1,10)); System.out.println("pi="+8*pi(1,1000)); } }《Java 8 in action·Chapter 2. Passing code with behavior parameterization》给出了较为简单的例子,采用策略模式进行重构。
2.模板方法模式 Vs. 高阶函数
在Java8之前,可以采用模板方法模式重构清单1。
package java8.passingCode;/** * 模板类 */public abstract class Sum{ //template Method public final double getSum(int a,int b){ double sum=0; for(int i =a;i<=b; i= next(i)){ sum+=item(i); } return sum; } abstract public int next(int i); abstract public double item(int x); }而后,求代数和、求立方数的代数和,求pi需要分别编写模板类Sum的子类。
<pre code_snippet_id="1710335" snippet_file_name="blog_20160607_4_7574436" name="code" class="java">package java8.passingCode;public class Sum_pi extends Sum{ @Override public double item(int x) { return 1.0 / (x * (x + 2)); } @Override public int next(int i) { return i + 4; }}
package java8.passingCode;public class Test{ public static void main(String[] a) { System.out.println("pi=" + 8 * new Sum_pi().getSum(1, 1000)); }}
采用模板方法模式,使用纯粹的面向对象技术,实现了行为参数化。
进一步,将abstract Sum中的两个抽象方法放入两个接口NextInterface和ItemInterface得到Sum_8,注意,getSum(int a,int b,NextInterface iNext,ItemInterface iItem)中形参类型有两个接口。
<pre code_snippet_id="1710335" snippet_file_name="blog_20160607_4_7574436" name="code" class="java">package java8.passingCode;public class Sum_8 { public final double getSum(int a,int b,NextInterface iNext,ItemInterface iItem){ double sum=0; for(int i =a;i<=b; i=iNext.next(i)){ sum+=iItem.item(i); } return sum; }}
Scheme对上述函数加以抽象或一般化的技术为高阶函数。高阶函数(的一种形式是函数作为形参,高阶函数的另一种形式是返回一个函数)。高阶函数sum中包含了两个函数形参term和next。
(define (sum term a next b) (if (> a b) 0 (+ (term a) (sum term (next a) next b))))
小结:
- 行为参数化,在Java 8之前,通过多态/策略模式/模板方法模式已经可以实现。
- Java中getSum(NextInterface iNext)这种方法,如果形参类型为函数接口,是否适合称之为高阶函数呢?理论上,方法定义时,Java不存在高阶函数;而在方法使用者看来,System.out.println("sum_cube(1,10)="+ new Sum_8().getSum(1, 10,i->++i,x->x*x*x) ); 可以视为高阶函数。
3.人妖
Java8:λ表达式是匿名类的语法糖中说明:Java的λ表达式是一个(拥有省略了名字的函数的)某个函数接口的匿名(实现)类。(注意:这里是从Java语言层面给出的论断,正如Java的int类型为32位一样,不考虑JVM的具体实现)。但是,getSum的实参则是Java的λ表达式,使用起来的感觉,就是在传递函数!
Java的λ表达式不是函数式编程语言如Scheme中的λ表达式。
Scheme中的λ表达式是函数,Java的λ表达式是函数接口的实现类。
换言之,Java8 的目的,是让程序员认为Java的λ表达式是函数,如同让程序员认为人妖是女人。getSum的实参是Java的λ表达式,使用起来的感觉,就是在传递函数!
对于Java的λ表达式,我们与其认为它类似函数式语言的λ表达式,不如说它类似C语言的函数指针。
为了让程序员认为人妖是女人,Java的λ表达式需要配套的概念:函数接口、method references等。
例如函数接口:
package java8.passingCode;@FunctionalInterfacepublic interface ItemInterface{ public double item(int x); }
传递函数!
public class Test{ public static void main(String[] a) { System.out.println("pi=" + 8 * new Sum_pi().getSum(1, 1000)); System.out.println("sum_integers(1,10)=" + new Sum() { @Override public double item(int x) { return x; } @Override public int next(int i) { return ++i; } }.getSum(1, 10)); System.out.println("sum_cube(1,10)="+ new Sum_8().getSum(1, 10,i->++i,x->x*x*x) ); }}Test类中,出现了多种传递函数的方式:Sum_pi是独立的类,求代数和使用了Sum的匿名类;而求立方数的代数和使用了函数接口的实现——λ表达式,实参是Java的λ表达式。
4.进一步抽象
Sum_8依赖于NextInterface和ItemInterface两个函数接口,可以借用java.util.function.*预定义的函数接口。package java8.passingCode;import java.util.function.*;public class Sum_8 { /*public final double getSum(int a,int b,NextInterface iNext,ItemInterface iItem){ double sum=0; for(int i =a;i<=b; i=iNext.next(i)){ sum+=iItem.item(i); } return sum; }*/ public final double getSum(int a,int b,IntUnaryOperator iuo,Function<Double,Double> f){ double sum=0; for(int i =a;i<=b; i=iuo.applyAsInt(i)){ sum+=f.apply(1.0*i); } return sum; } }
在减少了两个函数接口的同时,applyAsInt(i)显然不如next(i)含义清晰。java.util.function.*预定义的函数接口,反映了一个事实:Java的λ表达式真的是人妖。
《Java 8 in action·Chapter 2》的例子,使用List<T>、Predicate<T>代替List<Apple>、ApplePredicate则非常合适。
- Java8:λ表达式作为实参
- 流作为函数实参
- 数组作为函数实参
- string 作为函数实参
- Java8:λ表达式的本质
- 将数组作为实参传递
- λ表达式之争:Scala vs Java8
- java8入门(一) --λ表达式
- C++ template -- 字符串作为函数模板实参
- 使用字符串作为函数模板的实参
- (转帖)二维数组作为实参时
- C++ 全局变量作为实参之传递问题
- 一个函数作为另一个函数的实参
- 数组作为函数实参时注意
- 【读书笔记】以函数作为算法的实参
- Java8 Lambda表达式教程
- Java8 Lambda表达式教程
- Java8: Lambda表达式语法
- ChemDraw使用不了怎么办
- 解决PL/SQL Developer查询结果乱码
- tjut 5296
- 全国第一家算法编程大赛倒计时(同行交流)
- copy 和 mutableCopy
- Java8:λ表达式作为实参
- Inside Qt Series (全集)
- RxVolley使用文档 —— RxVolley = Volley + RxJava + OkHttp
- android之ViewFlipper实现左右滑动动画效果
- Kalman滤波器从原理到实现
- loopback安装教程--Node.js Cannot find Module xxx 的问题
- MySql数据库导出导入csv文件
- 从linphone_address_new研究linphone
- 表格CSS使用