一小时学会lambda表达式

本文详细介绍了Java 8的Lambda表达式,包括其基本语法、使用场景、方法引用以及在集合操作中的应用。通过示例展示了Lambda如何简化代码,如接口实现、排序、过滤等操作,并探讨了闭包的概念。此外,还提及了系统内置的函数式接口,如Predicate和Consumer。
摘要由CSDN通过智能技术生成

一、什么是lambda

lambda是java8添加的一个新的特性,是一个匿名函数,使用lambda表达式可以对一个接口进行非常简洁的实现,下面来看一段代码

public class LambdaTest {
    public static void main(String[] args) {
        //1.使用接口实现类
        Comparator comparator = new MyComparator();
        //2.使用匿名内部类
        Comparator comparator1 = new Comparator() {
            @Override
            public int compare(int a, int b) {
                return a - b;
            }
        };
        //3.使用lambda表达式
        Comparator comparator2 = (a, b) -> a - b;
    }
}

interface Comparator {
    int compare(int a, int b);
}

class MyComparator implements Comparator {

    @Override
    public int compare(int a, int b) {
        return a - b;
    }
}

由上面代码可以看出,使用匿名内部类的方式比使用接口实现类方式简单,使用lambda表达式比使用匿名内部类的方式更简单

二、lambda对接口的要求

虽然可以使用lambda表达式对某些接口进行简单的实现,但并不是所有的接口都可以使用lambda表达式来实现,要求接口中定义的必须要实现的抽象方法只能有一个
@FunctionInterface 修饰函数式接口的,接口中的抽象方法只有一个
看下面代码验证:
@FunctionInterface 修饰的接口抽象方法只有一个时,编译通过
在这里插入图片描述
@FunctionInterface 修饰的接口抽象方法个数>1,编译不通过
在这里插入图片描述

三、lambda基础语法

  • () : 用来描述参数列表
  • {} : 用来描述方法体
  • -> :lambda运算符,读goes to

1 无参无返回值

public class LambdaTest {
    public static void main(String[] args) {
        //无返回值无参数
        LambdaNoReturnNoParam lambdaNoReturnNoParam = () -> {
            System.out.println("hello world");
        };
        lambdaNoReturnNoParam.test();
    }
}

@FunctionalInterface
interface LambdaNoReturnNoParam {
    void test();
}

2 无返回值单个参数

public class LambdaTest {
    public static void main(String[] args) {
        //无返回值单个参数
        LambdaNoReturnSingleParam lambda2 = (int n) -> {
            System.out.println(n);
        };
        lambda2.test(1);
    }
}

@FunctionalInterface
interface LambdaNoReturnSingleParam {
    void test(int n);
}

3 无返回值多个参数

public class LambdaTest {
    public static void main(String[] args) {
        LambdaNoReturnMutipleParam lambda3=(int a,int b)->{
            System.out.println(a+b);
        };
        lambda3.test(1, 2);
    }
}

@FunctionalInterface
interface LambdaNoReturnMutipleParam {
    void test(int n, int b);
}

4 有返回值无参

public class LambdaTest {
    public static void main(String[] args) {
        LambdaSingleReturnNoParam lambda = () -> {
            return 2;
        };
        System.out.println(lambda.test());
    }
}

@FunctionalInterface
interface LambdaSingleReturnNoParam {
    int test();
}

5 有返回值单个参数

public class LambdaTest {
    public static void main(String[] args) {
        LambdaSingleReturnSingleParam lambda = (int n) -> {
            return n;
        };
        System.out.println(lambda.test(1));
    }
}

@FunctionalInterface
interface LambdaSingleReturnSingleParam {
    int test(int n);
}

6 有返回值多个参数

public class LambdaTest {
    public static void main(String[] args) {
        LambdaSingleReturnMutipleParam lambda = (int a, int b) -> {
            return a + b;
        };
        System.out.println(lambda.test(1, 2));
    }
}

@FunctionalInterface
interface LambdaSingleReturnMutipleParam {
    int test(int n, int b);
}

四、lambda语法精简

1 精简参数类型

由于在接口的抽象方法中,已经定义了参数的数量和类型,所以在lambda表达式中,参数类型可以省略

public class LambdaTest {
    public static void main(String[] args) {
        LambdaNoReturnMutipleParam lambda = (a, b) -> {
            System.out.println(a + b);
        };
        lambda.test(1, 2);
    }
}

@FunctionalInterface
interface LambdaNoReturnMutipleParam {
    void test(int n, int b);
}

注:如果需要省略类型,则每一个参数的类型都要省略,千万不要出现省略一个参数,不省略一个参数类型

2 精简参数小括号

如果参数列表中,参数的数量只有一个,此时小括号可以省略

public class LambdaTest {
    public static void main(String[] args) {
        LambdaNoReturnSingleParam lambda = a -> {
            System.out.println(a);
        };
        lambda.test(1);
    }
}
@FunctionalInterface
interface LambdaNoReturnSingleParam {
    void test(int n);
}

3 精简方法大括号

如果方法体中只有一条语句,大括号可以省略

public class LambdaTest {
    public static void main(String[] args) {
        LambdaNoReturnSingleParam lambda = a -> System.out.println(a);
        lambda.test(1);
    }
}
@FunctionalInterface
interface LambdaNoReturnSingleParam {
    void test(int n);
}

如果方法体中唯一的一条语句是一个返回语句,则在省略掉大括号的同时也必须省略掉return

public class LambdaTest {
    public static void main(String[] args) {
        LambdaSingleReturnNoParam lambda = () ->  10;
        System.out.println(lambda.test());;
    }
}

@FunctionalInterface
interface LambdaSingleReturnNoParam {
    int test();
}

五、lambda语法进阶

1 普通方法引用

方法引用可以快速将一个lambda表达式的实现指向一个已经实现的方法
语法: 方法的隶属着::方法名
方法分为静态的和非静态的,静态方法的常拿类来调用,非静态方法常用对象来调用,所谓方法隶属着视方法而定,比如下面的change方法,它是一个静态方法,那么隶属着指LambdaTest这个类,如果change方法是一个非静态方法,那么隶属着就是LambdaTest这个对象

public class LambdaTest {
    public static void main(String[] args) {
        LambdaSingleReturnSingleParam lambda = (a) ->  change(a);
        System.out.println(lambda.test(6));
        //方法引用,语法:[方法的隶属着::方法名]  引用了change方法的实现
        LambdaSingleReturnSingleParam lambda2=LambdaTest::change;
        System.out.println(lambda2.test(7));
    }
    private static int change(int a){
        return a*2;
    }
}

@FunctionalInterface
interface LambdaSingleReturnSingleParam {
    int test(int n);
}

方法引用中需注意以下亮点

  • 参数数量和类型与接口中定义的方法一致
  • 返回值类型也一定要和接口定义的类型一致

2 无参构造方法引用

public class ConstructLambdaTest {
    public static void main(String[] args) {
        PersonCreate c = () -> new Person();
        System.out.println(c.getPerson());
        //无关构造函数引用
        PersonCreate creater = Person::new;
        System.out.println(creater.getPerson());
    }
}

interface PersonCreate{
    Person getPerson();
}

@Data
 class Person {
    private String name;
    private int age;
}

3 含参构造方法引用

public class ConstructLambdaTest {
    public static void main(String[] args) {
        PersonCreate creater = Person::new;
        System.out.println(creater.getPerson("张三", 1));
    }
}

interface PersonCreate {
    Person getPerson(String name, int age);
}

@Data
class Person {
    private String name;
    private int age;

    public Person(String name, int age) {

    }
}

六、lambda综合案例

需求:在ArrayList有若干个Person对象,Person对象有name,age属性

@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
    private String name;
    private int age;
}

1 集合排序

将这些Person对象按年龄进行降序排序

        List<Person> list = new ArrayList<>();
        list.add(new Person("张三", 30));
        list.add(new Person("李四", 20));
        list.add(new Person("李四", 40));
        list.sort(((o1, o2) -> o2.getAge() - o1.getAge()));
        System.out.println(list);

2 TreeSet

使用lambda表达式实现Comparator接口,并实例化一个TreeSet对象
注意:treeset相等o1.getAge() - o2.getAge()=0时会自动对元素去重,所以不能让返回为0

        TreeSet<Person> set = new TreeSet<Person>((o1, o2) -> {
            if (o1.getAge() - o2.getAge() >= 0) {
                return -1;
            } else {
                return 1;
            }
        });
        set.add(new Person("张三", 30));
        set.add(new Person("李四", 20));
        set.add(new Person("李四", 40));
        System.out.println(set);

3 集合遍历

        List<Integer> list = new ArrayList<>();
        Collections.addAll(list, 1, 2, 3, 4, 5);
        //将集合中每一个元素都带入accept方法中
        list.forEach(System.out::println);
        //输出集合中的偶数
        list.forEach(ele -> {
            if (ele % 2 == 0) {
                System.out.println(ele);
            }
        });

4 删除集合元素

删除集合中年龄大于20岁的元素

        List<Person> list = new ArrayList<>();
        list.add(new Person("张三", 30));
        list.add(new Person("李四", 20));
        list.add(new Person("李四", 40));
        //将集合中的每个元素都带入到test方法中,如果返回是true,则删除这个元素
        list.removeIf(ele -> ele.getAge() > 20);
        System.out.println(list);

5 线程实例化

    public static void main(String[] args) {
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println(i);
            }
        }).start();
    }

七、系统内置函数式接口

指定类型的参数,返回值是boolean时可以用Predicate
在这里插入图片描述
Predicate 参数是T类型,返回值是boolean
IntPredicate 参数int 返回值boolean
LongPredicate
DoublePredicate
Consumer 参数T 返回值void
IntConsumer
Function<T, R> 参数是T 返回值R(指定类型参数,指定类型返回值)
IntFunction
LongFunction
IntToLongFunction
Supplier 无参 指定类型返回值
UnaryOperator 参数T 返回值T
BiFunction<T, U, R> 参数T U 返回值R
BinaryOperator 参数T T 返回值T
BiPredicate<T, U> 参数T U 返回值boolean
BiConsumer<T, U> 参数T U 返回值void

八、闭包

  • 闭包可以提升变量的生命周期,获取某个方法的局部变量
    public static void main(String[] args) {
        int n = getNumber().get();
        System.out.println(n);
    }

    public static Supplier<Integer> getNumber() {
        int num = 10;
        //闭包
        return () -> num;
    }
  • 在闭包中引用的变量一定是常量
    public static void main(String[] args) {
        int a = 10;
        Consumer<Integer> c = ele -> {
            System.out.println(a);//报错
        };
        a++;
        c.accept(1);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值