下面来说一下Lambda表达式,这个是 Java 8 的新特性,实质上是简便了对接口的实现,不用再写匿名内部类,而是简单的表达式。
首先,Lambda只能用于函数式接口,什么是函数式接口?
定义:抽象方法 的个数只有一个的接口。
就是这个 上边会有一个 @FunctionInterface标识,和@Override一样。
@Override 标识的方法如果不是重写的方法,编译器就会报错。
那@FunctionInterface标识的接口呢,如果接口方法大于一个,也会报错。
语法格式是什么样呢?
(参数列表)->{方法实现语句};
或者 (参数列表)->返回值语句;
从这个结构你就能看出来了,如果 有{} 那就可以多条语句,没有的话 只能有一条语句
下面 来个一Demo
package day12;
/**示例:Lambda语法*/
@FunctionalInterface
interface Info{
//1.无参无返回值类型
// void af();
//2.有参无返回值类型
// void af(int n);
//3.无参有返回值类型
// int af();
//4.有参有返回值类型
int af(int n);
}
public class TestLambda1 {
//1.无参无返回值类型
/* Info info1 = ()->{System.out.println("af");};
//只有一行代码 可以省略{}
Info info2 = ()->System.out.println("af");*/
//2 有参无返回值类型
// Info info3 = (num)->{System.out.println(num);};
// Info info3 = num ->System.out.println(num);
//3.无参有返回值类型
// Info info4 = ()->{return 22;};
// Info info5 = ()->22;
//4有参有返回值类型
Info info6 = (n)->{return n;};
Info info7 = n->45;
public static void main(String[] args) {
// new TestLambda1().info3.af(155);
// InfoImpl info = new InfoImpl();
// info.af();
//2.匿名内部类的实现
/* new Info() {
public void af() {
System.out.println("af");
}
}.af();*/
}
}
/*//1. 定义一个 实现类
class InfoImpl implements Info{
@Override
public void af() {
System.out.println("af");
}
}*/
从上边可以看出,其实Lambda表达式 就是为了简写 匿名内部类。
那来比较一下匿名内部类和 Lambda的区别:
1.Lambda只能实现 函数式 接口;
匿名内部类 可以是继承一个父类 或 实现一个父接口;
2.Lambda只能 针对 函数式接口 中的抽象方法;
匿名内部类可以 调用 非抽象方法:如:默认方法等。
再来个Demo 体会一下
package day12;
//跑
interface Run{
void run();
}
/*class Dog implements Run{
public void run() {
System.out.println("小狗跑了");
}
}
class Cat implements Run{
public void run() {
System.out.println("小猫跑了");
}
}*/
class ManagerRun{
//测试 怎么跑的
public void checkRun(Run run) {
run.run();
}
}
public class TestLambda2 {
public static void main(String[] args) {
ManagerRun m = new ManagerRun();
//匿名内部类传参
m.checkRun(new Run() {
@Override
public void run() {
System.out.println("小狗跑了");
}
});
//Lambda传参
m.checkRun(()->{System.out.println("小狗跑了");});
//Lambda 函数式接口类型
Run run = ()->{System.out.println("小狗跑了");};
Object o = run;
Object o1 =(Run) ()->{System.out.println("小狗跑了");};
/* Dog dog = new Dog();
Cat cat = new Cat();
ManagerRun m = new ManagerRun();
m.checkRun(dog);
m.checkRun(cat);*/
}
}
可以看到Lambda 是多么的灵巧,还有一些对集合操作的 用到Lambda 会非常的方便。
下面再说几种 Lambda的用法 :
Lambda的方法引用
当 Lambda只有一行代码,只调用了一个方法。
四种形式:
1.引用类方法;
类名::类方法
2.引用特定对象 的 实例方法;
特定对象::实例方法
3.引用 某个类对象 的 实例方法;
类::实例方法
4.引用 构造器。
类::new
下面上一个Demo
package day12;
/**示例:方法引用*/
interface La{
Integer f(String s);
}
class Student{
private String name;
Student(String name){
this.name = name;
}
}
interface La1{
Student f(String name);
}
public class TestLambda4 {
//------------------方法引用----------------------------
//1.引用 类方法
// La la1 = s->{return Integer.parseInt(s);};
La la1 = s -> Integer.parseInt(s);
La la2 = Integer::parseInt;
//2.特定对象 引用 实例方法
La la3 = s->"hello".indexOf(s);
La la4 = "hello"::indexOf;
//3.某类对象 的实例方法
La la5 = s->s.length();
La la6 = String::length;
//4.引用构造器
La1 la7 = s->new Student(s);
La1 la8 = Student::new;
public static void main(String[] args) {
Integer i = new TestLambda4().la2.f("35");
System.out.println(i);
}
}
再上两个Demo
package day12;
import java.util.Arrays;
import java.util.function.IntBinaryOperator;
import java.util.function.IntConsumer;
import java.util.function.IntUnaryOperator;
public class TestLambda5 {
public static void main(String[] args) {
int [] arr = {1,2,3,4,5};
//用 索引 替换掉 数组中的元素
//一元运算
/* Arrays.parallelSetAll(arr, new IntUnaryOperator() {
@Override
public int applyAsInt(int operand) {
// 数组的索引
return operand;
}
});*/
// Arrays.parallelSetAll(arr,index->index );
System.out.println(Arrays.toString(arr));
//二元运算
//用 二元运算的结果 来替换掉数组的每一个元素
/* Arrays.parallelPrefix(arr, new IntBinaryOperator() {
// left -前一个元素 right:当前元素
@Override
public int applyAsInt(int left, int right) {
// 当前元素是第一个元素 ,前一个元素 是1
return left * right;
}
});*/
Arrays.parallelPrefix(arr,(n1,n2)->n1*n2 );
System.out.println(Arrays.toString(arr));
//遍历数组 Stream流的方法
Arrays.stream(arr).forEach(new IntConsumer() {
//value数组元素
@Override
public void accept(int value) {
System.out.println(value);
}
});
//Lambda
Arrays.stream(arr).forEach(num->System.out.println(num));
//方法引用
Arrays.stream(arr).forEach(System.out::println);
}
}
package day12;
/**练习:Lambda参数传递*/
interface InfoArray{
void reverse(int[] arr);
}
class ArrayImpl{
public void display(int [] arr,InfoArray info) {
info.reverse(arr);
}
}
public class TestLambda6 {
public static void main(String[] args) {
ArrayImpl a = new ArrayImpl();
int [] arr = {11,22,33,44,55};
//匿名内部类
a.display(arr, new InfoArray() {
@Override
public void reverse(int[] arr) {
for(int i = arr.length-1; i >=0; i--) {
System.out.println(arr[i]);
}
}
});
//Lambda
a.display(arr, arr1->{
for(int i = arr1.length-1; i >=0; i--) {
System.out.println(arr1[i]);
}
});
}
}
写到这里,应该能掌握这个表达式的用法了,要写Lambda表达式,首先也是必须要知道接口的方法是如何实现的,另外呢 Lambda表达式最好用在用的多的地方,就比如遍历集合?! 大家能认出来,否则,这个表达式可读性太差了,所以能不用还是别用