title: JDK1.8特性
date: 2022-06-03 22:26:52
categories:
- JAVA
- 基础
一、接口的默认方法
Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,
代码如下:
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。
代码如下:
Formula formula = new Formula() {
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
formula.calculate(100); // 100.0
formula.sqrt(16); // 4.0
文中的formula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算 sqrt(a * 100)。在下一节中,我们将会看到实现单方法接口的更简单的做法。
理解:默认方法可以实现接口不需要些改动的方法,同时子类还可以重写,没有限制。
JDK9出来的私有方法的使用可以在默认方法中进行,避免代码冗余,降低耦合。
同时默认方法可以是静态的,调用私有静态方法
二、Lambda 表达式
首先看看在老版本的Java中是如何排列字符串的:代码如下:
List<String> names = Arrays.asList("peterF", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b)
{
return b.compareTo(a);
}
});
只需要给静态方法 Collections.sort 传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。
在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:
代码如下:
Collections.sort(names, (String a, String b) -> { return b.compareTo(a); });
看到了吧,代码变得更段且更具有可读性,但是实际上还可以写得更短:
代码如下:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字,但是你还可以写得更短点:
代码如下:
Collections.sort(names, (a, b) -> b.compareTo(a));
Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。接下来我们看看lambda表达式还能作出什么更方便的东西来:
- Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。
- 面向对象的思想: 做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情. 函数式编程思想: 只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程。
- 这是一种比匿名内部类更为简单的一种写法,只允许拥有一种抽象方法,或者只剩一种抽象方法没有实现(Compartor接口里面有两种抽象方法,compareTo 和 equals 方法)但是Object类都有equals方法默认实现了该抽象方法。
使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
- 写法理解:
(参数类型 参数名称) ‐> { 代码语句 }
Lambda表达式的标准格式为:格式说明:
- 小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
- ->是新引入的语法格式,代表指向动作。
eg1:
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
eg2:简单实现四大法则:
private static void lambda表达式(){
sf_ab(130,120,"+",(Integer a,Integer b,String h)->a+b);
sf_ab(130,120,"-",(Integer a,Integer b,String h)->a-b);
sf_ab(130,120,"*",(Integer a,Integerb,Stringh)->a*b);
sf_ab(130,120,"/",(Integer a,Integer b,String h)->a/b);
}
private static void sf_ab(int a,int b,String h,算法<Integer>t){
Integer sf=t.sf(a,b,h);
System.out.println(a+h+b+"结果:"+sf);
}
}
interface 算法<T>{
Tsf(T a,T b,String h);
}
三、函数式接口
1、函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式。
代码如下:
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123
2、需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。函数式接口可以对现有的函数友好地支持 lambda。
JDK 1.8 之前已有的函数式接口:
- java.lang.Runnable
- java.util.concurrent.Callable
- java.util.Comparator
- java.io.FileFilter
JDK 1.8 的java.util.function 包的接口:
Supplier接口:
抽象方法:
T get() :用来获取一个泛型参数指定类型的对象数据。
由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
Consumer接口:
抽象方法:
void accept (T t):处理一个指定泛型的数据。
默认方法:
Consumer andThen (Consumer after):
如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,首先做一个操作, 然后再做一个操作,实现组合。而这个方法就是 Consumer 接口中的default方法 andThen 。
**实例:**one.andThen(two).accept(info);
源码: