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";
    }
}

Java8新特性
在使用前,会进行判空处理。

	@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新特性
所以Java8中更推荐使用这种方式处理空指针。