面試準備:Java新特性詳解


更多資料,參考java8 新特性精心整理(全)

Java語言新特性

1.Lambda表達式和函數式接口

比如:

@FunctionalInterface
public interface Comparator<T> {
...
}
# main
Integer[] arr=new Integer[4];
Arrays.sort(arr,(o1,o2)->o2-o1);//Comparator

又比如:

# main
Arrays.asList(1,2,3,4).forEach(System.out::println);//Consumer

不做贅述,參考探索Java8——Lambda表達式

2.接口的默認方法和靜態方法

這個之前也介紹過了,也就是jdk8之後接口能夠使用default和static方法:

interface Defaulable{
    default String defaultMethod() {
        return "Default implementation";
    }
}
interface DefaulableFactory{
    static Defaulable staticMethod(Supplier<Defaulable> supplier){
        return supplier.get();
    }
}
class Main implements Defaulable{

    public static void main(String[] args) {
        Defaulable defaulable =DefaulableFactory.staticMethod(Main::new);
        System.out.println(defaulable.defaultMethod());
    }
}

當然也可以Override重寫:

class Main implements Defaulable{
    @Override
    public String defaultMethod() {
        return null;
    }
    ...
}

3.方法引用

java8方法引用有四種形式:

  • 構造器引用        :   Class :: new
  • 靜態方法引用       :   Class :: staticMethodName
  • 類的任意對象的實例方法引用:   Class :: instanceMethodName
  • 特定對象的實例方法引用  :   object :: instanceMethodName

第一種方法引用的類型是構造器引用,語法是Class::new,或者更一般的形式:Class<T>::new。注意:這個構造器沒有參數。

class Main {
    public static Main mainFactory(Supplier<Main> supplier){
        return supplier.get();
    }

    public static void main(String[] args) {
        Supplier<Main> supplier=Main::new;
        //等價於  Supplier<Main> supplier=()->new Main();
        Main m=Main.mainFactory(supplier);
    }
}

第二種方法引用的類型是靜態或者普通方法引用,語法是Class::staticMethodName

public class Test {
    public static void main(String[] args) {
        //lambda表達式使用:
        Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(s -> Test.println(s));
        //靜態方法引用:
        Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(Test::println);
    }

    public static void println(String s) {
        System.out.println(s);
    }
}

第三種方法引用的類型是某個類的成員方法的引用,語法是Class::instanceMethodName

# main
Arrays.sort(strs, String::compareToIgnoreCase);//Comparator
 
  @FunctionalInterface
  public interface Comparator<T> {
  	  //compare是兩個參數,也就是比實際調用的compareToIgnoreCase()多出一個參數。
  	  //第一個參數T o1傳的是對象,作用另一個例子會講到。
      int compare(T o1, T o2);
  }
 
# 而String的compareToIgnoreCase()函數如下:
public int compareToIgnoreCase(String str) {
	//這裏實際上使用的是第二個參數T o2
	return CASE_INSENSITIVE_ORDER.compare(this, str);
}

換個例子能更好的理解:

public class Student
{
    
    private String name;
    
    private Integer score;
    
    public void setNameAndScore(String name, Integer score)
    {
        this.name = name;
        this.score = score;
        System.out.println("Student "+  name +"'s score is " + score);
    }
     
    public static void main(String[] args)
    {
        /*lambda表達式的用法:
        TestInterface testInterface = (student, name, score) -> student.setNameAndScore(name, score);*/
        //類的任意對象的實例方法引用的用法:
        TestInterface testInterface = Student::setNameAndScore;
        testInterface.set(new Student(), "DoubleBin", 100);
    }
    
    @FunctionalInterface
    interface TestInterface
    {
        // 注意:入參比Student類的setNameAndScore方法多1個Student對象,除第一個外其它入參類型一致
        public void set(Student d, String name, Integer score);
    }
}

第四種方法引用的類型是某個實例對象的成員方法的引用,語法是object :: instanceMethodName

public class Test
{
    public static void main(String[] args)
    {
        Test test = new Test();
        // lambda表達式使用:
        Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(s -> test.println(s));
        // 特定對象的實例方法引用:
        Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(test::println);
    }
    
    public void println(String s)
    {
        System.out.println(s);
    }
}

第四種方法其實和第三種差不多,只不多第三個多出了一個參數用來傳入了object罷了。

4.重複註解

public class RepeatingAnnotations {
    @Target( ElementType.TYPE )
    @Retention( RetentionPolicy.RUNTIME )
    public @interface Filters {
        Filter[] value();
    }

    @Target( ElementType.TYPE )
    @Retention( RetentionPolicy.RUNTIME )
    @Repeatable( Filters.class )
    public @interface Filter {
        String value();
    };

    @Filter( "filter1" )
    @Filter( "filter2" )
    public interface Filterable {
    }

    public static void main(String[] args) {
        for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
            System.out.println( filter.value() );
        }
    }
}
  • @Repeatable( Filters.class )爲什麼要有後面一段Filters.class
    Filters是保存Filter註解的容器。(可以理解爲數組存放了元素)

5.更好的類型推斷

Java 8編譯器在類型推斷方面有很大的提升,在很多場景下編譯器可以推導出某個參數的數據類型,從而使得代碼更爲簡潔。例子代碼如下:

public class Value< T > {
    public static<T> T defaultValue() {
        return null;
    }

    public T getOrDefault( T value, T defaultValue ) {
        return ( value != null ) ? value : defaultValue;
    }

    public static void main(String[] args) {
        final Value< String > value = new Value<>();
        String s=value.getOrDefault( "22", Value.defaultValue() );
        String s2=value.getOrDefault(null,Value.defaultValue());
    }
}

參數Value.defaultValue()的類型由編譯器推導得出,不需要顯式指明。在Java 7中這段代碼會有編譯錯誤,除非使用Value.<String>defaultValue()

6.拓寬註解的應用場景

之前文章介紹過@Target註解,在JAVA8中,@Target多了這兩個類型:

/**
     * Type parameter declaration
     *
     * @since 1.8
     */
     /** 用來標註類型參數 */
    TYPE_PARAMETER,
 
    /**
     * Use of a type
     *
     * @since 1.8
     */
     /** 能標註任何類型名稱 */
    TYPE_USE
}
public class TestTypeUse {
 
    @Target(ElementType.TYPE_USE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TypeUseAnnotation {
         
    }
     
    public static @TypeUseAnnotation class TypeUseClass<@TypeUseAnnotation T> extends @TypeUseAnnotation Object {
        public void foo(@TypeUseAnnotation T t) throws @TypeUseAnnotation Exception {
             
        }
    }
     
    // 如下註解的使用都是合法的
    @SuppressWarnings({ "rawtypes", "unused", "resource" })
    public static void main(String[] args) throws Exception {
        TypeUseClass<@TypeUseAnnotation String> typeUseClass = new @TypeUseAnnotation TypeUseClass<>();
        typeUseClass.foo("");
        List<@TypeUseAnnotation Comparable> list1 = new ArrayList<>();
        List<? extends Comparable> list2 = new ArrayList<@TypeUseAnnotation Comparable>();
        @TypeUseAnnotation String text = (@TypeUseAnnotation String)new Object();
        java.util. @TypeUseAnnotation Scanner console = new java.util.@TypeUseAnnotation Scanner(System.in);
    }
}

Java編譯器新特性

參數名稱

爲了在運行時獲得Java程序中方法的參數名稱,老一輩的Java程序員必須使用不同方法,例如Paranamer liberary。Java 8終於將這個特性規範化,在語言層面(使用反射API和Parameter.getName()方法)和字節碼層面(使用新的javac編譯器以及-parameters參數)提供支持。

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
 
public class ParameterNames {
    public static void main(String[] args) throws Exception {
        Method method = ParameterNames.class.getMethod( "main", String[].class );
        for( final Parameter parameter: method.getParameters() ) {
            System.out.println( "Parameter: " + parameter.getName() );
        }
    }
}

JVM的新特性

使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM參數方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原來的-XX:PermSize和-XX:MaxPermSize。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章