lambda学习

基本使用

lambda表达式简介

什么是lambda表达式

  • lambda是java8添加的一个新特性,就是一个匿名函数

为什么使用lambda表达式

  • 使用lambda可以对一个接口进行非常简洁的实现。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public class Main {
    public static void main(String[] args) {
    //1. 使用接口实现类
    Comparator comparator = new MyComperator();
    //2. 使用匿名内部类
    Comparator comparator1 = new Comparator() {
    @Override
    public int compare(int a, int b) {
    return a-b;
    }
    };
    //3.使用lambda表达式来实现接口
    Comparator comparator2 = (a,b)->a-b;
    }
    }
    class MyComperator implements Comparator{
    @Override
    public int compare(int a, int b) {
    return 0;
    }
    }
    interface Comparator{
    int compare(int a,int b);
    }

lambda对接口的要求

  • 虽然可以用lambda表达是对某些接口进行简单实现,但是并不是所有接口都可以用lambda表达式来实现。要求接口中定义的必须要实现的抽象方法只能有一个。

在Java8对接口加了一个新的特性:default.lambda表达式要求要实现的方法只能有一个

@FunctionalInterface

  • 修饰函数是接口(抽象方法只有一个),所以用lambda表达式的接口一般都加上此注解

lambda基础表达式

  • lambda表达式是一个匿名函数,由参数列表和方法体构成
  • ()用来描述参数列表
  • {}用来描述方法体
  • ->lambda运算符,读作goes to
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
//无参无返回值
@FunctionalInterface
public interface LambdaNoneReturnNoneParameter {
void test();
}
//单参无返回值
@FunctionalInterface
public interface LambdaNoneReturnSingleParameter {
void test(int n);
}
//多参无返回值
@FunctionalInterface
public interface LambdaNoneReturnMutipleParameter {
void test(int a,int b);
}
//无参有返回值
@FunctionalInterface
public interface LambdaSingleReturnNoneParameter {
int test();
}
//单参有返回值
@FunctionalInterface
public interface LambdaSingleReturnSingleParameter {
int test(int a);
}
//多参有返回值
@FunctionalInterface
public interface LambdaSingleReturnMutipleParameter {
int test(int a,int b);
}
  • lambda基础实现
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    //无参无返回
    LambdaNoneReturnNoneParameter lambda1 = ()->{
    System.out.println("hello world");
    };
    lambda1.test();//hello world

    //无返回值,单个参数
    LambdaNoneReturnSingleParameter lambda2 = (int a)->{
    System.out.println(a);
    };
    lambda2.test(10);
    //10

    //无返回值,多个参数
    LambdaNoneReturnMutipleParameter lambda3 = (int a,int b)->{
    System.out.println(a+b);
    };
    lambda3.test(10,20);
    //30

    //无参数有返回值
    LambdaSingleReturnNoneParameter lambda4=()->{
    System.out.println("lambda4");
    return 100;
    };
    System.out.println(lambda4.test());
    //lambda4/n100

    //有返回值,一个参数
    LambdaSingleReturnSingleParameter lambda5 = (int a)->{
    System.out.println("lambda5");
    return a*3;
    };
    System.out.println(lambda5.test(4));
    //lambda5/n12

    //有返回值,多个参数
    LambdaSingleReturnMutipleParameter lambda6 = (int a,int b)->{
    System.out.println("lambda6");
    return a+b;
    };
    System.out.println(lambda6.test(5,6));
    //lambda6/n11

lambda语法精简

简化参数类型

  • 由于在接口的抽象方法中已经定义了参数的数量和类型,所以在lambda表达式中,参数的类型可以忽略
  • 备注: 如果需要省略类型,则每一个参数的类型都要省略
    1
    2
    3
    4
    5
    LambdaNoneReturnMutipleParameter lambda1 = (a,b)->{
    System.out.println(a+b);
    };
    lambda1.test(2,3);
    //5

简化参数小括号

  • 如果参数列表中,参数的数量只有一个,此时小括号可以省略
    1
    2
    3
    4
    5
    LambdaNoneReturnSingleParameter lambda2 = a->{
    System.out.println(a);
    };
    lambda2.test(5);
    //5

简化方法大括号

  • 如果此时方法体中只有一条语句,此时大括号可以省略
    1
    2
    3
    LambdaNoneReturnSingleParameter lambda3 = a-> System.out.println(a);
    lambda3.test(6);
    //6

简化return

  • 如果方法体中唯一的一条语句是一个返回语句,则省略大括号的同时也必须省略return
    1
    2
    3
    4
    5
    6
    7
    LambdaSingleReturnNoneParameter lambda4 = ()->10;
    System.out.println(lambda4.test());
    //10

    LambdaSingleReturnMutipleParameter lambda5 = (a,b)->a+b;
    System.out.println(lambda5.test(5,4));
    //9

语法进阶

## 方法引用

一般方法的引用

  • 语法:方法的隶属者::方法名

  • 注意:

  • 1.参数数量和类型一定要和接口中定义的方法一致
  • 2.返回值的类型一定要和接口中定义方法一致
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class Syntax3 {
    private static int change(int a){
    return a*2;
    }
    public static void main(String[] args) {
    //定一个方法,相当于只有一个值的参数,相当于return change(a);
    LambdaSingleReturnSingleParameter lambda1 = a->change(a);

    //方法引用:引用了'类::方法名'的静态change方法的实现
    LambdaSingleReturnSingleParameter lambda2 = Syntax3::change;

    //引用对象的方法
    Syntax3 syntax3 = new Syntax3();
    LambdaSingleReturnSingleParameter lambda3 = syntax3::change2;
    }
    private int change2(int a){
    return a*3;
    }
    }

构造方法的引用精简

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Person {
public String name;
public int age;

public Person() {
System.out.println("无参构造方法执行了");
}

public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造方法执行了");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Syntax4 {
public static void main(String[] args) {
PersonCreater creater = ()->new Person();

//构造方法的引用
PersonCreater creater1 = Person::new;
Person a = creater.getPerson();
//无参构造方法执行了

PersonCreater2 creater2 = Person::new;
Person b = creater2.getPerson("是我", 18);
//有参构造方法执行了
}
}
interface PersonCreater{
Person getPerson();
}
interface PersonCreater2{
Person getPerson(String name,int age);
}
  • 构造方法的引用精简是依托于接口中参数,对应构造方法的参数

lambda操作集合列表

排序1

  • 需求:一直再一个ArrayList中有若干个Person对象,将这些Person对象按照年龄进行降序排序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("a", 17));
    list.add(new Person("b", 12));
    list.add(new Person("c", 3));
    list.add(new Person("d", 144));
    list.add(new Person("e", 15));
    list.add(new Person("f", 18));
    list.add(new Person("g", 1));
    list.sort((o1, o2) ->
    o2.age - o1.age
    );
    System.out.println(list);
  • 实现原理就是实现了sort中的Comparator接口的compare方法

排序2

  • 使用TreeSet自带的排序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //使用Lambda表达式来实现Comparetor接口,并实例化一个TreeSet对象
    TreeSet<Person> set = new TreeSet<>((o1, o2) -> {
    if (o1.age > o2.age) {
    return -1;
    } else {
    return 1;
    }
    });
    set.add(new Person("a", 17));
    set.add(new Person("b", 12));
    set.add(new Person("c", 3));
    set.add(new Person("d", 144));
    set.add(new Person("e", 15));
    set.add(new Person("f", 18));
    set.add(new Person("g", 1));
    System.out.println(set);
  • 因为Tree会根据排序规则是否为0判断是否为统一元素去重,所以表达和上面有所不同

集合遍历

用list的forEach方法遍历,lambda实现一个Consumer

1
2
3
4
5
6
7
8
9
10
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,1,2,3,4,5,6,7);
//对所有输出
list.forEach(System.out::println);
//仅输出偶数
list.forEach(ele->{
if(ele%2==0){
System.out.println(ele);
}
});

删除集合元素

  • 删除满足条件的集合元素,删除年龄为偶数的元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("a", 17));
    list.add(new Person("b", 12));
    list.add(new Person("c", 3));
    list.add(new Person("d", 144));
    list.add(new Person("e", 15));
    list.add(new Person("f", 18));
    list.add(new Person("g", 1));

    //删除年龄为偶数的元素
    list.removeIf(person -> person.age % 2 == 0);
    System.out.println(list);
  • 是重写了removeIf的参数Predicate,lambda实现了他的test方法

操作线程

创建线程

  • 匿名内部类通过实现Runnable接口创建线程
    1
    2
    3
    4
    5
    6
    Thread thread = new Thread(()->{
    for (int i = 0; i <100 ; i++) {
    System.out.println(i);
    }
    });
    thread.start();

系统内置函数式接口

参考
防挂

闭包

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
System.out.println(getNumber().get());
}
private static Supplier<Integer> getNumber(){
int num = 10;
return ()->{
return num;
};
}
  • 此时输出是10
  • 问题:按说执行完getNumber了局部变量num就会销毁,怎么还能获取到值
  • 闭包会提升变量的生命周期
  • lambda中使用的局部变量一定是常量,如果没有写final,编译时候会自动加上final,不要修改lambda中调用的局部变量的值