1 为什么使用lambda表达式?
Lambda表达式允许将函数作为方法的参数,或者将code作为数据。使得代码简洁,可读性较高。
详情可参考官网 和博客
2 Lambda表达式的格式
(attr1,attr2,.....)->函数体
左边是参数,当参数为1个时,可以没有括号,比如:
e->e+2
当参数为0个时,用括号表示
()->System.out.println(“表达式”)
如果函数体为一行,那么就没有必须显示的使用return语句,比如,下面的两个代码是等价的:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
int result = e1.compareTo( e2 );
return result;
} );
如果函数体为多行,则需要将函数体用花括号”{ }”括起来*,表达式用分号结尾。*
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
int result = e1.compareTo( e2 );
return result;
} );
通常参数的类型是由编译器推测出来的,比如:
public class test1 {
private static String e="letter";//成员变量
public static void main(String[] args) {
Arrays.asList( "a", "b", "d" ).stream().forEach(attr->System.out.println(attr+"_"+ e ));
}
}
这里的attr被推测为String类型。
当然也可以显示的写出来:
public class test1 {
public static void main(String[] args) {
String e="letter";//局部变量
Arrays.asList( "a", "b", "d" ).stream().forEach((String attr)->System.out.print( e ));
}
}
Lamda表达式可以引用类的成员变量和局部变量
3.函数式接口和Lambda表达式
函数式接口(也叫SAM接口,Single Abstract Method)的对象可以作为函数的参数,这样参数在引用时,可以以lambda表达式的方式出现。
每个函数式接口里仅允许有一个抽象方法,这个方法叫做函数式方法,lambda表达式的参数和返回类型必须和该函数的参数和返回类型保持一致。你无须去创建这个类,编译器会帮你实现。
例如:
//定义一个函数式接口getNewString ,其函数式方法是getNew
public interface getNewString {
public abstract String getNew(String old);
}
测试该函数式接口:
public class test1 {
public static void main(String[] args) {
//定义1
getNewString getmethod=(object)-> {return (object+"hello");};
System.out.println(getmethod.getNew("Java8 "));
//定义2,当函数体仅有一行时,直接写表达式,不需要写return 语句。
getNewString getmethod2=(object)-> object+"Good Morning!";
System.out.println(getmethod.getNew("Java8 "));
//定义了函数式接口作为参数的函数,可以直接使用方法引用
Arrays.asList("1","2").stream().forEach(getmethod2::getNew);
}
}
从测试程序中的定义1和定义2可以看到,函数式接口的好处是可以做参数,并且函数体可以随意修改。
函数式接口仅允许有一个抽象方法,但是下面几种情况除外:
因为默认方法不是抽象方法,其有一个默认实现,所以是符合函数式接口的定义的:
如下代码不会报错:
@FunctionalInterface
interface GreetingService
{
void sayMessage(String message);
default void doSomeMoreWork1()
{
// Method body }
default void doSomeMoreWork2()
{
// Method body }
}
函数式接口里是可以包含静态方法,因为静态方法不能是抽象方法,是一个已经实现了的方法,所以是符合函数式接口的定义的;
如下代码不会报错:
函数式接口里是可以包含Object里的public方法,这些方法对于函数式接口来说,不被当成是抽象方法(虽然它们是抽象方法);因为任何一个函数式接口的实现,默认都继承了Object类,包含了来自java.lang.Object里对这些抽象方法的实现;
如下代码不会报错:
@FunctionalInterface
interface GreetingService
{
void sayMessage(String message);
@Override
boolean equals(Object obj);
}
因此,为了保证函数式接口定义准确,java8 提供了注解@FunctionalInterface
,这样当接口不正确时,在编译阶段会报错。例如:
@FunctionalInterface
public interface getNewString {
public abstract String getNew(String old);
}
Java中有哪些函数式接口呢?:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
java.util.function中定义了几组类型的函数式接口以及针对基本数据类型的子类。
Predicate — 传入一个参数,返回一个bool结果, 方法为boolean test(T t)
Consumer — 传入一个参数,无返回值,纯消费。 方法为void accept(T t)
Function — 传入一个参数,返回一个结果,方法为R apply(T t)
Supplier — 无参数传入,返回一个结果,方法为T get()
UnaryOperator — 一元操作符, 继承Function,传入参数的类型和返回类型相同。
BinaryOperator — 二元操作符, 传入的两个参数的类型和返回类型相同, 继承BiFunction
详细信息请参考官网