01. 分析匿名内部类存在的问题分析,使用Lambda表达式优化

34 阅读4分钟

我们要使用JDK8新特性,请务必调试好IDEA这两个配置。

image.png

image.png

(一)匿名内部类存在的问题分析

package com.lambda;

/**
 * @Author:kaiyang.cui
 * @Package:com.lambda
 * @Project:jdk8
 * @name:Demo01
 * @Date:2023/4/2 下午2:59
 * @Filename:Demo01
 * @Description:匿名内部类存在的问题
 * @Version:1.0
 */
public class Demo01 {

    public static void main(String[] args) {
        new Thread(new Runnable() {
        
            @Override
            public void run() {
                System.out.println("新线程中执行的代码:" + Thread.currentThread().getName());
            }
        }).start();

        System.out.println("主线程中的代码:"+ Thread.currentThread().getName());
    }
}

image.png

Result:

主线程中的代码:main
新线程中执行的代码:Thread-0

(二)Lambda表达式的使用

Lambda表达式是一个匿名函数,可以理解为一段可以传递的代码

package com.lambda;

/**
 * @Author:kaiyang.cui
 * @Package:com.lambda
 * @Project:jdk8
 * @name:Demo01
 * @Date:2023/4/2 下午2:59
 * @Filename:Demo01
 * @Description:使用Lambda表达式优化线程问题
 * @Version:1.0
 */
public class Demo01 {

    public static void main(String[] args) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("新线程中执行的代码:" + Thread.currentThread().getName());
            }
        }).start();

        System.out.println("主线程中的代码:"+ Thread.currentThread().getName());


        new Thread(() -> {
            System.out.println("新线程Lambda表达式..." + Thread.currentThread().getName());
        }).start();
    }

}

Result:

主线程中的代码:main
新线程中执行的代码:Thread-0
新线程Lambda表达式...Thread-1

Lambda表达式的优点:

简化了匿名内部类的使用,语法更加简单。

匿名内部类语法冗余,体验了Lambda表达式后,发现Lambda表达式是简化匿名内部类的一种方式。

Lambda的语法规则

~~public~~ ~~static~~ ~~void~~ ~~main~~(String[] args){}

Lambda表达式不关注权限控制符,不关注表述static,不关注方法的返回类型,更不会关注方法的名称, 针对的是参数列表方法体

Lambda会讲关注的部分做一个变形: 由原来的

(String[] args){}

变为:

(String[] args) -> {}

Lambda 表达式省去了面向对象的条条框框。Lambda 的标准格式由3个部分组成

(参数类型 参数名称) -> {

}

说明:

  • (参数类型 参数名称) 方法体
  • {} 代码体
  • ->: 箭头,分割参数列表和方法体

2.1 Lambda 练习1 【无参无返回值】

package com.lambda.service;

/**
 * @Author:kaiyang.cui
 * @Package:com.lambda.service
 * @Project:jdk8
 * @name:UserService
 * @Date:2023/4/2 下午3:43
 * @Filename:UserService
 * @Description:UserService
 * @Version:1.0
 */
public interface UserService {

    void show();
}

使用匿名内部类调用接口

package com.lambda;

import com.lambda.service.UserService;

/**
 * @Author:kaiyang.cui
 * @Package:com.lambda
 * @Project:jdk8
 * @name:Demo01
 * @Date:2023/4/2 下午2:59
 * @Filename:Demo01
 * @Description:参数中传递接口,应该使用内部类的方式调用。
 * @Version:1.0
 */
public class Demo02 {

    public static void main(String[] args) {
        /**
         * 参数是接口,接口不能实例化,只能通过内部类的方式调用
         */
        goShow(new UserService() {
            @Override
            public void show() {
                System.out.println("show 方法被调用");
            }
        });

    }
    public static void goShow(UserService userService){
        userService.show();
    }
}

使用lambda优雅的完成调用:

package com.lambda;

import com.lambda.service.UserService;

/**
 * @Author:kaiyang.cui
 * @Package:com.lambda
 * @Project:jdk8
 * @name:Demo01
 * @Date:2023/4/2 下午2:59
 * @Filename:Demo01
 * @Description:参数中传递接口,应该使用内部类的方式调用,但是不优雅,使用Lambda优雅的调用
 * @Version:1.0
 */
public class Demo03 {

    public static void main(String[] args) {
        goShow(()->{
            System.out.println("lambda show 方法被调用");
        });
    }
    public static void goShow(UserService userService){
        userService.show();
    }
}

2.2 Lambda 练习2 【有参有返回值】

我们在List集合中保存多个Person对象,然后对这些对象根据age做升序操作。

使用内部类实现递增排序

package com.lambda.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author:kaiyang.cui
 * @Package:com.lambda.domain
 * @Project:jdk8
 * @name:Person
 * @Date:2023/4/2 下午3:58
 * @Filename:Person
 * @Description:Person实体类
 * @Version:1.0
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {

    private String name;

    private Integer age;

    private Integer height;
}
package com.lambda;

import com.lambda.domain.Person;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author:kaiyang.cui
 * @Package:com.lambda
 * @Project:jdk8
 * @name:Demo01
 * @Date:2023/4/2 下午2:59
 * @Filename:Demo01
 * @Description:排序问题
 * @Version:1.0
 */
public class Demo04 {

    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();

        list.add(new Person("周杰伦4", 24, 184));
        list.add(new Person("周杰伦1", 21, 181));
        list.add(new Person("周杰伦5", 25, 185));
        list.add(new Person("周杰伦3", 23, 183));
        list.add(new Person("周杰伦2", 22, 182));

        // 排序
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        });

        for (Person person : list) {
            System.out.println("person = " + person);
        }

    }

}

Result:

person = Person(name=周杰伦1, age=21, height=181)
person = Person(name=周杰伦2, age=22, height=182)
person = Person(name=周杰伦3, age=23, height=183)
person = Person(name=周杰伦4, age=24, height=184)
person = Person(name=周杰伦5, age=25, height=185)

优雅的使用lambda排序

我们发现sort方法的第二个参数是Comparator接口的匿名内部类,且执行的方法和返回值,那么我们可以改写为Lambda表达式。

package com.lambda;

import com.lambda.domain.Person;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @Author:kaiyang.cui
 * @Package:com.lambda
 * @Project:jdk8
 * @name:Demo01
 * @Date:2023/4/2 下午2:59
 * @Filename:Demo01
 * @Description:排序问题-Lambda解决
 * @Version:1.0
 */
public class Demo05 {

    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();

        list.add(new Person("周杰伦4", 24, 184));
        list.add(new Person("周杰伦1", 21, 181));
        list.add(new Person("周杰伦5", 25, 185));
        list.add(new Person("周杰伦3", 23, 183));
        list.add(new Person("周杰伦2", 22, 182));

        Collections.sort(list,(Person o1,Person o2) -> {
            return o1.getAge() - o2.getAge();
        });

        for (Person person : list) {
            System.out.println("person = " + person);
        }

    }

}

Result:

person = Person(name=周杰伦1, age=21, height=181)
person = Person(name=周杰伦2, age=22, height=182)
person = Person(name=周杰伦3, age=23, height=183)
person = Person(name=周杰伦4, age=24, height=184)
person = Person(name=周杰伦5, age=25, height=185)

FunctionalInterface 注解说明

public interface UserService {

    void show();

    void show2();
}

在接口中再定一个方法,我们神奇的发现,报错了,

image.png

我们使用UserService接口必须得有一个抽象方法。

怎么保证接口中只有一个抽象方法呢?

@FunctionalInterface

@FunctionalInterface注解的作用就是保证注解所修饰的抽象方法只能定义一个抽象方法!!!!