当前位置:   article > 正文

JDK8新特性(一):Lambda表达式_jdk8链式表达式

jdk8链式表达式

1.首先来个Demo

  1. public class LambdaDemo {
  2. public static void main(String[] args) {
  3. //开启一个线程
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. System.out.println("新线程执行代码");
  8. }
  9. }).start();
  10. }
  11. }

分析:

   当我们以 new Thread().start() 的方式启动一个线程时,我们做了如下3件事情:

  1. 定义了一个没有名字的类(匿名类)
  2. 这个类的参数,调用的是 Runnable 接口
  3. 我们通过 new Runnable(){...}的方式创建了这个类,并重写了该接口的 run() 方法

   在这个示例中,其实我们关注的并不是 new Runnable() 这个过程,而是如下2点:

  1. run() 方法    (参数情况)
  2. {...}方法体中执行的代码

Lambda表达式的出现

    在以上Demo中,针对使用匿名内部类语法冗余的问题,JDK8推出了 Lambda 表达式。

  1. Lambda表达式体现的是函数式编程思想,只需要将要执行的代码放到函数中即可(函数就是类中的方法);
  2. Lambda表达式就是一个匿名函数,我们只需要将执行的代码放到 Lambda 表达式中即可。

Lambda表达式格式

    Lambda省去面向对象的条条框框,Lambda的标准格式由3部分组成:

  1. (参数类型 参数名称) -> {
  2. 方法体;
  3. return 返回值;
  4. }

  格式说明: 

  1. (参数类型 参数名称):参数列表部分
  2. {...}:方法体,即要执行的代码部分
  3. ->:箭头,无实际含义,起到连接参数列表方法体的作用

Lambda 表达式的省略规则

  1. 小括号中的参数类型可以省略
  2. 如果小括号中只有一个参数,那么可以省略小括号
  3. 如果大括号中只有一条语句,那么可以同时省略大括号、return关键字及语句分号

使用Lambda表达式改造

  1. public class LambdaDemo {
  2. public static void main(String[] args) {
  3. //匿名内部类方式
  4. new Thread(new Runnable() {
  5. @Override
  6. public void run() {
  7. System.out.println("新线程执行代码了");
  8. }
  9. }).start();
  10. //体验Lambda表达式
  11. new Thread(() ->{
  12. System.out.println("Lambda表达式执行了");
  13. }).start();
  14. }
  15. }

Lambda表达式的好处

☆ 可以简化匿名内部类,让代码更加精简

☆ Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。

Lambda表达式练习

1.无参数无返回值的Lambda表达式

   ①定义一个接口类ISwim,接口中定义一个抽象方法 swimming();

  1. /**
  2. * ISwim接口
  3. */
  4. public interface ISwim {
  5. //swimming()抽象方法
  6. public abstract void swimming();
  7. }

   ②定义一个方法 goSwimming(ISwim swim),注意该方法参数是一个接口类ISwim。然后 main 中调用该方法;

  1. public class LambdaDemo {
  2. public static void main(String[] args) {
  3. //1.使用匿名内部类方式
  4. goSwimming(new ISwim() {
  5. @Override
  6. public void swimming() {
  7. System.out.println("我是匿名内部类的游泳");
  8. }
  9. });
  10. //2.Lambda表达式方式
  11. goSwimming(()->{
  12. System.out.println("我是Lambda表达式的游泳");
  13. });
  14. }
  15. //goSwimming(ISwim swim) 方法
  16. public static void goSwimming(ISwim swim){
  17. swim.swimming();
  18. }
  19. }
  20. //测试结果:
  21. // 我是匿名内部类的游泳
  22. // 我是Lambda表达式的游泳

2.有参数有返回值的Lambda表达式

   ①定义一个接口类ISmoke,接口中定义一个具有返回值(int)的抽象方法 smoking();

  1. /**
  2. * ISmoke接口
  3. */
  4. public interface ISmoke {
  5. //smoking()抽象方法
  6. public abstract int smoking(String name);
  7. }

   ②定义一个方法 goSwimming(ISwim swim),注意该方法参数是一个接口类ISwim。然后 main 中调用该方法;

  1. public class LambdaDemo {
  2. public static void main(String[] args) {
  3. //1.使用匿名内部类方式
  4. goSmoking(new ISmoke() {
  5. @Override
  6. public int smoking(String name) {
  7. System.out.println("匿名内部类:抽了"+ name + "牌香烟");
  8. return 5;
  9. }
  10. });
  11. //2.使用Lambda表达式方式
  12. goSmoking((String name)->{
  13. System.out.println("Lambda表达式:抽了"+ name + "牌香烟");
  14. return 6;
  15. });
  16. }
  17. //有参数有返回值的Lambda
  18. public static void goSmoking(ISmoke smoke){
  19. int i = smoke.smoking("中华");
  20. System.out.println("返回值:"+i);
  21. }
  22. }
  23. //测试结果:
  24. // 匿名内部类:抽了中华牌香烟
  25. // 返回值:5
  26. // Lambda表达式:抽了中华牌香烟
  27. // 返回值:6

日常工作中的案例

       我们有一个List集合,集合中存放了 4个Person对象,Person对象中有 name,age,height 属性。对集合进行排序,我们会使用到 Collections 工具类中的 Collections.sort()方法。

      sort()方法中传递的两个参数:1.list集合   2.Comparator 比较器。我们发现 Comparator 是一个接口,所以此处也可以使用 Lambda 表达式来替代匿名内部类。

  1. /**
  2. * Person实体类
  3. */
  4. public class Person {
  5. private String name;
  6. private int age;
  7. private int height;
  8. public Person(String name, int age, int height) {
  9. this.name = name;
  10. this.age = age;
  11. this.height = height;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public int getAge() {
  20. return age;
  21. }
  22. public void setAge(int age) {
  23. this.age = age;
  24. }
  25. public int getHeight() {
  26. return height;
  27. }
  28. public void setHeight(int height) {
  29. this.height = height;
  30. }
  31. @Override
  32. public String toString() {
  33. return "Person{" +
  34. "name='" + name + '\'' +
  35. ", age=" + age +
  36. ", height=" + height +
  37. '}';
  38. }
  39. }
  1. public class CollectionsLambdaDemo{
  2. public static void main(String[] args) {
  3. List<Person> persons = new ArrayList<>();
  4. persons.add(new Person("刘德华",58,174));
  5. persons.add(new Person("张学友",56,176));
  6. persons.add(new Person("郭富城",54,171));
  7. persons.add(new Person("黎明",53,178));
  8. //1.匿名内部类,对集合进行排序
  9. Collections.sort(persons, new Comparator<Person>() {
  10. //年龄降序排序
  11. @Override
  12. public int compare(Person o1, Person o2) {
  13. return o2.getAge() - o1.getAge();
  14. }
  15. });
  16. for (Person person: persons) {
  17. System.out.println(person);
  18. }
  19. System.out.println("-----------------------------------");
  20. //2.Lambda表达式
  21. Collections.sort(persons,(Person o1,Person o2) ->{
  22. return o1.getAge() - o2.getAge();
  23. });
  24. for (Person person: persons) {
  25. System.out.println(person);
  26. }
  27. }
  28. }
  29. //测试结果:
  30. Person{name='刘德华', age=58, height=174}
  31. Person{name='张学友', age=56, height=176}
  32. Person{name='郭富城', age=54, height=171}
  33. Person{name='黎明', age=53, height=178}
  34. -----------------------------------
  35. Person{name='黎明', age=53, height=178}
  36. Person{name='郭富城', age=54, height=171}
  37. Person{name='张学友', age=56, height=176}
  38. Person{name='刘德华', age=58, height=174}

Lambda表达式使用的前提条件

1.方法的参数局部变量类型必须为接口!!!,才能使用Lambda

   eg:局部变量类型:(Runnable是一个接口)
       匿名内部类方式:
             Runnable r = new Runnable(){
                 @override
                 public void run(){
                     System.out.println("xxx");
                 }
             }
       这种情况,你要来个局部变量,可以使用 Lambda表达式
            Runnable r = ()-> System.out.println("xxx");

2.接口中有且仅有一个抽象方法

       JDK8中,只有一个抽象方法的接口称为函数式接口,我们就能使用 Lambda。


       针对一个接口中,是否有大于一个抽象方法?JDK8为我们新增了一个注解:@FunctionalInterface。它能够帮助我们检测这个接口是不是只有一个抽象方法,如果有两个抽象方法,则会报错。

Lambda表达式原理分析

       请跳转学习:Lambda表达式原理分析

Lambda 和 匿名内部类对比

1.所需的类型不一样

     匿名内部类,需要的类型可以使类,抽象类,接口;

     Lambda表达式,需要的类型必须是接口。

2.抽象方法的数量不一样

     匿名内部类所需的接口中抽象方法的数量随意;

     Lambda表达式所需的接口只能有一个抽象方法。

3.实现原理不同

     匿名内部类是在编译后,会形成额外的一个 类名$0 的.class文件

     Lambda 表达式实在程序运行的时候动态生成 .class 文件

总结

       当接口中只有一个抽象方法时,建议使用 Lambda 表达式;其他情况下,还是需要使用匿名内部类。


附:JDK8新特性(目录)

       本目录为 JDK8新特性 学习目录,包含JDK8 新增全部特性的介绍。

       如需了解,请跳转链接查看:我是跳转链接


博主写作不易,来个关注呗

求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙

博主不能保证写的所有知识点都正确,但是能保证纯手敲,错误也请指出,望轻喷 Thanks♪(・ω・)ノ

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/726771
推荐阅读
相关标签
  

闽ICP备14008679号