第23篇:匿名类的排序、Lambda 表达式、方法引用

简介: 🔖 Lambda Expression 是 Java8 开始才有的语法🔖 函数式接口(Functional Interface):只包含1个抽象方法的接口(可以包含多个默认方法和静态方法)📕 可以在接口上加上@FunctionalInterface注解,表示它是一个函数式接口🔖 当匿名类实现的是函数式接口的时候,可以使用 Lambda 表达式简化代码的书写(但是匿名类和 Lambda 在作用域上还是有点区别的)

一、匿名类排序

☘️ Java 官方通过 匿名类这种语法,让使用者可以传入 不同的排序逻辑(是升序排序,还是倒序排序)

🔖 可以使用java.util.Arrays类对数组进行排序

Arrays.sort() 进行升序排序:

public class TestDemo {
    public static void main(String[] args) {
        int[] ints = {5, 2, 0, 1, 3, 1, 4, 8, 7, 22, 35, 51, 6};

        /* 使用 Arrays.toString() 可以打印数组里面的内容 */
        // [5, 2, 0, 1, 3, 1, 4, 8, 7, 22, 35, 51, 6]
        System.out.println(Arrays.toString(ints));

        /* Arrays.sort() 可对数组进行升序排序(默认就是升序排序) */
        Arrays.sort(ints);

        // [0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 22, 35, 51]
        System.out.println(Arrays.toString(ints));
    }
}
☘️ 通过该方法还可对数组进行倒顺序排序,这就需要通过匿名类语法传入排序逻辑了。

Arrays.sort() 进行降序排序:

public class TestDemo {
    public static void main(String[] args) {
        Integer[] intArr = {5, 2, 0, 1, 3, 1, 4, 8, 7, 22, 35, 51, 6};

        /* 使用 Arrays.toString() 可以打印数组里面的内容 */
        // [5, 2, 0, 1, 3, 1, 4, 8, 7, 22, 35, 51, 6]
        System.out.println(Arrays.toString(intArr));

        /* Arrays.sort() 可对数组进行降序排序 */
        Arrays.sort(intArr, new Comparator<Integer>() {
            @Override
            public int compare(Integer i1, Integer i2) {
                // return 0; // 相当于没有进行排序操作
                // return i1 - i2; // 升序排序
                return i2 - i1; // 降序排序
            }
        });

        // [51, 35, 22, 8, 7, 6, 5, 4, 3, 2, 1, 1, 0]
        System.out.println(Arrays.toString(intArr));
    }
}
☘️ Comparator 是 jdk 自带的一个接口
☘️ Comparator 中有一个 compare 方法( compare 方法中可以指定是降序还是升序)【具体看上面的代码】

二、Lambda 表达式

(1) Lambda 基本使用

🔖 Lambda Expression 是 Java8 开始才有的语法

🔖 函数式接口(Functional Interface):只包含1个抽象方法的接口(可以包含多个默认方法和静态方法)

📕 可以在接口上加上 @FunctionalInterface注解,表示它是一个函数式接口

🔖 当匿名类实现的是函数式接口的时候,可以使用 Lambda 表达式简化代码的书写(但是匿名类和 Lambda 在作用域上还是有点区别的)

---
Lambda 表达式格式:

   /*
       Lambda 表达式格式:
       (parameter list) -> {
           return xxx;
       }
    */
📕 Lambda 表达式的格式和 JavaScript 中的 箭头函数非常相似
📕 parameter list:指函数式接口里面唯一的 抽象方法的参数列表(若那个唯一的抽象方法没有参数,可不写)

计算代码执行时间的工具类(上篇文章介绍的):

/**
 * 计算某段代码的执行时间
 */
public class CodeTimes {

    @FunctionalInterface
    public interface BlockInter {
        void passCode();
    }

    public static void check(String description, BlockInter codeBlock) {
        if(codeBlock == null) return;
        
        System.out.println("\n----------------------------");
        System.out.println("测试功能:" + description);
        long beginTime = System.currentTimeMillis();

        codeBlock.passCode();

        long endTime = System.currentTimeMillis();
        long duration = (endTime - beginTime) / 1000;
        System.out.println("代码执行花费时间:" + duration + "秒");
        System.out.println("----------------------------");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        CodeTimes.check("简单测试1", () -> {
            String string = "Happy";
            for (int i = 0; i < 50000; i++) {
                string += i;
            }
        });

        CodeTimes.check("简单测试2", () -> {
            test();
        });
    }

    private static void test() {
        StringBuilder string = new StringBuilder("Happy");
        for (int i = 0; i < 50000; i++) {
            string.append(i);
        }
    }

    /*
            ----------------------------
            测试功能:简单测试1
            代码执行花费时间:6秒
            ----------------------------

            ----------------------------
            测试功能:简单测试2
            代码执行花费时间:0秒
            ----------------------------
     */
}
📕 本篇文章第一节中用到的 Arrays.sort() 进行降序排序的时候使用到的 Comparator 也是函数式接口
📕 它的书写方式也可以使用 Lambda 表达式进行简化

Lambda 简化 Arrays.sort() 进行降序排序时候的 Comparator 接口的写法:

public class TestDemo {
    public static void main(String[] args) { 
        Integer[] intArr = {1, 3, 5, 7, 9, 2, 6, 8, 10};
        
        // 降序排序
        Arrays.sort(intArr, (Integer i1, Integer i2) -> {
            return i2 - i1;
        });

        // [10, 9, 8, 7, 6, 5, 3, 2, 1]
        System.out.println(Arrays.toString(intArr));
    }
}

(2) Lambda 更加简化

✏️ 参数列表可以省略参数类型
✏️ 当只有一条语句的时候:可以省略大括号、分号和return
✏️ 当只有一个参数的时候:可以省略小括号(一个参数都没有的时候不能省略小括号)
更加简化后的降序排序代码:

public class TestDemo {
    public static void main(String[] args) {
        Integer[] intArr = {1, 3, 5, 7, 9, 2, 6, 8, 10};

        // 降序排序
        Arrays.sort(intArr, (i1, i2) -> i2 - i1);

        // [10, 9, 8, 7, 6, 5, 3, 2, 1]
        System.out.println(Arrays.toString(intArr));
    }
}

(3) Lambda 使用注意

✏️ Lambda 只能访问 final 或有效 final 的局部变量(和匿名类一样)
✏️ Lambda 没有引入新的作用域(和匿名类不同)

@FunctionalInterface
interface Testable {
    void test(int p);
}

public class OuterClass {
    private int age = 666;

    public class InnerClass {
        private int age = 888;

        void inner() {
            // int p = 123; // ERROR: Variable p is already defined in the scope
            Testable t = p -> { // p 只能在 Lambda 的大括号里面使用
                System.out.println(p); // 678
                System.out.println(age); // 888 (Lambda 表达式没有引入新的作用域)
                System.out.println(this.age); // 888 (Lambda 表达式没有引入新的作用域)
                System.out.println(InnerClass.this.age); // 888
                System.out.println(OuterClass.this.age); // 666
            };
            t.test(678);
        }
    }
}

class TestDemo {
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.inner();
    }
}

匿名类和 Lambda 表达式区别测试代码:

@FunctionalInterface
interface Testable {
    void test(int p);
}

public class OuterClass {
    private int age = 666;

    public class InnerClass {
        private int age = 888;

        void inner() {
            /* 匿名类类似局部类(可以访问外部类的所有成员) */
            Testable t = new Testable() {
                // int age = 5;

                @Override
                public void test(int p) {
                    // System.out.println(this.age); // ERROR:age 未定义
                    System.out.println(age); // 888
                    System.out.println(p); // 678
                }
            };
            t.test(678);
        }
    }
}

三、方法引用

✏️ 方法引用:Method Reference
✏️ 若 Lambda 中的内容仅仅是调用某个方法,可以使用方法引用来简化
✏️ Lambda 表达式是对匿名类的简化,方法引用是对 Lambda 表达式的简化

🌻 引用静态方法: ClassName::staticMethodName
🌻 引用特定对象的实例方法: ObjectName::instanceMethodName
🌻 引用特定类型的任意对象的实例方法: ClassName::methodName
🌻 引用构造方法: Class:new
🌻 引用当前类中定义的实例方法: this::instanceMethodName
🌻 引用父类中定义的实例方法: super::instanceMethodName

💡 平时写代码的时候把它写成 Lambda 表达式即可,编译器会帮忙简化代码的书写

相关文章
|
3月前
Lambda表达式方法引用举例
Lambda表达式方法引用举例
22 1
|
10月前
|
分布式计算 Java 数据安全/隐私保护
Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(下 )
Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(下)
53 0
Lambda 语法糖《方法引用》
Lambda 语法糖《方法引用》
|
3月前
|
存储 Python 容器
python函数的返回值、嵌套方式以及函数中的变量(一)
python函数的返回值、嵌套方式以及函数中的变量(一)
220 2
|
3月前
|
Python
python函数的返回值、嵌套方式以及函数中的变量(二)
python函数的返回值、嵌套方式以及函数中的变量(二)
232 1
|
3月前
|
JavaScript 前端开发 Java
23、匿名类的排序、Lambda 表达式、方法引用
23、匿名类的排序、Lambda 表达式、方法引用
24 0
|
10月前
|
Java Kotlin
Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(上)
Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(上)
45 0
|
11月前
引用作为重载条件
引用作为重载条件
34 0
|
存储 算法 编译器
【C++】lambda 表达式 | 包装器
【C++】lambda 表达式 | 包装器
【C++】lambda 表达式 | 包装器
|
安全 Java
Lambda、方法引用、函数式接口
Lambda、方法引用、函数式接口