Java基础——Lambda表达式——lambda规则详解与常见使用

参考https://www.bilibili.com/video/BV164411E7Ny

Lambda表达式

一、Lambda表达式简介

什么是Lambda?

Lambda是JAVA 8添加的新特性,说白了,Lambda是一个匿名函数

为什么使用Lambda

使用Lambda表达式可以对一个接口的方法进行非常简洁的实现

Lambda对接口的要求

接口的抽象方法只能是一个,lambda表达式才能实现该接口

在JAVA8中 ,对接口加了一个新特性:default
可以使用default对接口方法进行修饰,被修饰的方法在接口中可以默认实现

@FunctionalInterface

修饰函数式接口的,接口中的抽象方法只有一个

二、Lambda的基础语法

—lambda表达式如何实现各类接口

1.语法

lambda表达式是实现一种接口的方式

()里面传入的是实现方法的参数列表

// 1.Lambda表达式的基础语法
// Lambda是一个匿名函数 一般关注的是以下两个重点
// 参数列表 方法体

/**
* ():用来描述参数列表
*  {}:用来描述方法体 有时可以省略
*  ->: Lambda运算符 读作goes to
*  例 Test t=()->{System.out.println("hello word")}; 大括号可省略
*/

2.创建多个接口(准备工作)

—2、3代码复制粘贴就可以看到效果(jdk1.8以上)

无返回值无个参数 LambdaNoneReturnNoneParameter
无返回值单个参数 LambdaNoneReturnSingleParameter
无返回值多个参数 LambdaNoneReturnMulParameter
有返回值单个参数 LambdaSingleReturnSingleParameter
有返回值多个参数 LambdaSingleReturnMulParameter

public class Syntax {
    public static void main(String[] args) {

    }
}

//无返回值无参数
@FunctionalInterface
interface LambdaNoneReturnNoneParameter {
    void test();
}

//无返回值单个参数
@FunctionalInterface
interface LambdaNoneReturnSingleParameter{
    void test(int a);
}

//无返回值多个参数
@FunctionalInterface
interface LambdaNoneReturnMulParameter{
    void test(int a, int b);
}

//有返回值单个参数
@FunctionalInterface
interface LambdaSingleReturnSingleParameter{
    int test(int a);
}

//有返回值多个参数
@FunctionalInterface
interface LambdaSingleReturnMulParameter{
    int test(int a, int b);
}

3.测试

        System.out.println("<-----test01----->");
    // 无返回值无个参数 LambdaNoneReturnNoneParameter
        LambdaNoneReturnNoneParameter lambda01=()->{
            System.out.println("test01");
        };
        lambda01.test();

        System.out.println("<-----test02----->");
    // 无返回值单个参数 LambdaNoneReturnSingleParameter
        LambdaNoneReturnSingleParameter lambda02 = (a) -> {
            System.out.println("test02"+"---"+a);
        };
        lambda02.test(123);

        System.out.println("<-----test03----->");
    // 无返回值多个参数 LambdaNoneReturnMulParameter
        LambdaNoneReturnMulParameter lambda03 = (a, b) -> {
            System.out.println("test03" + "-----" + (a + b));
        };
        lambda03.test(3,4 );

        System.out.println("<-----test04----->");
    // 有返回值单个参数 LambdaSingleReturnSingleParmter
        LambdaSingleReturnSingleParameter lambda04 = (a) -> {
            System.out.println("test04" + "---" + a);
            return a;
        };
        System.out.println(lambda04.test(5));

        System.out.println("<-----test05----->");
    // 有返回值多个参数 LambdaSingleReturnMulParameter
        LambdaSingleReturnMulParameter lambda05=(a,b)->{
            System.out.println("test05"+"---"+a+b);
            return a+b;
        };
        System.out.println(lambda05.test(3,4 ));
    }

三、语法精简

1.参数类型精简

    /**
     * 语法精简
     * 1.参数类型
     * 由于在接口的抽象方法中,已经定义了参数的数量类型 所以在Lambda表达式中参数的类型可以省略
     * 备注:如果需要省略类型,则每一个参数的类型都要省略,千万不要一个省略一个不省略
     */
    @Test
    public void test01() {
        LambdaNoneReturnMulParameter lambda1 = (int a, int b) -> {
            System.out.println("hello world"+a+b);
        };
//        可以精简为:
        LambdaNoneReturnMulParameter lambda1_ = (a, b) -> {
            System.out.println("hello world"+a+b);
        };
        lambda1_.test(1, 2);

    }

2.参数小括号精简

参数的数量只有一个,可以省略()

    /**
     * 2.参数小括号
     * 如果参数列表中,参数的数量只有一个 此时小括号可以省略
     */
    @Test
    public void test02(){
        LambdaNoneReturnSingleParameter lambda2=(a)->{
            System.out.println("hello world"+a);
        };
//        可以精简为:
        LambdaNoneReturnSingleParameter lambda2_= a->{
            System.out.println("hello world"+a);
        };
        lambda2_.test(1);
    }

3.方法大括号精简

方法体中只有一条语句,可以省略{}

    /**
     * 3.方法大括号
     * 如果方法体中只有一条语句,此时大括号可以省略
     */
    @Test
    public void test03(){
        LambdaNoneReturnSingleParameter lambda3=a->{
            System.out.println("hello world");
        };
//        可以精简为:
        LambdaNoneReturnSingleParameter lambda3_=a->System.out.println("hello world");
        lambda3_.test(2);
    }

4.大括号精简补充

方法体中唯一的一条语句是一个返回语句,可以省略return

    /**
     * 4.如果方法体中唯一的一条语句是一个返回语句
     * 贼省略大括号的同时 也必须省略return
     */
    @Test
    public void test04(){
        LambdaSingleReturnNoneParameter lambda4=()->{
            return 10;
        };
//        可以精简为:
        LambdaSingleReturnNoneParameter lambda4_=()->10;
        System.out.println(lambda4_.test());
    }

5.多参数,有返回值精简

    @Test
    public void test05(){
        LambdaSingleReturnMulParameter lambda5=(a,b)->{
            return a+b;
        };
//        可以精简为:
        LambdaSingleReturnMulParameter lambda5_=(a,b)->a+b;

        System.out.println(lambda5_.test(1, 2));
    }

四、Lambda语法进阶

—引用其他方法实现接口

1.方法引用(普通方法与静态方法)

在实际应用过程中,一个接口在很多地方都会调用同一个实现,例如:

LambdaSingleReturnMutipleParmeter lambda1=(a,b)->a+b;
LambdaSingleReturnMutipleParmeter lambda2=(a,b)->a+b;

这样一来每次都要写上具体的实现方法 a+b,如果需求变更,则每一处实现都需要更改,基于这种情况,可以将后续的是实现更改为已定义的方法,需要时直接调用就行

语法
/**
*方法引用:
* 可以快速的将一个Lambda表达式的实现指向一个已经实现的方法
* 方法的隶属者 如果是静态方法 隶属的就是一个类  其他的话就是隶属对象
* 语法:方法的隶属者::方法名
* 注意:
*  1.引用的方法中,参数数量和类型一定要和接口中定义的方法一致
*  2.返回值的类型也一定要和接口中的方法一致
*/
例:
public class Syntax {
    public static void main(String[] args) {
        LambdaSingleReturnSingleParameter lambda1=a->a*2;
        LambdaSingleReturnSingleParameter lambda2=a->a*2;
        LambdaSingleReturnSingleParameter lambda3=a->a*2;

        //简化
        LambdaSingleReturnSingleParameter lambda4=a->staticMethod(a);

        //方法引用
        LambdaSingleReturnSingleParameter lambda5=Syntax::staticMethod;
    }
    public static int staticMethod(int a){
        return a*2;
    }
}

2.方法引用(构造方法)

需求

两个接口,各有一个方法,一个接口的方法需要引用Person的无参构造,一个接口的方法需要引用Person的有参构造 用于返回两个Person对象,例:

准备(还需要之前定义的接口,在二的2中):
package lambda;

public class Syntax1 {
    public static void main(String[] args) {

    }
}
class Person {
    public String name;
    public int age;

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

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person的有参构造方法执行");
    }
}
interface PersonCreater01{
    //通过Person的无参构造实现
    Person getPerson();
}

interface PersonCreater02{
    //通过Person的有参构造实现
    Person getPerson(String name,int age);
}
测试:
		PersonCreater01 creater=()->new Person();

        //引用的是Person的无参构造
        //PersonCreater接口的方法指向的是Person的方法
        PersonCreater01 creater1=Person::new; //等价于上面的()->new Person()
        //实际调用的是Person的无参构造 相当于把接口里的getPerson()重写成new Person()。
        Person a=creater1.getPerson();

        //引用的是Person的有参构造
        PersonCreater02 creater2=Person::new;
        Person b=creater2.getPerson("张三",18);

五、综合练习(需要四中2的Person类)

1.集合排序案例

需求:已知在一个ArrayList中有若干各Person对象,将这些Person对象按照年龄进行降序排列

//需求:已知在一个ArrayList中有若干各Person对象,将这些Person对象按照年龄进行降序排列
        ArrayList<Person> list=new ArrayList<>();


        list.add(new Person("张三",10));
        list.add(new Person("李四",12));
        list.add(new Person("王五",13));
        list.add(new Person("赵六",14));
        list.add(new Person("李雷",11));
        list.add(new Person("韩梅梅",8));
        list.add(new Person("jack",10));

        System.out.println("排序前:"+list);

        //将排列的依据传入 具体的方法指向的是 内部元素的age相减 sort会依据结果的正负进行降序排列
        //sort 使用提供的 Comparator对此列表进行排序以比较元素。
        list.sort((o1, o2) -> o2.age-o1.age);

        System.out.println("排序后:"+list);

2.Treeset排序案例

treeset 自带排序 要添加进集合,必须实现Comparator接口

		/**Treeset 自带排序
         * 但是现在不知道Person谁大谁小无法排序
         * 解决方法:
         * 使用Lambda表达式实现Comparator接口,并实例化一个TreeSet对象
         * 注意:在TreeSet中如果Comparator返回值是 0 会判断这是两个元素是相同的 会进行去重
         * TreeSet<Person> set=new TreeSet<>((o1, o2) -> o2.age-o1.age);
         * 这个获取的对象打印会少一个Person
         * 此时我们将方法修改
         */

        TreeSet<Person> set=new TreeSet<>((o1, o2) ->{
            if(o1.age>=o2.age){
                return -1;
            }else {
                return 1;
            }
        });

        set.add(new Person("张三",10));
        set.add(new Person("李四",12));
        set.add(new Person("王五",13));
        set.add(new Person("赵六",14));
        set.add(new Person("李雷",11));
        set.add(new Person("韩梅梅",8));
        set.add(new Person("jack",10));

        System.out.println(set);

3.集合的遍历

		ArrayList<Integer> list=new ArrayList<>();

        Collections.addAll(list,1,2,3,4,5,6,7,8,9);
        /**
         * list.forEach(Consumer<? super E> action)
         * api文档解释: 对 集合中的每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。
         * 将集合中的每一个元素都带入到接口Consumer的方法accept中  然后方法accept指向我们的引用
         * 输出集合中的所有元素
         * list.forEach(System.out::println);
         */

        //输出集合中所有的偶数
        list.forEach(ele->{
            if(ele%2==0){
                System.out.println(ele);
            }
        });

4.删除集合中满足条件的元素

    	ArrayList<Person> list=new ArrayList<>();

        list.add(new Person("张三",10));
        list.add(new Person("李四",12));
        list.add(new Person("王五",13));
        list.add(new Person("赵六",14));
        list.add(new Person("李雷",11));
        list.add(new Person("韩梅梅",8));
        list.add(new Person("jack",10));

        //删除集合中年龄大于12的元素
        /**
         * 之前迭代器的做法
         * ListIterator<Person> it = list.listIterator();
         * while (it.hasNext()){
         *   Person ele=it.next();
         *   if(ele.age>12){
         *         it.remove();
         *   }
         * }
         */

        /**
         * lambda实现
         * 逻辑
         * 将集合中的每一个元素都带入到接口Predicate的test方法中,
         * 如果返回值是true,则删除这个元素
        */
        list.removeIf(ele->ele.age>10);
        System.out.println(list);

5.开辟一条线程 做一个数字的输出

需求:开辟一条线程 做一个数字的输出

		/**
         * 通过Runnable 来实例化线程
         */
        Thread t=new Thread(()->{
            for(int i=0;i<100;i++){
                System.out.println(i);
            }
        });
        t.start();

六、系统内置的函数式接口

 		// Predicate<T>              :     参数是T 返回值boolean  
        // 在后续如果一个接口需要指定类型的参数,返回boolean时可以指向 Predicate
        //          IntPredicate            int -> boolean
        //          LongPredicate           long -> boolean
        //          DoublePredicate         double -> boolean

        // Consumer<T>               :      参数是T 无返回值(void)
        //          IntConsumer             int ->void
        //          LongConsumer            long ->void
        //          DoubleConsumer          double ->void

        // Function<T,R>             :      参数类型T  返回值R
        //          IntFunction<R>          int -> R
        //          LongFunction<R>         long -> R
        //          DoubleFunction<R>       double -> R
        //          IntToLongFunction       int -> long
        //          IntToDoubleFunction     int -> double
        //          LongToIntFunction       long -> int
        //          LongToDoubleFunction    long -> double
        //          DoubleToLongFunction    double -> long
        //          DoubleToIntFunction     double -> int

        // Supplier<T> : 参数 无 返回值T
        // UnaryOperator<T> :参数T 返回值 T
        // BiFunction<T,U,R> : 参数 T、U 返回值 R
        // BinaryOperator<T> :参数 T、T 返回值 T
        // BiPredicate<T,U> :  参数T、U  返回值 boolean
        // BiConsumer<T,U> :    参数T、U 无返回值

        /**
         * 常用的 函数式接口
         * Predicate<T>、Consumer<T>、Function<T,R>、Supplier<T>
         */

七、Lambda闭包

ackage com.alan.closure;

import java.util.function.Supplier;

public class ClosureDemo {
    public static void main(String[] args) {

        /**
         * lambda的闭包会提升包围变量的生命周期
         * 所以局部变量 num在getNumber()方法内被 get()引用 不会在getNumber()方法执行后销毁
         * 这种方法可以在外部获取到某一个方法的局部变量
         */
        int n=getNumber().get();
        System.out.println(n);
    }
    private static Supplier<Integer> getNumber(){
        int num=10;
        /**
         * Supplier supplier=()->num;
         * return supplier;
         */
        return ()->{
            return num;
        };
    }
}
*************************************************************************
    
import java.util.function.Consumer;
public class ClosureDemo2 {
    public static void main(String[] args) {
        int a=10;
        Consumer<Integer> c=ele->{
            System.out.println(a+1);
            //System.out.println(ele);
            //System.out.println(a++); 会报错
            //在lambda中引用局部变量 这个变量必须是一个常量
        };
        //a++; 这样也会导致内部报错
        //如果在内部已经引用局部变量 参数传递后 打印的还是 10
        c.accept(1);
    }
}

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的Lambda表达式Java SE 8中引入的新特性,它是一种匿名函数,可以作为函数式接口的实例使用,能够简化代码,使得Java代码更加简洁、易读和灵活。 Lambda表达式的语法如下: (parameter1, parameter2, ..., parameterN) -> { statement1; statement2; ... } 其中,参数列表可以为空,也可以有一个或多个参数;箭头 -> 表示传递参数到方法体;方法体可以是一个语句块,也可以是一个表达式。 下面对Lambda表达式的详细使用进行讲解: 1. Lambda表达式作为函数式接口的实例 函数式接口是只有一个抽象方法的接口,并且该接口可以被Lambda表达式所实现。例如,Java中的Runnable接口就是一个函数式接口,可以使用Lambda表达式来实现它。 示例代码: ```java // 使用Lambda表达式实现Runnable接口 Runnable runnable = () -> { System.out.println("Hello, Lambda!"); }; // 使用Lambda表达式创建线程 Thread thread = new Thread(runnable); thread.start(); ``` 2. Lambda表达式作为方法参数 可以将Lambda表达式作为方法的参数进行传递。例如,Java中的Collections.sort()方法可以接受一个Comparator接口的实例作为参数,使用Lambda表达式可以更加方便地实现该接口。 示例代码: ```java // 使用Lambda表达式实现Comparator接口 List<Integer> list = Arrays.asList(5, 3, 1, 2, 4); Collections.sort(list, (a, b) -> a.compareTo(b)); System.out.println(list); // [1, 2, 3, 4, 5] ``` 3. Lambda表达式作为返回值 可以将Lambda表达式作为方法的返回值进行返回。例如,Java中的Supplier接口表示一个供应商,可以使用Lambda表达式来实现它。 示例代码: ```java // 使用Lambda表达式实现Supplier接口 public static Supplier<String> getSupplier() { return () -> "Hello, Lambda!"; } // 使用Lambda表达式获取Supplier接口实例 Supplier<String> supplier = getSupplier(); System.out.println(supplier.get()); // Hello, Lambda! ``` Lambda表达式使用可以大大简化Java代码,提高代码的可读性和灵活性。但是,需要注意Lambda表达式只能用于函数式接口,否则编译器会报错。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值