JAVA8 新特性學習筆記

ajzx3880 7年前發布 | 17K 次閱讀 Java8 Java開發

語法的新特性:

一、 接口 默認方法和靜態方法 ,給接口賦予了類的能力,增強了java的靈活性。

接口中可加入default默認方法或static靜態方法。

可有多個但必須實現其方法體。Java接口中定義了默認方法,實現類不用每個方法都實現一遍了。而且不需要修改繼承接口的實現類,就給接口添加了新的方法實現。其給接口賦予了抽象類的能力,增強了java的靈活性。

二、 方法引用

ClassName::methodName (靜態方法 + 實例方法 都可使用)

super::methodName (超類上的實例方法使用)

Class::new (創建新實例時可使用)

TypeName[]::new

三、 Lambda表達式(也叫做閉包)

Collections.sort(names, (String a, String b) -> {
         return b.compareTo(a);
     });

Collections.sort(names, (String a, String b) -> b.compareTo(a));

Collections.sort(names, (a, b) -> b.compareTo(a));</code></pre> 

Lambda 作用域 ?

在lambda表達式中可以訪問外層局部變量,但不能修改外層局部變量。(閉包的作用域)

和本地變量不同的是,lambda內部對于實例的字段或類的靜態變量是即可讀又可寫。

四、 函數式接口

函數式接口 有且僅有一個抽象方法 ,每一個lambda匹配這個抽象方法。因為static與defualt默認方法不是抽象的,所以可以在函數式接口中自由的添加。

函數式接口應該用@FunctionalInterface來注解接口,但可省略。

函數式接口的作用是使lambda表達式融入java的類型系統。每一個lambda相當于一種指定類型的函數式接口的實現。

@FunctionalInterface
   public interface MyFuncitonalInterface {
       void fun();
   }

   MyFuncitonalInterface mf = () -> System.out.println(666);
           mf.fun();

常用javaAPI標準函數接口:

  1. Predicate 斷言,一般用來判斷是否滿足某條件

  2. Consumer 接收一個參數,無返回值

  3. Function 接收T對象,返回R對象

  4. Supplier 類似工廠,調用時會返回一個指定類型的對象

  5. UnaryOperator 執行一元操作(與、或、非)

  6. BinaryOperator 接收兩個參數,返回一個值

一些函數式接口的典型用例:

public class Lambda {

       @FunctionalInterface
       interface Fun {
           void foo();
       }

       public static void main(String[] args) throws Exception {

           // Predicates

           Predicate<String> predicate = (s) -> s.length() > 0;

           predicate.test("foo");              // true
           predicate.negate().test("foo");     // false

           Predicate<Boolean> nonNull = Objects::nonNull;
           Predicate<Boolean> isNull = Objects::isNull;

           Predicate<String> isEmpty = String::isEmpty;
           Predicate<String> isNotEmpty = isEmpty.negate();

           // Functions

           Function<String, Integer> toInteger = Integer::valueOf;
           Function<String, String> backToString = toInteger.andThen(String::valueOf);//在toInteger加入apply結束后執行的方法,生成新的Function

           backToString.apply("123");     // "123"

           // Suppliers

           Supplier<Person> personSupplier = Person::new;
           personSupplier.get();   // new Person

           // Consumers

           Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
           greeter.accept(new Person("Luke", "Skywalker"));

           // Comparators

           Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);

           Person p1 = new Person("John", "Doe");
           Person p2 = new Person("Alice", "Wonderland");

           comparator.compare(p1, p2);             // > 0
           comparator.reversed().compare(p1, p2);  // < 0

           // Runnables

           Runnable runnable = () -> System.out.println(UUID.randomUUID());
           runnable.run();

           // Callables

           Callable<UUID> callable = UUID::randomUUID;
           callable.call();
       }

   }

小結:

以上新增的語言特性使Java 能夠實現一部分“函數式”的編程范式,可以用簡單的函數式風格(例如filter和map)簡化笨重的代碼。但Java需要用類型來表示它們。如java.util.function中的Predicate、Function和Consumer接口。

java庫的新特性

五、 Stream 流操作

java.util.Stream 表示能應用在一組元素上一次執行的操作序列。

Stream 操作分為中間操作或者最終操作兩種,最終操作返回一特定類型的計算結果,而中間操作返回Stream本身,這樣你就可以將多個操作依次串起來。

Stream 的創建需要指定一個數據源,比如 java.util.Collection的子類,List或者Set, Map不支持。通過 Collection.stream() 或者 Collection.parallelStream() 來創建一個Stream。

Stream的操作可以串行執行或者并行(parallelStream)執行。

常用操作:

forEach 遍歷

stringCollection  
    .stream()
    .forEach(System.out::println);

Filter 過濾

過濾通過一個predicate接口來過濾并只保留符合條件的元素,該操作屬于中間操作,所以我們可以在過濾后的結果來應用其他Stream操作(比如forEach)。forEach需要一個函數來對過濾后的元素依次執行。forEach是一個最終操作,所以我們不能在forEach之后來執行其他Stream操作。

stringCollection  
    .stream()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);

Sort 排序

排序是一個中間操作,返回的是排序好后的Stream。如果你不指定一個自定義的Comparator則會使用默認排序。需要注意的是,排序只創建了一個排列好后的Stream,而不會影響原有的數據源,排序之后原數據stringCollection是不會被修改的:

stringCollection  
    .stream()
    .sorted()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);

Map 映射

中間操作map會將元素根據指定的Function接口來依次將元素轉成另外的對象,下面的示例展示了將字符串轉換為大寫字符串。你也可以通過map來講對象轉換成其他類型,map返回的Stream類型是根據你map傳遞進去的函數的返回值決定的。

stringCollection  
    .stream()
    .map(String::toUpperCase)
    .sorted((a, b) -> b.compareTo(a))
    .forEach(System.out::println);

Match 匹配

Stream提供了多種匹配操作,允許檢測指定的Predicate是否匹配整個Stream。所有的匹配操作都是最終操作,并返回一個boolean類型的值。

boolean anyStartsWithA =  
    stringCollection
        .stream()
        .anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA);      // true  
boolean allStartsWithA =  
    stringCollection
        .stream()
        .allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA);      // false  
boolean noneStartsWithZ =  
    stringCollection
        .stream()
        .noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ);      // true

Count 計數

計數是一個最終操作,返回Stream中元素的個數,返回值類型是long。

long startsWithB =  
    stringCollection
        .stream()
        .filter((s) -> s.startsWith("b"))
        .count();

Reduce

這是一個最終操作,允許通過指定的函數來講stream中的多個元素規約為一個元素,規約后的結果是通過Optional接口表示的:

Optional<String> reduced =  
    stringCollection
        .stream()
        .sorted()
        .reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);

collect獲取集合

//獲取年齡大于12的用戶列表 
        List<User> list = users.parallelStream().filter(p -> p.age > 12) 
                .collect(Collectors.toList()); 
        System.out.println(list);

六、 Optional 處理空指針問題

Optional內部封裝了要處理的值value,對外提供了一下方法:

//============創建方法=====================================//
<T> Optional<T> empty() ;//返回空對象

<T> Optional<T> of(T value);//返回封裝value的Optional對象,內部用Objects.requireNonNull,判斷value為null的情況拋出NullPointerException

<T> Optional<T> ofNullable(T value);//返回一個封裝value的Optional對象,value為null的情況返回空的Optional對象

//============使用方法=====================================//
T get();// 返回value,若value為nul拋出NoSuchElementException

boolean isPresent();//判斷value是否存在

void ifPresent(Consumer<? super T> consumer) ;//若value非null,執行consumer.accept(value)方法

Optional<T> filter(Predicate<? super T> predicate);//若value存在并且value符合predicate的判定,返回Optional對象,否則返回空Optional對象

<U> Optional<U> map(Function<? super T, ? extends U> mapper);//若value存在執行mapper.apply(value)并返回Optional對象,否則返回空Optional對象。flatMap略(為空拋出NullPointerException)

T orElse(T other);//返回value,若value為null返回other

T orElseGet(Supplier<? extends T> other);//返回value,若value為null返回other.get()的返回值

<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X ;//返回value,若value為null拋出exceptionSupplier.get()的返回值
//典型用例:
//獲取字符串s,若為null返回""
String str = Optional.fromNullable(s).orElse("");  
//獲取車輛對象,若為null則new一個
Car car = Optional.fromNullable(car).orElse(Car::new);

其他:

  • Objects工具類, 對Object空指針問題進行了處理。

  • 數組工具類:Arrays.parallelSort 并行排序

  • Map新增方法:

map.forEach((id, val) -&gt; System.out.println(val));

map.getOrDefault(42, &quot;not found&quot;);&nbsp; // 沒有返回默認值

  • HashMap 內部結構變為:數組+鏈表+紅黑樹(解決hashCode沖突使用鏈地址法,將key加入鏈表,當鏈表長度大于8時轉換為紅黑樹,引入紅黑樹利用紅黑樹快速增刪改查的特點大程度優化了HashMap的性能。這個數據結構很屌但很復雜(⊙o⊙)?)

  • 多重Annotation:允許我們把同一個類型的注解使用多次,只需要給該注解標注一下@Repeatable即可。還增加到兩種新的target:@Target({ElementType.TYPE PARAMETER, ElementType.TYPE USE})

  • 全新的時間日期API。

  • JVM的新特性:JVM內存永久區已經被metaspace替換(JEP 122)。JVM參數 -XX:PermSize 和 –XX:MaxPermSize被XX:MetaSpaceSize 和 -XX:MaxMetaspaceSize代替。

 

來自:https://blog.souche.com/java8-xin-te-xing-xue-xi-bi-ji/

 

 本文由用戶 ajzx3880 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!