JavaSE-Lambda表达式-01-201804
初步学习
(since JDK 1.8)
1.函数式编程:(x->f(x)),x到f(x)的映射关系。f(x)的值只取决于x。
函数式编程 | 命令式编程 | |
---|---|---|
关注点 | 映射关系 | 实现过程 |
x是否可变 | 否 | 是 |
有无循环 | 无(可使用递归) | 有 |
并行便利度 | 高 | 低 |
写法简洁度 | 高 | 低 |
2.函数接口
概念:只有一个抽象方法的接口。(用作Lambda表达式的类型)
注: a. jdk1.8后接口内可以有非抽象方法,此时函数接口实现不会对接这些方法。
b.当接口含有与Object内public类型方法相同的抽象方法时,这些方法不会影响函数接口的实现。
(原因:i. 所有函数接口的实现类必然也是Object的子类;
ii. 接口内抽象方法默认为public,如Object类中的protected Object clone()此时权限将扩大,与Object类中
clone() 方法签名不同,会影响影响函数接口的实现。)
3.Lambda表达式概念
实质是一个匿名函数(可传递的代码块)。
例: Runnable noArgs=()->System.out.println("noArgs");
解析:Runnable 接口只有一个abstract方法void run(),该接口可作为函数接口。()->System.out.println("noArgs"); 表示一个实 现了Runnable接口并重写其run()方法为System.out.println("noArgs")的类生成的一个对象。
4.Lambda表达式语法
a.无参单行
Runnable noArgs=()->System.out.println("noArgs");
b.无参多行
Runnable noArgs=()->{
System.out.println("no");
System.out.println("Args");
};
c.单参隐式
ActionListener al=event->System.out.println("clicked");
d.多参隐式
BinaryOperator<Integer> add=(x,y)->x+y;
e.显式
Comparator<String> comp=(String s1,String s2)->s1.length()-s2.length();
(此处类型String,可由泛型<String>推导出,实际可写作隐式。仅作展示显式语法)
f.带return字句
BinaryOperator<Integer> doubleX=(x,y)->{
if(x>y){
return x*2;
}
return y*2;
};
(注:若lambda表达式返回类型不为空,且在if中使用return字句,必须保证该代码块始终有返回值。)
5.Lambda表达式引用外部变量
jdk1.7及以前版本,局部内部类引用的外部变量必须为常量(final),而jdk1.8后局部内部类和Lambda表达式中对外部变量声明的要求放宽,不要求强制声明为final,但实际仍然为常量(Effectively final)。
int m=9;
//m=10; 若添加本行则编译不过,原因是lambda表达式引入的外部变量必须为实际常量(effective final)
//eclipse报错Local variable m defined in an enclosing scope must be final or effectively final
Tryone to=n->n*m; //Tryone是自定义的函数接口,接口方法int one(int x)
//Tryone to=n->{m=m+1;return m;};
System.out.println(to.one(5));
6.方法引用
概念:使用lambda表达式调用已存在的方法.
例:Runnable runQuo=System.out::println; // <==> ()->System.out.println();
将要使用的example环境:
interface Tryone {
int one(int n);
}
interface Two<T>{
T two(int n);
}
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
class TryAll implements Tryone{
int n;
public TryAll(int n) {this.n=n;}
public TryAll() {}
@Override
public int one(int n) {
// TODO Auto-generated method stub
return n*n;
}
@Override
public String toString() {
return "TryAll [n=" + n + "]";
}
}
a.引用类的静态方法--Class::staticMethod
Tryone to2=Math::abs; //取绝对值 [注意使用方法引用时参数类型需一致]/<==> n->Math.abs(n);
b.引用对象的实例方法--object::instanceMethod
Tryone to3=new TryAll();
Tryone to4=to3::one;
c.引用类型对象的实例方法--Class::instanceMethod
Arrays.sort(testStr, String::compareToIgnoreCase);
//等价于 Arrays.sort(testStr, (s1,s2)->s1.compareToIgnoreCase(s2)); //按字典顺序排序-lambda表达式的一般形式
注意: 1.引用对象的实例方法时,对象可以是this、super.
2.对于引用类型对象的实例方法,若实例方法是泛型的,可能需要在::前加泛型 。
3.对于引用类型对象的实例方法,若有多个同名重载方法,编译器会尝试从上下文中找出正确方法。
7.构造方法引用-- Class::new
应选择带泛型返回值或所需类型返回值的函数接口.
a.无参构造
Supplier<TryAll> supplier=TryAll::new; //Supplier接口是jdk1.8新增java.util.function包中的函数接口
System.out.println(supplier.get().toString());
b.带参构造
Two<TryAll> tryTwo=TryAll::new;
System.out.println(tryTwo.two(2).toString());
8.数组构造方法引用--TypeName::new
数组的构造方法引用的语法则比较特殊,可以假想存在一个接收int参数的数组构造方法。
即参数为int,返回类型为数组的函数接口。
Two<int[]> arrayMaker = int[]::new;
int[] array = arrayMaker.two(5); // 创建数组 int[5]
System.out.println(Arrays.toString(array));
参考资料:http://www.cnblogs.com/figure9/p/java-8-lambdas-insideout-language-features.html
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html