JDK13於9月17號正式GA,版本新特性可參考: https://www.oschina.net/news/109934/jdk-13-released
html
雖然JDK更新迅速,但開發者貌似並不買帳,據統計,目前仍以JDK8使用最多,預計可能還會延續好長一段時間。雖然JDK版本已至13,但對Java8的新特性,掌握程度如何呢?
本文對Java8的主要特性進行了梳理。供溫習參考。java
之前的接口只容許有抽象方法(沒有實現體),java8中提供了接口默認方法支持,便可以提供方法的默認實現,實現類能夠直接繼承,也能夠覆蓋。默認方法主要解決接口的修改致使現有實現類不兼容的問題。python
@RunWith(SpringRunner.class) @SpringBootTest public class InterfaceDefaultFunctionTest { public interface MyFunction<T> { T func(T t); //默認方法 default int func2(T t){ return t.hashCode(); } //靜態方法 static<T> void print(T t) { System.out.println(t); } } @Test public void testInterface(){ MyFunction<String> myFunction = new MyFunction<String>(){ @Override public String func(String s) { return s.toUpperCase(); } }; System.out.println(myFunction.func("abc")); System.out.println(myFunction.func2("abc")); LambdaTest.MyFunction.print("efg"); } }
默認方法經過關鍵字 default 聲明。同時也能夠在接口中定義靜態方法。 數組
函數式接口就是有且僅有一個抽象方法的接口(能夠有其它非抽象方法),如1所示代碼中 MyFunction 就是一個函數式接口,只有一個抽象方法 func, 其它非抽象方法如默認方法 func2, 靜態方法 print 不影響其函數式接口的特性。安全
函數式接口可使用註解 @FunctionalInterface 標註,該註解會去檢查接口是否符合函數式接口的規範要求,不符合的話IDE會給出提示。微信
java中內置了一些函數式接口,app
函數式接口 | 描述 |
---|---|
Consumer | 包含方法 void accept(T t), 對類型爲T的對象t進行操做 |
Supplier | 包含方法 T get(),返回類型爲T的對象 |
Function<T,R> | 包含方法 R apply(T t),對類型爲T的對象進行操做,返回類型R的對象 |
Predicat | 包含方法 boolean test(T t), 判斷類型爲T的對象是否知足條件 |
以及基於這些接口的其它變種或子接口,如BiConsumer<T,U>,BiFunction<T,U,R>等。還有如Runnable,Callable等接口,也屬於函數式接口 —— 都只有一個抽象方法。ide
@FunctionalInterface public interface BiConsumer<T, U> { void accept(T t, U u); default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) { Objects.requireNonNull(after); return (l, r) -> { accept(l, r); after.accept(l, r); }; } }
lambda表達式實質就是一個匿名函數,在python中很常見,java到了jdk8提供了支持。函數
lambda表達式的格式形如: (參數) -> {方法體語句},當參數只有一個時,左邊小括號能夠省略,當方法體語句只有一條時,右邊大括號能夠省略。工具
Java的lambda表達式基本上是對函數式接口實現的一種簡化 —— 用lambda表達式直接代替一個函數式接口的具體實現(抽象方法的實現)。當咱們使用jdk8在IDE中編寫1中代碼時,IDE會給出提示,
匿名實現類能夠用lambda表達式替換。上述代碼使用lambda表達式替換可調整爲,
@Test public void testInterface(){ MyFunction<String> myFunction = s -> s.toUpperCase(); System.out.println(myFunction.func("abc")); System.out.println(myFunction.func2("abc")); }
lambda表達式甚至可做爲方法參數傳入(實質也是做爲一個函數式接口的實現類實例)
@FunctionalInterface public interface MyFunction<T> { T func(T t); } public void print(MyFunction<String> function, String s){ System.out.println(function.func(s)); } @Test public void testInterface(){ //將lambda表達式做爲方法參數傳入 print((String s) -> s.toUpperCase(), "abc"); }
局部變量在lambda表達式中是隻讀的,雖可不聲明爲final,但沒法修改。如
@Test public void testInterface(){ int i = 1; //lambda表達式中沒法修改局部變量i,將報編譯錯誤 print((String s) -> {i = i+10; return s.toUpperCase();}, "abc"); }
當須要使用lambda表達式時,若是已經有了相同的實現方法,則可使用方法引用來替代lambda表達式,幾種場景示例以下。
@RunWith(SpringRunner.class) @SpringBootTest public class FunctionReferenceTest { @Test public void testFunctionReference() { // 實例::實例方法 Consumer<String> consumer = s -> System.out.println(s); //lambda表達式 Consumer<String> consumer2 = System.out::println; //方法引用 consumer.accept("abc"); consumer2.accept("abc"); //類::靜態方法 Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y); //lambda表達式 Comparator<Integer> comparator2 = Integer::compare; //方法引用 System.out.println(comparator.compare(10, 8)); System.out.println(comparator2.compare(10, 8)); //類::實例方法, 當引用方法是形如 a.func(b)時,用類::實例方法的形式 BiPredicate<String, String> biPredicate = (a, b) -> a.equals(b); //lambda表達式 BiPredicate<String, String> biPredicate2 = String::equals; //方法引用 System.out.println(biPredicate.test("abc", "abb")); System.out.println(biPredicate2.test("abc","abb")); //type[]::new 數組引用 Function<Integer,Integer[]> fun= n-> new Integer[n]; //lambda表達式 Function<Integer,Integer[]> fun2=Integer[]::new; //方法引用 System.out.println(fun.apply(10)); System.out.println(fun2.apply(10)); //構造器引用 Function<String,String> func = n-> new String(n); //lambda表達式 Function<String,String> func2 = String::new; //方法引用 System.out.println(func.apply("aaa")); System.out.println(func2.apply("aaa")); } }
Stream與lambda應該是java8最重要的兩大特性。Stream 對集合的處理進行了抽象,能夠對集合進行很是複雜的查找、過濾和映射等操做。提供了一種高效的且易於使用的處理數據的方式。
Stream的三個特性:
Java8 的Collection接口包含了兩個方法 stream(), parallelStream(), 分別返回一個順序流與一個並行流,全部Collection類型(如List, )的對象能夠調用這兩個方法生成流。
Java8 的Arrays類也提供了 stream(T[] array)等方法用以生成流。也可使用靜態方法 Stream.iterate() 和 Stream.generate() 來建立無限流。
Stream的中間操做包括
操做 | 描述 |
---|---|
filter(Predicate p) | 接收 Lambda , 從流中過濾出知足條件的元素 |
distinct() | 經過hashCode() 和 equals() 去除重複元素 |
limit(long maxSize) | 截斷流,使元素的個數不超過給定數量 |
skip(long n) | 跳過前面的n個元素,若流中元素不足n個,則返回一個空流 |
map(Function f) | 將每一個元素使用函數f執行,將其映射成一個新的元素 |
mapToDouble(ToDoubleFunction f) | 將每一個元素使用f執行,產生一個新的DoubleStream流 |
mapToInt(ToIntFunction f) | 將每一個元素使用f執行,產生一個新的IntStream流 |
mapToLong(ToLongFunction f) | 將每一個元素使用f執行,產生一個新的LongStream流 |
flatMap(Function f) | 將流中的每一個值都經過f轉換成另外一個流,而後把全部流鏈接成一個流 |
sorted() | 按天然順序排序,產生一個新流 |
sorted(Comparator comp) | 根據比較器排序,產生一個新流 |
allMatch(Predicate p) | 判斷是否匹配全部元素 |
anyMatch(Predicate p) | 判斷是否匹配至少一個元素 |
noneMatch(Predicate p) | 判斷是否沒有匹配任意元素 |
findFirst() | 返回第一個元素 |
findAny() | 返回任意一個元素 |
reduce(T iden, BinaryOperator b) | 對流中的元素進行reduce操做,返回T類型對象 |
reduce(BinaryOperator b) | 對流中的元素進行reduce操做,返回Optional對象 |
Stream的終止操做包括
操做 | 描述 |
---|---|
count() | 返回元素總數 |
max(Comparator c) | 返回最大值 |
min(Comparator c) | 返回最小值 |
forEach(Consumer c) | 內部迭代調用Consumer操做 |
collect(Collector c) | 將流轉換爲其餘形式,通常經過Collectors來實現 |
Stream使用示例
@Test public void testStream() { List<User> list = new ArrayList<>(); //轉換爲List,這裏沒啥意義,僅作示範 List<User> users = list.stream().collect(Collectors.toList()); //轉換爲Set Set<User> users1 = list.stream().collect(Collectors.toSet()); //轉換爲Collection Collection<User> users2 = list.stream().collect(Collectors.toCollection(ArrayList::new)); //計數 long count = list.stream().collect(Collectors.counting()); //求和 int total = list.stream().collect(Collectors.summingInt(User::getAge)); //求平均值 double avg= list.stream().collect(Collectors.averagingInt(User::getAge)); //獲取統計對象,經過該統計對象可獲取最大值,最小值之類的數據 IntSummaryStatistics iss= list.stream().collect(Collectors.summarizingInt(User::getAge)); //將值經過","拼接 String str= list.stream().map(User::getName).collect(Collectors.joining(",")); //最大值 Optional<User> max= list.stream().collect(Collectors.maxBy(Comparator.comparingInt(User::getAge))); //最小值 Optional<User> min = list.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getAge))); //從累加器開始,對指定的值,這裏是年齡,進行sum的reduce操做 int t =list.stream().collect(Collectors.reducing(0, User::getAge, Integer::sum)); //對轉換的結果再進行處理 int how = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size)); //分組 Map<String, List<User>> map= list.stream().collect(Collectors.groupingBy(User::getName)); //根據條件進行分區 Map<Boolean,List<User>> vd= list.stream().collect(Collectors.partitioningBy(u -> u.getName().startsWith("W"))); }
Optional是一個容器類,能夠避免顯式的null判斷,基本使用示例以下
@RunWith(SpringRunner.class) @SpringBootTest public class OptionalTest { @Test public void testOptional(){ // of 不容許傳入null值,不然拋出NPE Optional<Integer> optional = Optional.of(new Integer(10)); System.out.println(optional.get()); // ofNullable 容許傳入null,可是直接調用get會拋出NoSuchElementException異常, // 可經過isPresent判斷是否存在值 Optional<Integer> optional1 = Optional.ofNullable(null); if(optional1.isPresent()) { System.out.println(optional1.get()); }else{ System.out.println("optional1 is empty"); } // orElse 判斷是否存在值,存在則返回,不存在則返回參數裏的值 Integer value = optional1.orElse(new Integer(0)); // map方法,若是optional有值,則對值進行處理返回新的Optional, // 若是沒有值則返回Optional.empty() optional = optional.map(x -> x*x); System.out.println(optional.get()); // 與map相似,只是要求返回值必須是Optional,進一步避免空指針 optional = optional.flatMap(x ->Optional.of(x*x)); System.out.println(optional.get()); } }
在java8中,Base64成爲了java類庫的標準,可直接使用
import java.util.Base64; @RunWith(SpringRunner.class) @SpringBootTest public class Base64Test { @Test public void testBase64(){ //base64編碼 String encode = Base64.getEncoder().encodeToString("abc".getBytes()); System.out.println(encode); //base64解碼 System.out.println(new String(Base64.getDecoder().decode(encode))); } }
之前的Date類是非線程安全的,而且一些經常使用的日期時間運算須要本身編寫util工具類。java8推出了java.time包,裏面包含了如 LocalDate, LocalTime, LocalDateTime等類,可方便地進行日期時間的運算,如日期間隔、時間間隔,日期時間的加減,格式化等等。
—————————————————————————————
做者:空山新雨
歡迎關注個人微信公衆號:jboost-ksxy
原文出處:https://www.cnblogs.com/spec-dog/p/11555352.html