Java 8 新特性
目录
1. 允许在接口中有默认方法实现
Java 8允许我们使用default关键字在接口中添加非抽象的方法实现,这个特性也称为扩展方法。
/**
* Java 8新特性:允许使用default关键字在接口中添加非抽象的方法实现
* 在接口中除了定义抽象方法query外,还定义了一个默认方法printUsername,该类的实现类只需要实现抽象方法query,在实现类中可以直接调用默认方法;
*/
public interface DefaultMainFieldExample {
void query(String id);
default void printUsername(String username) {
System.out.println(username);
}
}
/**
* default默认关键字实现类
* 在实现类中可以直接调用父类定义的默认方法
*/
public class DefaultMainFieldExampleImpl implements DefaultMainFieldExample {
@Override
public void query(String id) {
System.out.println(id);
}
public static void main(String[] args) {
DefaultMainFieldExampleImpl defaultMainFieldExample = new DefaultMainFieldExampleImpl();
defaultMainFieldExample.query("001");
// 直接调用父类定义的默认方法
defaultMainFieldExample.printUsername("default");
// 匿名对象
DefaultMainFieldExample mainFieldExample = new DefaultMainFieldExample() {
@Override
public void query(String id) {
printUsername(id);
}
};
mainFieldExample.query("002");
mainFieldExample.printUsername("default");
}
}
2. Lambda表达式
先从一个简单的例子说起,如何对一个String列表排序;
// JDK 8以前的方式
// Collections.sort接收一个集合以及比较接口Comparator作为输入参数,可以指定一个匿名对象作为参数传递值
List<String> names = Arrays.asList("Java", "Python", "JavaScript");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
在Java 8中提供了一种相较于匿名对象更简洁的方法:Lambda表达式;
// Lambda表达式
// 适用于接口只有且只有一个"抽象"方法,Lambda表达式必须与抽象方法的声明相匹配
// 如果实现代码只有一行,可以省略大括号以及return关键字
// Java编译器会自动识别参数类型,可以省略参数类型
// IDEA推荐不要直接对象比较(针对该例中的字符串比较)
// Collections.sort(names, (String a, String b) -> b.compareTo(a));
Collections.sort(names, (String a, String b) -> {
return b.toLowerCase().compareTo(a.toLowerCase());
});
Collections.sort(names, (String a, String b) -> b.toLowerCase().compareTo(a.toLowerCase()));
Collections.sort(names, (a, b) -> b.toLowerCase().compareTo(a.toLowerCase()));
3. 函数式接口
Lambda表达式是如果精确匹配Java的类型系统的呢?
1.每一个Lambda表达式都通过一个特定的接口,和一个给定的类型匹配;
2.函数式接口:每一个函数式接口都有且只有一个抽象方法声明,每个与之对应的Lambda表达式必须要与抽象方法的声明相匹配;
3.默认方法不是抽象的,可以添加任意的默认方法;
4.任意只包含一个抽象方法的接口,我们都可以用来做成Lambda表达式;
5.@FunctionalInterface注解,约束接口中只能有一个抽象方法,否则抛出编译器错误;
// @FunctionalInterface注解:约束接口中只能有一个抽象方法,否则抛出编译器错误;可省略
@FunctionalInterface
public interface LambdaInterface<F, T> {
T convert(F from);
default void printTip(String username) {
System.out.println(username);
}
}
// 函数式接口
// Lambda如果匹配Java的类型系统?
// 每一个函数式接口都必须包含一个精确的抽象方法声明,接口的每个Lambda表达式都必须与该方法的声明相匹配
// 默认方法不是抽象的,可以添加任意的默认方法
// 只要满足函数式接口的定义:有且仅有一个抽象方法,就可以对任意接口作为Lambda表达式
// @FunctionalInterface注解,约束接口中只能有一个抽象方法,否则抛出编译器错误
LambdaInterface<String, Integer> lambdaInterface = (from) -> Integer.valueOf(from);
lambdaInterface.printTip("Lambda");
Integer integer = lambdaInterface.convert("003");
System.out.println(integer);
4. 方法和构造函数引用
Java 8允许通过关键字"::"获取方法或者构造函数的引用;
// 方法和构造函数引用
// Java 8允许通过"::"关键字获取方法和构造函数的引用
// 说明:使用"::”关键字时,只适用于仅一个参数的方法,构造函数除外;
// 静态方法引用
LambdaInterface<String, Integer> integerLambdaInterface = Integer::valueOf;
System.out.println(integerLambdaInterface.convert("004"));
// 对一个对象的方法引用
SomeThing someThing = new SomeThing();
LambdaInterface<String, String> stringLambdaInterface = someThing::startWith;
System.out.println(stringLambdaInterface.convert("Lambda"));
// 静态方法引用
LambdaInterface<String, String> endWithLambdaInterface = SomeThing::endWith;
endWithLambdaInterface.convert("Lambda");
// 对构造函数的引用
PersonFactory<Person> personFactory = Person::new;
personFactory.create("Jack", "Rose");
class SomeThing {
public String startWith(String startWith) {
return String.valueOf(startWith.charAt(0));
}
public static String endWith(String endWith) {
return String.valueOf(endWith.charAt(0));
}
public static String subString_0(String subString, int start, int end) {
return subString.substring(start, end);
}
public static String subString_1(String subString) {
return subString.substring(0, 1);
}
public static String subString_2(String subString, int start) {
return subString.substring(start);
}
}
class Person {
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
interface PersonFactory<P extends Person> {
P create(String firstName, String lastName);
}
5. Lambda的范围
5.1 访问局部变量
Lambda表达式可以访问外部的的final局部变量;
// 访问外部final局部变量
final int finaNum = 1;
LambdaInterface<Integer, String> lambdaInterfaceFinal = (from -> String.valueOf(finaNum + from));
System.out.println(lambdaInterfaceFinal.convert(2));
// 和匿名对象不一样的地方在于:局部变量不一定要是final
int finalNum = 2;
LambdaInterface<Integer, String> lambdaInterface = (from -> String.valueOf(finalNum + from));
System.out.println(lambdaInterface.convert(3));
// 虽然Lambda访问的外部变量不一定需要定义为final,然鹅在编译的时候变量会被隐式的当做final变量处理
// 从Lambda表达式引用的本地变量必须是最终变量或实际上的最终变量
int finalNoChange = 3;
LambdaInterface<Integer, String> lambdaInterfaceNoChange = (from -> String.valueOf(finalNoChange + from));
System.out.println(lambdaInterfaceNoChange.convert(4));
// finalNoChange = 4;
5.2 访问成员变量和静态变量
在Lambda表达式的内部可以获取对成员变量或者静态变量读写权限;
public void lambdaGetClassVariable() {
// 访问成员变量和静态变量
// 访问静态变量
LambdaInterface<Integer, String> lambdaInterface1ClassStaticVariable = (from -> String.valueOf(staticNum
+ from));
System.out.println(lambdaInterface1ClassStaticVariable.convert(7));
// 访问成员变量
LambdaInterface<Integer, String> lambdaInterface1ClassNonStaticVariable = (from -> String.valueOf(nonStaticNum
+ from));
System.out.println(lambdaInterface1ClassNonStaticVariable.convert(8));
}
5.3 访问默认接口方法
默认方法在Lambda表达式中无法访问;
6. 内置函数式接口
JDK 8 API中的函数式接口
6.1 Predicate
Predicate是一个布尔类型的函数,该函数只有一个输入参数。Predicate接口包含了多种默认方法;
public static void main(String args[]) {
// Predicate是一个布尔类型的函数,该函数只有一个输入参数。Predicate接口包含了多种默认方法,
// 用于处理复杂的逻辑动词(and, or,negate)
// 函数式接口方法 - test
Predicate<String> predicate = s -> s.length() > 0;
System.out.println(predicate.test("Lambda"));
// 默认方法 - and
Predicate<String> predicate1And = s -> s.indexOf("mb") > 0;
System.out.println(predicate1And.test("lambda"));
// 连用
System.out.println(predicate.and(predicate1And).test("JDK-8-Lambda"));
// 理解:该默认方法的return其实也是一个Lambda表达式,返回一个布尔类型的参数给Predicate对象接收
// default Predicate<T> and(Predicate<? super T> other) {
// Objects.requireNonNull(other);
// 这里的返回其实也是一个Lambda表达式,返回一个布尔类型的参数(or方法也类似)
// return (t) -> test(t) && other.test(t);
// }
// 默认方法 - negate
Predicate<String> predicate1Negate = s -> s.length() > 0;
System.out.println(predicate1Negate.negate().test("Predicate.negate"));
// 默认方法 - or
Predicate<String> predicate1Or = s -> s.length() > 0;
System.out.println(predicate1Or.or(predicate1Negate).test("or"));
// 静态方法 - isEqual
Predicate<String> predicate1IsEqual = Predicate.isEqual("Lambda");
predicate1IsEqual.test("Lambda");
// Predicate - 静态方法实现
Predicate<Boolean> nonNull = Objects::nonNull;
System.out.println(nonNull.test(true));
Predicate<Boolean> isNull = Objects::isNull;
System.out.println(isNull.test(false));
Predicate<String> isEmpty = String::isEmpty;
System.out.println(isEmpty.test(" "));
Predicate<String> isNotEmpty = isEmpty.negate();
System.out.println(isNotEmpty.test("Lambda"));
}
Predicate源码查看:
6.2 Functions
Function接口接收一个参数,并返回单一的结果,默认方法可以将多个函数串联在一起;
public static void main(String args[]) {
// Function接口接收一个参数,并返回单一的结果
Function<String, String> stringFunction = s -> s.substring(1);
System.out.println(stringFunction.apply("stringFunction"));
Function<String, Integer> integerFunction = s -> s.length();
System.out.println(integerFunction.apply("integerFunction"));
// andThen
Function<String, Integer> andThenFunction = Integer::valueOf;
Function<String, String> applyFunctionAndThen = andThenFunction.andThen(String::valueOf);
System.out.println(applyFunctionAndThen.apply("20200323"));
// compose
Function<Integer, String> composeFunction = String::valueOf;
Function<String, String> applyFunctionCompose = composeFunction.compose(Integer::valueOf);
System.out.println(applyFunctionCompose.apply("20200323"));
}
Function源码查看:
6.3 Supplier
Supplier接口产生一个给定类型的结果,Supplier没有输入参数;
public static void main(String args[]) {
// Supplier接口产生一个给定类型的结果,Supplier没有输入参数
Supplier<String> supplier = String::new;
System.out.println(supplier.get());
}
6.4 Consumer
Consumer代表在一个输入参数上需要进行的操作;
public static void main(String args[]) {
// Consumer代表在一个输入参数上需要进行的操作
Consumer<String> consumer = s -> {
s = s.substring(1);
System.out.println(s);
};
consumer.accept("consumer");
}
/**
* 源码 - Consumer
*/
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* andThen
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
6.5 Comparator
Comparator接口接收两个参数,实现参数的比较,返回一个int类型的结果值;
public class DefaultFunctionInterfaceComparator {
public static void main(String[] args) {
// Person在之前已定义
Comparator<Person> personComparator = (p_jack, p_rose) -> p_jack.getFirstName()
.compareTo(p_rose.firstName);
Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");
personComparator.compare(p1, p2); // > 0
personComparator.reversed().compare(p1, p2); // < 0
}
}
这节到此为止,欲知后事如何,请见下回分解哈!