Java8 相关内容
- Lambda 表达式
- 函数式接口
- 方法引用 / 构造器引用
- Stream API
- 接口中的默认方法 / 静态方法
- 新时间日期 API
- 其他新特性
Java8 特点
- 速度更快
- 代码更少
- 强大的 StreamAPI
- 便于并行
- 最大化减少空指针异常(Optional)
无参数、无返回值的语法格式: () ->
// 无参数、无返回值的示例代码
public class TestLambda {
public static void main(String[] args) {
// 匿名内部类写法
new Runnable(){
@Override
public void run() {
//在局部类中引用同级局部变量
//只读
System.out.println("Hello World");
}
};
// Lambda 表达式写法
Runnable runnable = () -> System.out.println("Hello Lambda");
}
}
有参数、有返回值的语法格式:
(a1, a2, ...) -> {
System.out.println("Hello World");
return a1;
}
// 有参数、有返回值的示例代码:
public class TestLambda {
public static void main(String[] args) {
// 匿名内部类
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
@Override
public boolean equals(Object obj) {
return false;
}
};
// 调用
TreeSet<Integer> set = new TreeSet<>(comparator);
}
}
// Java8 Lambda 表达式写法
public class TestLambda {
public static void main(String[] args) {
// Lambda 表达式
Comparator<Integer> comparator = (o1, o2) -> Integer.compare(o1, o2);
// 调用
TreeSet<Integer> set = new TreeSet<>(comparator);
System.out.println("===================或者==================");
// 如果有多条记录, 需要加上 {}
Comparator<Integer> comparator = (o1, o2) -> {
System.out.println("Hello TestLambda");
return Integer.compare(o1, o2);
};
// 调用
TreeSet<Integer> set = new TreeSet<>(comparator);
}
}
函数式接口在 Java 中值: 有且仅有一个抽象方法的接口。
函数式接口适用于 函数式编程。Java 中的函数式编程体现就是 Lambda, 所以函数式接口就是可以适用于 Lambda 使用的接口。只有确保接口中有且仅有一个抽象方法,Java 中的 Lambda 才能顺利地进行推导。
需要确保接口中有且只有一个抽象方法
@FunctionalInterface
<权限修饰符> interface <接口名> {
<返回值类型> <方法名称>(<入参>);
}
@FunctionalInterface
: 与@Override
注解类型,Java8 中专门为函数式接口引入了这个注解;一旦使用该注解来定义接口,编译器会强制检查该接口是否确实有且仅有一个抽象方法,否则会报错。需要注意的是,即使不适用这个注解,只要满足函数式接口的定义,这个接口就仍然是一个函数式接口。
// ------------ define interface ------------
@FunctionalInterface
public interface MyInterface {
Integer count(Integer a, Integer b);
}
// ------------ main -----------
public class TestMyInterface {
public Integer operate(Integer a, Integer b, MyInterface myInterface) {
return myInterface.count(a, b);
}
public static void main(String[] args) {
MyInterface myInterface = (a, b) -> a + b;
Integer result = operate(2, 99, myInterface);
// 或者将上述两行写为
Integer result2 = operate(2, 99, (a, b) -> a + b);
System.out.println(result);
System.out.println(result2);
}
}
案例一: 使用 Collections.sort() 方法, 先比较工资,再比较年龄,使用 Lambda 表达式做参数传递。
// ------------- define BOJO ------------
class Employee {
private Integer id;
private String name;
private Integer age;
private Double salary;
// 省略 get/set 和 构造器
}
public class TestLambda1 {
public static void main(String[] args) {
List<Employee> emps = Arrays.asList(
new Employee(1, "zhangsan", 39, 99999.0),
new Employee(2, "lisi", 23, 5555.0),
new Employee(3, "wangwu", 43, 3425.0),
new Employee(4, "maliu", 19, 19921.0),
new Employee(5, "tianqi", 26, 21101.0)
);
Collections.sort(emps, (e1, e2) -> {
if (e1.getSalary() == e2.getSalary()) {
return e1.getAge().compareTo(e2.getAge());
} else {
return Double.compare(e1.getSalary(), e2.getSalary());
}
});
for (Employee emp : emps) {
System.out.println(emp);
}
}
}
案例二: 声明函数式接口,接口中声明抽象方法: String getValue(String val)
, 声明类 TestLambda
, 在类中编写方法使用接口作为参数,将第一个字符串转换成大写,并作为方法的返回值。
@FunctionalInterface
public interface MyInterface2 {
String getValue(String val);
}
public class TestLambda {
public static void main(String[] args) {
String operateO = operate("KinO", (x) -> x.toUpperCase());
System.out.println(operateO);
}
public static String operate(String x, MyInterface2 myInterface2) {
return myInterface2.getValue(x);
}
}
案例三: 声明一个带两个泛型的函数式接口,泛型类型为<T, R>
, T 为参数,R 为返回值;接口中声明对应的抽象方法;在 TestLambda 类中声明方法,使用接口作为参数,计算两个 Long 类型参数的合;再计算两个 Long 类型参数的乘积。
@FunctionalInterface
public interface MyInterface1<T, R> {
R operate(T t);
}
public class TestLambda {
public static void main(String[] args) {
Long sum = operate(5L, (x) -> x + x);
System.out.println("sum: "+sum);
Long product = operate(5L, (x) -> x * x);
System.out.println("product: "+product);
}
public static Long operate(Long x, MyInterface1<Long, Long> myInterface1) {
return myInterface1.operate(x);
}
}
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer 消费类型接口 |
T | void | 对类型为 T 的对象应用操作: void accept(T t) |
Supplier 提供型接口 |
无 | T | 返回类型为 T 的对象: T get() |
Function 函数型接口 |
T | R | 对类型为 T 的对象应用操作,并返回结果为 R 类型的对象: R apply(T t) |
Predicate 断言型接口 |
T | boolean | 确定类型为 T 的对象是否满足某约束,并返回 boolean: boolean test(T t) |
public class TestConsumer {
public static void main(String[] args) {
method("hello world", (x) -> {
System.out.println(x.split(" ", 1)[0]);
});
}
public static void method(String name, Consumer<String> consumer) {
consumer.accept(name);
}
}
andThen() 方法
public class TestConsumer {
public static void main(String[] args) {
method("hello world", (x) -> {
System.out.println(x.split(" ", 1)[0]);
}, (y) -> {
System.out.println(y.split(" ", 2)[1]);
});
}
public static void method(String name, Consumer<String> consumer1, Consumer<String> consumer2) {
// consumer1 连接 consumer2, 先执行 consumer1 消费数据, 在执行 consumer1 消费数据
consumer1.andThen(consumer2).accept(name);
}
}
使用 Supplier 接口作为方法参数类型,通过 Lambda 表达式求出 int 数组中的最大值。
public class TestSupplier {
public static void main(String[] args) {
int[] arr = {10,20,1,999,90,-2,200};
int maxValue = getMax(() -> {
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
return max;
});
System.out.println(maxValue);
}
public static Integer getMax(Supplier supplier) {
return supplier.get();
}
}
做判断,返回有个 boolean 结果
public class TestPredicate {
public static void main(String[] args) {
}
}