lambda表达式

本文深入探讨了Java 8的Lambda表达式,它简化了匿名内部类的使用,使得代码更加简洁。Lambda表达式适用于函数式接口,可以推导参数类型、省略参数括号和函数体花括号,尤其在处理多线程和集合排序等场景下,表现出高效和灵活性。通过实例展示了Lambda如何逐步替代匿名内部类,强调了其在面向对象和函数式编程思想中的作用。
摘要由CSDN通过智能技术生成

lambda表达式

首先,我们要明白lambda表达式在表达什么?答案就是lambda表达式表达接口函数的实现。

传统方式如下(经典OOP的实现样式):

public class LambdaDemo {
    //函数定义 方法printSomething定义行为,可以是控制台打印,也可以是其他的打印行为
    public void printSomething(String something) {
        System.out.println(something);
    }
    //通过创建对象调用函数
    public static void main(String[] args) {
        LambdaDemo demo = new LambdaDemo();
        String something = "I am learning Lambda";
        demo.printSomething(something);
    }
}

对上面代码进行修改 ,创建一个功能接口,并对该接口定义抽象方法。

public class LambdaDemo {
    //创建一个功能接口,并对该接口定义抽象方法。
    interface Printer {
        void print(String val);
    }
    //通过参数传递功能接口
    public void printSomething(String something, Printer printer) {
        printer.print(something);
    }
}

在上述实现中,Printer接口负责定义打印行为,可以是控制台打印,也可以是其他的打印行为。方法printSomething不再定义行为,这样的设计更加灵活。代码如下:

public static void main(String[] args) {
    LambdaDemo demo = new LambdaDemo();
    String something = "I am using a Functional interface";
    //实现Printer接口
    Printer printer = new Printer() {
        @Override
        public void print(String val) {
            //控制台打印
            System.out.println(val);
        }
    };
    demo.printSomething(something, printer);
}

上面使用的是匿名内部类实现的,至此我们都尚未使用lambda表达式。我们仅创建了Printer接口的具体实现,并将其传递给printSomething方法。

lambda表示式实现方式
现在,我们使用lambda表达式重构一下代码

public static void main(String[] args) {
    LambdaDemo demo = new LambdaDemo();
    String something = "I am learning Lambda";
    //实现Printer接口(请关注下面这行lambda表达式代码)
    Printer printer = (String toPrint)->{System.out.println(toPrint);};
    //调用接口打印
    demo.printSomething(something, printer);
}

lambda表达式使我们代码更简洁。实际上使用lambda表达式在性能和多核处理还有更多的好处,但是只有在理解java8 Streams API之后它们才有意义
代码量是不是减少了很多?但这仍然不是最简的实现方式,我们一步一步来。

Printer printer = (String toPrint)->{System.out.println(toPrint);};
//简化:去掉参数类型
Printer printer = (toPrint)->{System.out.println(toPrint);};
//简化:去掉参数括号
Printer printer = toPrint->{System.out.println(toPrint);};
//简化:去掉函数体花括号
Printer printer = toPrint->System.out.println(toPrint);

即使没有在箭头的左侧指定参数的类型,编译器也会从接口方法的形式参数中推断出其类型
当只有一个参数的时候,我们完全可以省略参数的括号
当函数体只有一行的时候,我们完全可以省略函数体花括号

如果我们的接口方法定义不带任何参数,则可以用空括号替换:

()->  System.out.println("anything you wan to print")

那么,我们最终通过lambda表达式,简化完成的代码是:

public static void main(String[] args) {
    LambdaDemo demo = new LambdaDemo();
    String something="I am Lambda";
    //关注下面的这行代码
    demo.printSomething(something, toPrint -> System.out.println(toPrint));
}

面向对象思想:怎么做。
函数式编程思想:做什么

 匿名内部类的格式:
        new 父类或接口() {
            重写方法
        }
     匿名内部类中很多东西都是冗余的,在匿名内部类中核心的东西是方法的参数,方法体,返回值,最好的情况只关注这三点。
     在整个匿名内部类中最重要的是方法的前中后三点。
        前:方法参数
        中:方法体
        后:返回值。
    使用Lambda表达式可以让我们只关注方法参数,方法体,返回值这三个内容。
    Lambda表达式可以省去面向对象中的条条框框,让我们只关注最核心的内容。

Lambda表达式是函数式编程思想,函数式编程思想中,可推导,就是可省略。
比如在使用匿名内部类完成多线程代码中。

因为Thread构造方法中需要传递一个Runnable类型的参数,所以我们不得不写了new Runnable
因为匿名内部类中要重写方法,所以我们又不得不写了run方法的声明部分(public void run)

如果使用Lambda表达式,可以只关注最核心的内容,可以解决匿名内部类的冗余
Lambda是匿名内部类的简化写法
Lambda表达式使用的是函数式编程思想

public static void main(String[] args) {
        //使用匿名内部类的方式完成多线程。
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行了");
            }
        }).start();

        //Lambda表达式初体验
        // 因为Runnable中只有一个抽象方法叫做run,所以在重写该方法时可以省略public void run
        new Thread(() -> System.out.println(Thread.currentThread().getName()  + "执行了")).start();
    }
  • 标准格式
    Lambda表达式的标准格式:
    (参数类型 参数名) -> {
    方法体;
    return 返回值;
    }

     格式解释:
     	1. 小括号中的参数和之前方法小括号中的参数是基本一致的。如果有多个参数,使用逗号隔开。
     	2. -> 是一个运算符,表示指向性的动作。
     	3. 大括号里面的内容和之前方法大括号中的内容是一样的。
     	4. lambda表达式,表达的是接口函数
    
  • 省略格式
    省略规则:
    1. 小括号中的参数类型可以省略。
    2. 如果小括号中只有一个参数,小括号能够省略。
    3. 如果大括号中只有一条语句,那么可以省略大括号,return,以及分号。

public static void main(String[] args) {
        //使用匿名内部类完成多线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行了");
            }
        }).start();

        //使用Lambda标准格式完成多线程
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "执行了");
        }).start();
        //使用Lambda表达式省略格式完成多线程
        new Thread(() -> System.out.println(Thread.currentThread().getName() + "执行了")).start();
    }
  • 使用前提

     Lambda表达式的使用前提:
     1. 必须要有接口(不能是抽象类),接口中必须有且仅有一个需要被重写的抽象方法。(函数式接口)(比如Runnable或Comparator)
     2. 必须支持上下文推导。要能够推导出来Lambda表达式表示的是哪个接口中的哪个方法
     
     	最常用的一种上下文推导的方式是使用【函数式接口】当做参数,然后传递Lambda表达式。
    

注意:
如果一个接口中有且仅有一个需要被重写的抽象方法,那么这个接口就是函数式接口

Lambda表达式虽然是匿名内部类的简化写法,但是不能完全替换匿名内部类。
        1. 匿名内部类不仅可以使用接口,也可以使用抽象类或者普通类。
           Lambda表达式只支持接口。
        2. 匿名内部类中可以重写多个方法。
           Lambda表达式要求接口中只有一个抽象方法,Lambda表达式只能表示这一个方法。
    public static void main(String[] args) {
        //() -> System.out.println(Thread.currentThread().getName() + "执行了");

        //因为Thread构造方法需要传递Runnable接口类型的参数,而Runnable接口中只有一个需要被重写的抽象方法叫做run
        //所以向Thread构造方法位置传递的Lambda表示必然表示Runnable接口中的run方法。
        new Thread(() -> System.out.println(Thread.currentThread().getName() + "执行了")).start();
    }
	
	// 使用比较器排序对集合中的Person对象按照年龄从小到大的顺序排序

    public static void main(String[] args) {
        //创建集合
        List<Person> list = new ArrayList<>();
        //添加Person对象
        list.add(new Person("jack", 20));
        list.add(new Person("rose", 18));
        list.add(new Person("tony", 22));
        //使用比较器排序(对集合中的Person对象按照年龄从小到大的顺序排序)
        //单独定义Comparator实现类,然后创建实现类对象。
        //Collections.sort(list, new Rule());

        //使用匿名内部类完成比较器排序
        /*
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        */

        /*
            (参数类型 参数名) -> {
                方法体;
                return 返回值;
            }
         */
        //使用Lambda表达式完成比较器排序
        /*
        Collections.sort(list, (Person o1, Person o2) -> {
            return o1.getAge() - o2.getAge();
        });
        */

        //使用Lambda表达式省略格式完成比较器排序
        Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());


        //输出结果
        System.out.println(list);
    }
public class Rule implements Comparator<Person>{
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge() - o2.getAge();
    }
}
public class Person {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Person() {
    }

    public Person(String name, int age) {

        this.name = name;
        this.age = age;
    }

    public String getName() {

        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值