JAVA8 新特性學習筆記
語法的新特性:
一、 接口 默認方法和靜態方法 ,給接口賦予了類的能力,增強了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標準函數接口:
-
Predicate 斷言,一般用來判斷是否滿足某條件
-
Consumer 接收一個參數,無返回值
-
Function 接收T對象,返回R對象
-
Supplier 類似工廠,調用時會返回一個指定類型的對象
-
UnaryOperator 執行一元操作(與、或、非)
-
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) -> System.out.println(val));
map.getOrDefault(42, "not found"); // 沒有返回默認值
-
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/