一、匿名类排序
☘️ 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 表达式即可,编译器会帮忙简化代码的书写