一、集合遍历与 Lambda 表达式 引入
package com.java.design.java8;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.*;
import java.util.function.Consumer;
/**
* @author 陈杨
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class ErgodicList {
@Test
public void testErgodicList() {
// 直接构造集合对象 保证了集合 size>0
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
System.out.println(“————————— 传统 for 循环 ——————–\n”);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println(“————————— 增强 for 循环 ——————–\n”);
for (Integer i : list) {
System.out.println(i);
}
System.out.println(“————————— 迭代器 ————————-\n”);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer integer = iterator.next();
System.out.println(integer);
}
System.out.println(“—————————forEach————————\n”);
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
二、@FunctionalInterface 函数式接口与 Lambda 表达式
1、概念
// Consumer @FunctionalInterface 函数式接口
// Conceptually, a functional interface has exactly one abstract method.
// 从概念上看,一个函数式接口有且只有一个精确的抽象方法
// 从 java8 开始 接口中不仅仅存在抽象方法 还能存在有具体实现的方法(默认方法)
2、函数式接口的区分
// Since {@linkplain java.lang.reflect.Method#isDefault()
// default methods} have an implementation, they are not abstract. If
// an interface declares an abstract method overriding one of the
// public methods of {@code java.lang.Object}, that also does
// <em>not</em> count toward the interface’s abstract method count
// since any implementation of the interface will have an
// implementation from {@code java.lang.Object} or elsewhere.
// 因为 java.lang.reflect.Method#isDefault() default methods 有一个实现 所以不是抽象的
// 如果一个接口声明一个抽象方法,其实现了 java.lang.Object 类中 public 方法:不计入抽象方法的个数
3、函数式接口的实例化方式
// Note that instances of functional interfaces can be created with
// lambda expressions, method references, or constructor references.
// 函数式接口的实例化:lambda 表达式 方法引用 构造方法引用
4、函数式接口中的默认方法
// default void forEach(Consumer<? super T> action) {
// Objects.requireNonNull(action);
// for (T t : this) {
// action.accept(t);
// }
// }
// action 针对每个元素 执行的动作行为
// default 修饰接口 已实现的默认方法
5、总结与思考
// 1、如果一个接口中有且只有一个抽象方法 则其为一个函数式接口
// 2、如果一个接口上声明了 @FunctionalInterface 注解 则编译器会按照函数式接口的定义来要求该接口
// If a type is annotated with this annotation type, compilers are
// required to generate an error message unless:
// (1)The type is an interface type and not an annotation type, enum, or class.
// (2)The annotated type satisfies the requirements of a functional interface.
// However, the compiler will treat any interface meeting the
// definition of a functional interface as a functional interface
// regardless of whether or not a {@code FunctionalInterface}
// annotation is present on the interface declaration.
// 3、如果接口上只有一个抽象方法,但我们没有对其加上 @FunctionalInterface 编译器仍然将其看作函数式接口
// 加上注解后 一目了然 如果没有满足强制性要求 则会抛出错误信息
// 4、只有一个抽象方法的接口 有必要加上 @FunctionalInterface 如 Runnable 接口
// 5、所有的函数式接口 都可以使用 lambda 表达式 实现(表达易懂 简单)
三、函数式接口实例化 之 Lambda 表达式
System.out.println(“——————–lambda 创建函数式接口实例 —————\n”);
list.forEach(i -> {
// 若能推断出 i 的类型 不需要声明
// 如不能推断出(Integer i)->{}
System.out.println(i);
});
四、在排序过程中 Lambda 表达式的 演变
System.out.println(“————————–lambda 排序 ———————–\n”);
// Collections.sort(list, new Comparator<Integer>() {
// @Override
// public int compare(Integer o1, Integer o2) {
// return o2.compareTo(o1);
// }
// });
// Collections.sort(list,(String o1, String o2)->{return o2.compareTo(o1);});
// Collections.sort(list, (o1, o2) -> {return o2.compareTo(o1); });
// statement {return o2.compareTo(o1); }
// expression o2.compareTo(o1)
// Collections.sort(list,(String::compareTo));
// Collections.sort(list,Collections.reverseOrder());
Collections.sort(list, (o1, o2) -> o2.compareTo(o1));
System.out.println(list);
五、函数式接口实例化 之 方法引用
System.out.println(“——————– 方法引用创建函数式接口实例 ————–\n”);
list.forEach(System.out::println);
}
}
六、深入理解 Lambda 表达式
// lambda 表达式:
// 1、从函数式编程角度来看:
// lambda 表达式为 Java 添加了函数式编程的新特性 函数升格成为一等公民
// 在函数作为一等公民的语言 如 Python 中 lambda 表达式为函数类型
// 但在 java 中 lambda 表达式是对象类型 依赖于函数式接口 Functional Interface
// 2、lambda 表达式书写
// lambda 表达式形式 () -> {} 必需根据上下文确定其匿名函数类型 函数方法 -> 函数实现
// () 省略 参数只有一个且类型可根据上下文推导
// {} 省略 方法体主体只有一条语句,返回值类型与主体表达式(匿名函数)一致
// 3、进一步理解 lambda 表达式
// lambda 表达式传递行为 action 不仅仅是值的传递(类比 Node.js 的事件驱动 与 回调函数 callback)
// lambda 表达式替换前:事先定义对象及所持有的方法 根据“对象. 方法”进行方法的调用 预先定义好的 action
// lambda 表达式替换后:{} 方法调用 R apply(T t); 事先不知道 action 仅在调用时才知道 action
// 提升抽象层次 API 重用性 使用灵活