Lambda表达式
本篇文单主要介绍Lambda表达式,在介绍Lambda表达式之前,需要了解一下接口的静态方法,接口的默认方法,函数式接口、方法引用。Lambda表达式是建立在此基础上,这些也都是JDK1.8引入进来的。
接口的静态方法
接口的静态方法就是,直接在接口类中用static修饰的实现方法。该方法不能被实现类重写,也不能被实现类调用。
public interface Hello {
/**
* 接口中定义的static方法
*/
static void printHello() {
System.out.println("Hello");
}
}
调用方式,直接用接口类.方法名()。而接口的实现类HelloImpl是没有printHello方法的。
/**
* 测试接口的Static方法
*/
@Test
public void testStatic() {
Hello.printHello();
}
接口的默认方法
接口的默认方法就是,直接在接口类中用default修饰的实现方法,该方法可以被接口的实现类重写。
public interface Hello {
/**
* 在接口中定义的default
*/
default void talk() {
System.out.println("default talk");
}
default void talk2() {
System.out.println("default talk2");
}
}
接口的实现类中重写其中的talk2方法
public class HelloImpl implements Hello {
/**
* 重写接口中的default方法
*/
@Override
public void talk2() {
System.out.println("talk2");
}
}
调用:
/**
* 测试接口的默认方法
*/
@Test
public void testDefault() {
Hello hello = new HelloImpl();
hello.talk();
}
/**
* 测试接口的默认方法
*/
@Test
public void testDefault2() {
Hello hello = new HelloImpl();
hello.talk2();
}
结果:
default talk
talk2
函数式接口-@FunctionalInterface
函数接口的定义如下:仅含有一个抽象方法的接口 两个关键条件 1、是一个接口 2、只有一个抽象方法。这个抽象方法不包括equals方法,当然接口的静态方法和默认方法都不是抽象方法,也就是说函数式接口可以用static和default方法。如果满足:1、是一个接口 2、只有一个抽象方法。可以在接口类上面添加@FunctionalInterface注解。
@FunctionalInterface
public interface Glue {
/**
* 返回一个由arg1连接arg2的字符串
*
* @param arg1
* @param arg2
* @return
*/
String link(String arg1, String arg2);
}
Glue就是一个函数式接口,如果仅包含static、default方法或equals方法也可以。说明一下,不是因为添加了@FunctionalInterface注解就是函数式接口,@FunctionalInterface注解是编译检查用的。只要仅含有一个抽象方法的接口就是函数式接口。
Lambda是什么?
个人理解,Lambda就是一个匿名的函数式接口实现类
@Test
public void test1() {
Glue glue = (arg1, arg2) -> {
return arg1 + "_" + arg2;
};
String result = glue.link("a","b");
System.out.println(result);
}
结果:
a_b
简单说明一下:()->{} ()部分就是函数式接口中仅有的一个方法的形参,如果没有形参()中间就不需要形参名,{}部分就是函数式接口中仅有的一个方法的实现。如果有返回值就需要return,如果没有返回值就不需要,如果方法的实现只有一行代码并且有返回值,也可以不需要{}
上例也可以这个执行:
@Test
public void test1() {
Glue glue = (arg1, arg2) -> arg1 + "_" + arg2;
String result = glue.link("a","b");
System.out.println(result);
}
无形参数函数式接口示例:
@FunctionalInterface
public interface Glue {
void print();
}
@Test
public void test1() {
Glue glue = () -> {
System.out.println("Glue函数式接口的维一抽象方法print的实现");
};
glue.print();
}
另一个例子,JDK自带的Runnable接口也是一个FunctionalInterface
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
开启一个子线程也可以这样:
@Test
public void testRunnable1(){
Runnable runnable = ()->{
System.out.println("Runnable接口的run实现"+Thread.currentThread().getName());
};
new Thread(runnable).start();
}
@Test
public void testRunnable2(){
new Thread(()->{
System.out.println("Runnable接口的run实现"+Thread.currentThread().getName());
}).start();
}
方法引用
方法引用分为普通方法引用和静态方法引用,普通方法引用为:对象名::方法,静态方法引用为:类::方法。它用在函数式接口的唯一抽象方法实现中。
定义一个普通的方法:
public class RandomNumImpl {
/**
* 产生一个随机数
*/
public void buildNum() {
Random random = new Random();
System.out.println(random.nextInt(10));
}
}
定义一个函数式接口Glue
@FunctionalInterface
public interface Glue {
void print();
}
如果用Lamabe来表示一个函数式接口Glue的匿名实现类,并且print方法的实现还需要用到RandomNumImpl类,常用的写法是:
@Test
public void test2() {
RandomNumImpl randomNum = new RandomNumImpl();
Glue glue = () -> {
randomNum.buildNum();
};
glue.print();
}
也可以简化成:
@Test
public void test3() {
RandomNumImpl randomNum = new RandomNumImpl();
Glue glue = randomNum::buildNum;
glue.print();
}
如果把函数式接口Glue的唯一抽象方法print的实现改成需要调一个类的静态方法,还可以简化成:
public class RandomNumImpl {
public static void buildLongNum() {
Random random = new Random();
System.out.println(random.nextLong());
}
}
@Test
public void test4() {
Glue glue = RandomNumImpl::buildLongNum;
glue.print();
}
小结一下: A::B A表示Lamada将要实现的抽象方法所需外部变量名,B表示A的某个方法,如果是静态方法,A则为了类名。