什么是Lambda表达式?
在一般数学计算中lambda表达式就是一个函数,为部分或者所有输入值指定一个输出值,在java中Lambad表达式是以函数的概念引入,可以理解为一种语法更加紧凑的匿名方法,并且允许省略修饰符,返回类型并且某种情况下的参数类型。
语法:
lambda基本语法:
1
2
3
( parameters ) -> expression
or
( parameters ) -> { statements ; }
Examples:
1
2
3
4
5
6
( int x , int y )-> x + y //取整数x,y并返回它们的和
( x , y ) -> x - y //取整数x,y并返回它们的差
() -> 42 //不取任何值,直接返回42
( String s ) -> System . out . println ( s ) //取字符串s,在控制台打印,不返回任何值。
x -> 2 * x //取一个数字,返回它的2倍
c -> { int s = c . size (); c . clear (); return s ; } //取集合c,清空它,然后返回它清空前的大小
语法说明
1.参数类型可以显式声明(ex.1,4)或者隐式推断(ex.2,5,6),显式声明和隐式推断参数不允许用在同一个lambda表达式。
2.lambda body可以是一个block({}大括号包含代码块ex.6)或者是一个表达式(ex.1-5)。block body可以返回值(ex.6)
或者什么都不返回()。
3.如果lambda body是一个表达式,它也可能返回值(ex.1,2,3,5)或者什么都不返回(ex.4)。
4.隐式推断可以省略()(ex.5,6)。
5.ex.6 lambda能操作一个集合,同样的,根据上下文给定的参数,如果一个参数a拥有size和clear方法,
它也能操作并返回其类型的值。
函数式接口
Lambda表达式如何匹配Java的类型系统?每一个lambda都能够通过一个特定的接口,与一个给定的类型进行匹配。
一个所谓的函数式接口必须要有且仅有一个抽象方法声明(java8允许接口有默认方法)。每个与之对应的lambda表达式必须要与抽象方法的声明相匹配。
1、一个可以接受Lambda表达式的接口只能有一个抽象方法,否则在编译时将抛出异常。
2、为了显示的说明某接口是可使用lambda表达式,可以使用 @FunctionalInterface
注解该接口。
1
2
3
4
5
6
7
8
9
10
11
12
@FunctionalInterface
interface Converter < F , T > {
T convert ( F from ); //抽象方法只能一个
default double sqrt ( int a ) { //可以多个接口默认方法
return Math . sqrt ( a );
}
}
Converter < String , Integer > converter = ( from ) -> Integer . valueOf ( from );
Integer converted = converter . convert ( "123" );
System . out . println ( converted ); // 123
Default Methods(默认方法)详情
注意,如果不写 @FunctionalInterface
标注,程序也是正确的。
官网例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Calculator {
interface IntegerMath {
int operation ( int a , int b );
}
public int operateBinary ( int a , int b , IntegerMath op ) {
return op . operation ( a , b );
}
public static void main ( String ... args ) {
Calculator myApp = new Calculator ();
IntegerMath addition = ( a , b ) -> a + b ; //隐式推断类型
IntegerMath subtraction = ( int a , int b ) -> a - b ; //显式声明类型
System . out . println ( "40 + 2 = " +
myApp . operateBinary ( 40 , 2 , addition ));
System . out . println ( "20 - 10 = " +
myApp . operateBinary ( 20 , 10 , subtraction ));
}
}
为什么Java要增加lambda表达式?
Lambda表达式,也叫做闭包,是一个在很多现代程序语言中十分流行的特性。在众多不同的原因中当中,Java平台最迫切的原因之一是lambda表达式能简化多线程环境下集合的分布式处理。
1.内部循环和外部循环
常规的外部循环:
1
2
3
4
5
List < Integer > numbers = Arrays . asList ( 1 , 2 , 3 , 4 , 5 , 6 );
for ( int number : numbers ) {
System . out . println ( number );
}
这种情况简单的存在3个缺点:
1.只能顺序处理List中的元素
2.不能充分利用多核CPU
3.不利于编译器优化
使用Lamdba表达式内部循环:
1
2
3
List < Integer > numbers = Arrays . asList ( 1 , 2 , 3 , 4 , 5 , 6 );
numbers . forEach (( Integer value ) -> System . out . println ( value ));
1.不一定需要顺序处理List中的元素,顺序可以不确定
2.可以并行处理,充分利用多核CPU的优势
3.有利于JIT编译器对代码进行优化
2、传递行为,而不仅仅是传值
传值局限性的场景
1
2
3
4
5
6
7
8
9
List < Integer > numbers = Arrays . asList ( 1 , 2 , 3 , 4 , 5 , 6 );
public int sumAll ( List < Integer > numbers ) {
int total = 0 ;
for ( int number : numbers ) {
total += number ;
}
return total ;
}
sumAll算法很简单,完成的是将List中所有元素相加。某一天如果需要增加一个对List中所有偶数求和的方法sumAllEven,如下:
1
2
3
4
5
6
7
8
9
public int sumAllEven ( List < Integer > numbers ) {
int total = 0 ;
for ( int number : numbers ) {
if ( number % 2 == 0 ) {
total += number ;
}
}
return total ;
}
又有一天,需要增加第三个方法:对List中所有大于3的元素求和,那是不是继续加下面的方法呢?
1
2
3
4
5
6
7
8
9
public int sumAllEven ( List < Integer > numbers ) {
int total = 0 ;
for ( int number : numbers ) {
if ( number > 3 ) {
total += number ;
}
}
return total ;
}
比较这三个方法,发现了一个很明显的“代码臭味”—— 代码重复。
如果使用Lambda表达式,那么需要Lambda表达式中的谓词(Predicate)发挥作用:
1
2
3
4
5
6
7
8
9
10
11
12
13
public int sumAll ( List < Integer > numbers , Predicate < Integer > p ) {
int total = 0 ;
for ( int number : numbers ) {
if ( p . test ( number )) {
total += number ;
}
}
return total ;
}
sumAll ( numbers , n -> true );
sumAll ( numbers , n -> n % 2 == 0 );
sumAll ( numbers , n -> n > 3 );
3、Consumer与Loan Pattern
比如有一个资源类Resource:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Resource {
public Resource () {
System . out . println ( "Opening resource" );
}
public void operate () {
System . out . println ( "Operating on resource" );
}
public void dispose () {
System . out . println ( "Disposing resource" );
}
}
//调用
Resource resource = new Resource ();
try {
resource . operate ();
} finally {
resource . dispose ();
}
但是有一个问题,如果很多地方都要用到这个资源,那么就存在很多段类似这样的代码,这很明显违反了DRY(Don’t Repeat It Yourself)原则。而且如果某位程序员由于某些原因忘了用try/finally处理资源,那么很可能导致内存泄漏。那咋办呢?Java 8提供了一个Consumer接口,代码改写为如下:
因为对资源对象resource执行operate方法时可能抛出RuntimeException,所以需要在finally语句块中释放资源,防止可能的内存泄漏。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Resource {
public Resource () {
System . out . println ( "Opening resource" );
}
public void operate () {
System . out . println ( "Operating on resource" );
}
public void dispose () {
System . out . println ( "Disposing resource" );
}
public static void withResource ( Consumer < Resource > consumer ) {
Resource resource = new Resource ();
try {
consumer . accept ( resource );
} finally {
resource . dispose ();
}
}
public static void main ( String [] args ) {
Resource . withResource ( resource -> resource . operate ());
}
}
Console:
Opening resource
Operating on resource
Disposing resource
外部要访问Resource,只能通过withResource方法了,而且也完全杜绝了因人为疏忽而导致的潜在内存泄漏。
Lambda表达式范围
对于lambdab表达式外部的变量,其访问权限的粒度与匿名对象的方式非常类似。
1
2
3
4
5
@FunctionalInterface
interface Converter < F , T > {
T convert ( F from );
}
1.访问局部变量
1
2
3
4
5
final int num = 1 ;
Converter < Integer , String > stringConverter =
( from ) -> String . valueOf ( from + num );
stringConverter . convert ( 2 ); // 3
与匿名对象不同的是,变量num不一定是final。
1
2
3
4
5
int num = 1 ; //去掉final也是正确的
Converter < Integer , String > stringConverter =
( from ) -> String . valueOf ( from + num );
stringConverter . convert ( 2 ); // 3
但是num在编译的时候隐式的当作final变量来处理。
1
2
3
4
int num = 1 ;
Converter < Integer , String > stringConverter =
( from ) -> String . valueOf ( from + num );
num = 3 ; //这样是错误的不能对final变量重新复制,在lambda表达式内部改变num的值也是不允许的
2.访问成员变量和静态变量
与局部变量不同,我们在lambda表达式的内部能获取到对成员变量或静态变量的读写权。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class LambdaTest {
static int outerStaticNum ;
int outerNum ;
void testScopes () {
Converter < Integer , String > stringConverter1 = ( from ) -> {
outerNum = 23 ;
return String . valueOf ( from );
};
Converter < Integer , String > stringConverter2 = ( from ) -> {
outerStaticNum = 72 ;
return String . valueOf ( from );
};
}
}
默认方法无法在lambda表达式内部被访问。因此下面的代码是无法通过编译的:
1
2
3
4
5
6
7
8
interface Formula {
double calculate ( int a );
default double sqrt ( int a ) {
return Math . sqrt ( a );
}
}
Formula formula = ( a ) -> sqrt ( a * 100 );
内置函数式接口
Predicates
Predicate是一个布尔类型的函数,该函数只有一个输入参数。Predicate接口包含了多种默认方法,用于处理复杂的逻辑动词(and, or,negate)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Predicate < String > predicate = ( s ) -> s . length () > 0 ;
predicate . test ( "Java" );
Predicate < String > predicate1 = String: : isEmpty ;
System . out . println ( predicate1 . test ( "Java" )); // false
System . out . println ( predicate1 . negate (). test ( "Java" )); // true
Predicate < String > predicate2 = String: : isEmpty ;
System . out . println ( predicate2 . or ( predicate ). test ( "JAVA" )); // true
System . out . println ( predicate2 . and ( predicate ). test ( "JAVA" )); // false
System . out . println ( Predicate . isEqual ( "Java" ). test ( "Java" )); // true
System . out . println ( Predicate . isEqual ( "Java" ). test ( "Java8" )); // false
Predicate源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@FunctionalInterface
public interface Predicate < T > {
boolean test ( T t );
//and
default Predicate < T > and ( Predicate <? super T > other ) {
Objects . requireNonNull ( other );
return ( t ) -> test ( t ) && other . test ( t );
}
//取反
default Predicate < T > negate () {
return ( t ) -> ! test ( t );
}
//or
default Predicate < T > or ( Predicate <? super T > other ) {
Objects . requireNonNull ( other );
return ( t ) -> test ( t ) || other . test ( t );
}
//isEqual
static < T > Predicate < T > isEqual ( Object targetRef ) {
return ( null == targetRef )
? Objects: : isNull
: object -> targetRef . equals ( object );
}
}
Functions
Function接口接收一个参数,并返回单一的结果。默认方法可以将多个函数串在一起。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Function < String , Integer > toInteger = Integer: : valueOf ;
Function < String , String > backToString = toInteger
. andThen ( String: : valueOf );
Integer integer = toInteger . apply ( "123" );
String string = backToString . apply ( "123" );
System . out . println ( integer ); // 123
System . out . println ( string ); // "123"
Function < String , Integer > toInteger = Integer: : valueOf ;
Function < String , String > toString = ( from ) -> from + "123" ;
//toString Function的结果作为toInteger Fuction的输入
Integer result = toInteger . compose ( toString ). apply ( "123" ); //此处的"123"是toString Function的输入
System . out . println ( result ); //123123
Function源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@FunctionalInterface
public interface Function < T , R > {
R apply ( T t );
default < V > Function < V , R > compose ( Function <? super V , ? extends T > before ) {
Objects . requireNonNull ( before );
return ( V v ) -> apply ( before . apply ( v ));
}
default < V > Function < T , V > andThen ( Function <? super R , ? extends V > after ) {
Objects . requireNonNull ( after );
return ( T t ) -> after . apply ( apply ( t ));
}
static < T > Function < T , T > identity () {
return t -> t ;
}
}
Suppliers
Supplier接口产生一个给定类型的结果。与Function不同的是,Supplier没有输入参数。
1
2
Supplier < Person > personSupplier = Person: : new ;
Person person = personSupplier . get ();
Suppliers源码:
1
2
3
4
5
6
7
8
9
10
@FunctionalInterface
public interface Supplier < T > {
/**
* Gets a result.
*
* @return a result
*/
T get ();
}
Consumers
Consumer代表了在一个输入参数上需要进行的操作。
为什么Java增加Lambda表达式章节的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void withResource ( Consumer < Resource > consumer ) {
Resource resource = new Resource ();
try {
//输入一个resource对象
consumer . accept ( resource );
} finally {
resource . dispose ();
}
}
public static void main ( String [] args ) {
//在输入的resource对象上执行operate()操作
Resource . withResource ( resource -> resource . operate ());
}
Consumer也可以将多个操作穿串一起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Person {
private String firstName ;
private String lastName ;
Person () {
}
public Person ( String firstName , String lastName ) {
super ();
this . firstName = firstName ;
this . lastName = lastName ;
}
}
//先执行打印firstName操作
Consumer < Person > greeter = ( p ) -> System . out . println ( "Hello, "
+ p . getFirstName ());
//后执行打印lastName操作
greeter . andThen ( p -> System . out . println ( "Hello, " + p . getLastName ()))
. accept ( new Person ( "Luke" , "Skywalker" ));
Console:
Hello , Luke
Hello , Skywalker
Consumer源码:
1
2
3
4
5
6
7
8
@FunctionalInterface
public interface Consumer < T > {
void accept ( T t );
default Consumer < T > andThen ( Consumer <? super T > after ) {
Objects . requireNonNull ( after );
return ( T t ) -> { accept ( t ); after . accept ( t ); };
}
}
Comparators
Java 8 为这个接口添加了不同的默认方法。
1
2
3
4
5
6
7
8
Comparator < Person > comparator = ( p1 , p2 ) -> p1 . getFirstName ()
. compareTo ( p2 . getFirstName ());
Person p1 = new Person ( "John" , "Doe" );
Person p2 = new Person ( "Alice" , "Wonderland" );
comparator . compare ( p1 , p2 ); //> 0
comparator . reversed (). compare ( p1 , p2 ); // < 0
Optionals
Optional不是一个函数式接口,而是一个精巧的工具接口,用来防止NullPointerEception产生。
Optional类的Javadoc描述如下:
这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
of:调用工厂方法创建Optional实例
1
2
3
Optional < String > name = Optional . of ( "Sanaulla" );
//传入参数为null,抛出NullPointerException.
Optional < String > someNull = Optional . of ( null );
ofNullable:为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。
ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况。
1
Optional empty = Optional . ofNullable ( null );
isPresent:如果值存在返回true,否则返回false。
1
2
Optional < String > name = Optional . of ( "Java" );
System . out . println ( name . isPresent ()); //true
get:如果Optional有值则将其返回,否则抛出NoSuchElementException。
1
2
3
4
5
6
7
8
Optional empty = Optional . ofNullable ( null );
//执行下面的代码会输出:No value present
try {
//在空的Optional实例上调用get(),抛出NoSuchElementException
System . out . println ( empty . get ());
} catch ( NoSuchElementException ex ) {
System . out . println ( ex . getMessage ());
}
ifPresent:如果Optional实例有值则为其调用Consumer,否则不做处理
1
2
3
4
5
Optional < String > name = Optional . of ( "Java" );
name . ifPresent (( value ) -> {
System . out . println ( "The length of the value is: " + value . length ());
//The length of the value is: 4
});
orElse:如果有值则将其返回,否则返回指定的其它值。
1
2
3
4
5
6
7
8
Optional < Object > empty = Optional . ofNullable ( null );
Optional < String > name = Optional . of ( "not null" );
System . out . println ( empty . orElse ( "There is no value present!" ));
System . out . println ( name . orElse ( "There is some value!" ));
Console:
There is no value present !
not null
orElseGet:orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。
1
2
3
4
5
6
7
8
//orElseGet与orElse方法类似,区别在于orElse传入的是默认值,
//orElseGet可以接受一个lambda表达式生成默认值。
System . out . println ( empty . orElseGet (() -> "Default Value" ));
System . out . println ( name . orElseGet (() -> "Default Value" ));
Console:
Default Value
not null
orElseThrow:如果有值则将其返回,否则抛出Supplier接口创建的异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
try {
//orElseThrow与orElse方法类似。与返回默认值不同,
//orElseThrow会抛出lambda表达式或方法生成的异常
empty . orElseThrow ( ValueAbsentException: : new );
} catch ( Throwable ex ) {
//输出: No value present in the Optional instance
System . out . println ( ex . getMessage ());
}
class ValueAbsentException extends Throwable {
public ValueAbsentException () {
super ();
}
public ValueAbsentException ( String msg ) {
super ( msg );
}
@Override
public String getMessage () {
return "No value present in the Optional instance" ;
}
}
map:如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
1
2
3
4
Optional < String > name = Optional . of ( "not null" );
Optional < String > upperName = name . map (( value ) -> value . toUpperCase ());
//输出:NOT NULL
System . out . println ( upperName . orElse ( "No value found" ));
flatMap:如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。
1
2
3
4
Optional < String > name = Optional . of ( "not null" );
name = name . flatMap (( value ) -> Optional . of ( value . toUpperCase ()));
//输出:NOT NULL
System . out . println ( name . orElse ( "No value found" ));
filter:filter个方法通过传入限定条件对Optional实例的值进行过滤。对于filter函数应该传入实现了Predicate接口的lambda表达式。
1
2
3
4
5
6
7
8
9
10
11
Optional < String > name = Optional . of ( "Sanaulla" );
//filter方法检查给定的Option值是否满足某些条件。
//如果满足则返回同一个Option实例,否则返回空Optional。
Optional < String > longName = name . filter (( value ) -> value . length () > 6 );
System . out . println ( longName . orElse ( "The name is less than 6 characters" )); //输出Sanaulla
//另一个例子是Optional值不满足filter指定的条件。
Optional < String > anotherName = Optional . of ( "Sana" );
Optional < String > shortName = anotherName . filter (( value ) -> value . length () > 6 );
//输出:The name is less than 6 characters
System . out . println ( shortName . orElse ( "The name is less than 6 characters" ));
参考资料:
http://www.lambdafaq.org/
http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#use-case
http://java.dzone.com/articles/why-we-need-lambda-expressions
http://java.dzone.com/articles/why-we-need-lambda-expressions-0
http://www.javacodegeeks.com/2013/09/deep-dive-into-optional-class-api-in-java-8.html