方法引用与函数式编程
先引入一个问题, 在js中, func()与func 有什么区别呢?
1 2 3
| function func(){ console.log("这是一个函数"); }
|
区别就是func()是调用函数, 他的值是函数的返回值(这里返回值为undefined); 而func是函数引用, 他的值是函数的地址
那么在Java中, 如何实现?
在java的语法里, 以Arrays的sort方法为例, Arrays.sort()是调用方法; Arrays::sort是引用方法;
有什么用呢?
看个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public void func(Consumer<String> print) { print.accept("Hello Java8"); }
@Test public void test() { func(System.out::print); func(str -> System.out.println(str)); }
|
执行测试方法test() , 会打印出两个 “Hello Java8”
大概等同于js中的如下代码: (感觉js简单多了)
1 2 3 4 5 6 7 8 9
| function func(print) { print("Hello java8"); }
func(console.log);
func(str => { console.log(str); });
|
Consumer 对函数的参数和返回值都进行了限制, 还有其他类型的API, 见: Java 8 函数式接口 | 菜鸟教程 (runoob.com)
或者还可以自定义, 实际上Consumer以及其他API的底层也是使用的这种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @FunctionalInterface interface Func { int call(int i, int j); } public class Test { void lambda(Func func) { int res = func.call(1, 2); System.out.println(res); }
public static void main(String[] args) { Test test = new Test(); test.lambda(Integer::sum); test.lambda((a, b) -> a * b); test.lambda(test::doubleSum); }
int doubleSum(int i, int j) { return 2 * (i + j); } }
|
应用
1 2 3 4
| @FunctionalInterface public interface SortMethod { void call(int[] arr); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class Test { public static void printMethodRunTime(SortMethod sortMethod, int[] arr) { long start = System.currentTimeMillis(); sortMethod.call(arr); long runTime = System.currentTimeMillis() - start; System.out.println("总耗时" + runTime + "毫秒"); }
public static int[] generateRandomArray(int length, int min, int max) { if (max - min < 1 || length < 1) { throw new IllegalArgumentException("参数异常"); } int[] array = new int[length]; double random; for (int i = 0; i < length; i++) { random = Math.random() * (max + 1 - min) + min; array[i] = (int) random; } return array; }
public static void main(String[] args) { SortMethods sortMethods = new SortMethodsImpl(); printMethodRunTime(sortMethods::bubbleSort, generateRandomArray(10000, -100, 100)); printMethodRunTime(sortMethods::insertSort, generateRandomArray(10000, -100, 100)); printMethodRunTime(sortMethods::selectSort, generateRandomArray(10000, -100, 100)); printMethodRunTime(sortMethods::quickSort, generateRandomArray(10000, -100, 100));
} }
|
注: 排序方法接口SortMethods及其实现类SortMethodsImpl代码见: https://gist.github.com/tiam-bloom/ea2bc5112dfa67506a960a76bdf3c367
Lambda、方法引用、函数式编程都是java8的新特性, 还有stream流等等
更多请查看: JDK 8 中的新增功能 (oracle.com)
常见的使用, 比如遍历集合
1 2
| List<String> list = new ArrayList<>(); list.forEach(System.out::println);
|
函数编程的应用呢?
比如: 可以编写一个通用的排序方法的测试方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
public void testSortMethod(int testTimes, Consumer<int[]> sortMethod) { for (int i = 0; i < testTimes; i++) { int[] arr = generateRandomArray(10); sortMethod.accept(arr); if (!isRightSort(arr)) { System.out.println("第" + (i + 1) + "次排序出问题啦!!!"); System.out.println("sortMethod 排序结果: " + Arrays.toString(arr)); return; } } System.out.println("通过" + testTimes + "次测试, 哎哟不错哦"); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
public int[] generateRandomArray(int length, int min, int max) { if (max - min < 1 || length < 1) { throw new IllegalArgumentException("参数异常"); } int[] array = new int[length]; double random; for (int i = 0; i < length; i++) { random = Math.random() * (max + 1 - min) + min; array[i] = (int) random; } return array; }
public int[] generateRandomArray(int length) { return this.generateRandomArray(length, -100, 100); }
|
1 2 3 4 5 6 7 8 9 10 11
|
public boolean isRightSort(int[] arr) { int[] arrCopy = Arrays.copyOf(arr, arr.length); Arrays.sort(arrCopy); return Arrays.equals(arrCopy, arr); }
|