Java8新特性
1.方法重载
Java中可以进行方法重载,造成多个方法有相同的的方法名,但是签名却不同。这在推断参数类型时会带来问题,因为系统可能会推断出多种类型,这时,javac会选择最最具体的类型。
private void overLoadMethod(String string){
System.out.println("String");
}
private void overLoadMethod(Integer integer){
System.out.println("Integer");
}
private void overLoadMethod(Object object){
System.out.println("Object");
}
@Test
public void testOverLoad(){
overLoadMethod("ss");
overLoadMethod(2);
overLoadMethod(new Object());
}
String
Integer
Object
private void overLoadMethod(BinaryOperator<Integer> binaryOperator){
System.out.println("BinaryOperator:Integer");
}
private void overLoadMethod(IntegerBiFuction integerBiFuction){
System.out.println("IntegerBiFuction");
}
@Test
public void testOverLoad2(){
overLoadMethod((x,y) -> x + y);
}
其中
package intf;
import java.util.function.BinaryOperator;
public interface IntegerBiFuction extends BinaryOperator<Integer>{
}
结果
IntegerBiFuction
private void overLoadMethod(Predicate<Integer> predicate){
System.out.println("predicate:Integer");
}
private void overLoadMethod(IntPredicate intPredicate){
System.out.println("intPredicate");
}
@Test
public void testOverLoad1(){
overLoadMethod((x) -> true);
}
Description Resource Path Location Type
The method overLoadMethod(Predicate<Integer>) is ambiguous for the type Other Other.java /study_java8Lambda/src/client line 160 Java Problem
[email protected]
该注解会强制javac检查一个接口是否符合函数接口的标准。如果该注释添加给一个枚举类型、类、或者另一个注解,或者接口包含不止一个抽象方法,javac就会报错。
3.Java的二进制接口的兼容性
二进制兼容性一直被视为Java的关键优势,除非引入新的关键字,否则其源代码依然可以向后兼容。但是二进制兼容只是保证jdk1~jdk7环境下的源代码无需任何更改在jdk8中依然可以编译通过,但是可能会发生异常。
比如在jdk8中修改了集合类的核心类库,在Collection中增加了stream方法,那么,所有的实现了Collection接口的类都必须实现这个方法。但是这样就打破了二进制兼容性,以及开闭原则等等。
为了保持这种情况的发生,jdk8的另一个新特性:默认方法完美解决这种情况。
4.默认方法
默认方法的定义关键词就是default
在接口中用default修饰的方法就是默认方法。
默认方法的传播规则:
1.继承传播
2.实现传播
3.子类覆盖
举个例子:
A接口中有一个a默认方法;
B接口继承A接口,那么B接口默认拥有这个a方法;
如果B接口也有一个a方法,那么B接口就会使用B接口自己实现的a方法,其实现类及后代接口使用的同样是B接口中的a方法;
如果任何实现了A接口,A接口的子接口,B接口,B接口的子接口,上述实现类及子类中重写了a方法,以子类重写的为主。
为什么需要默认方法:
1.默认方法需要在Java8中保证二进制兼容性;
2.接口没有成员变量,默认方法只能通过调用子类的方法修改子类本身,避免对子类的实现做各种处理。
默认方法称为了虚方法:
任何时候,一旦与类中定义的方法产生冲突,都需要优先选择类中定义的方法。
默认方法传播规则的原因:
为了接口做向上兼容。
比如jdk8在Collection中新增了方法,只需要增加默认方法即可,无需对Collection的实现类及子接口做任何处理。当实现或者子接口需要重写时,不会因默认方法产生任何影响。
5.多重继承
因为实现接口不受个数的限制,所以,如果多个接口中拥有同样的默认方法,会形成多重继承的情况。
此时,因为javac不确定调用哪一个方法,所以需要开发人员手动的确定应该调用哪一个方法。
package intf;
public interface Intf1 {
public default void message(){
System.out.println("message#Intf1");
}
}
package intf;
public interface Intf2 {
public default void message(){
System.out.println("message#Intf2");
}
}
package intf;
public class ClassIntf implements Intf1,Intf2 {
}
Description Resource Path Location Type
Duplicate default methods named message with the parameters () and () are inherited from the types Intf2 and Intf1 ClassIntf.java /study_java8Lambda/src/intf line 3 Java Problem
解决方法:
package intf;
public class ClassIntf implements Intf1,Intf2 {
@Override
public void message(){
Intf1.super.message();
}
}
在实现类中使用增强的super语法,指定需要调用的方法。
@Test
public void test1(){
ClassIntf classIntf = new ClassIntf();
classIntf.message();
}
message#Intf1
之前super指向的是父类,现在InterfaceName.super指向的是继承自父接口的方法。
6.多重继承于抽象类
接口允许多重继承,但是却没有成员变量;抽象类可以继承成员变量,但是却不能多重继承。
7.接口的静态方法
静态方法又称类方法,通常用于封装工具方法等等。
所以,接口的静态方法也是同样的目的,使静态方法与使用更加紧密,距离更加进。
public static<T> Stream<T> of(T t) {
return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}
比如上述方法更多的是被当做工具类的工具方法使用。。。
8.避免空指针异常
写Java程序,遇到的最多的大概就是空指针异常了,因为使用null表示空,但是却又无法安全的处理空指针异常(大多都是调用前没有进行空指针判断,直接使用)。
基于此,jdk新增加了一个对象类型,在使用前会调用判空处理。
Optional
package java.util;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
public boolean isPresent() {
return value != null;
}
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
public T orElse(T other) {
return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
}
在使用前,会进行判空处理。
@Test
public void testOptional(){
Optional<String> sOptional = Optional.of("a");
assertEquals("a",sOptional);
Optional nullOptional = Optional.empty();
Optional alsoEmptyOptional = Optional.ofNullable(null);
assertEquals(nullOptional, alsoEmptyOptional);
assertTrue(sOptional.isPresent());
assertEquals("b", nullOptional.orElse("b"));
assertEquals("c", alsoEmptyOptional.orElseGet(() -> "c"));
}
所以Java8中更推荐使用这种方式处理空指针。