浓缩版java8新特性
目錄
- 一、Lambda
- 1、定義/設計原因
- 2、結構
- 3、規則
- 4、使用
- 二、函數式接口
- 1、定義
- 2、設計原因
- 3、使用
- 三、方法引用
- 1、定義/設計原因
- 2、使用
- 四、接口的默認方法
- 1、定義
- 2、設計原因
- 3、使用
- 五、Stream
- 1、定義
- 2、設計原因
- 2、使用
- 六、Optional 類
- 1、定義
- 2、設計原因
- 3、使用
- 六、日期時間類
- 1、定義
- 2、設計原因
- 3、使用
- 七、Base64
- 1、定義
- 2、使用
一、Lambda
1、定義/設計原因
官方解釋:允許把函數作為一個方法的參數。使代碼變的更加簡潔緊湊。表達式免去了使用匿名方法的麻煩。
個人解釋:用來創建匿名方法
2、結構
Lambda表達式可由逗號分隔的參數列表、->符號和語句塊組成
- 可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。
- 可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。
- 可選的大括號:如果主體只有一個語句,就不需要使用大括號。
- 可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號必須指定return值
3、規則
表達式用到的局部變量不管是不是final,都會被變成final,后面代碼不可以改它了。全局變量則不受限。
4、使用
public class Java8Tester {@FunctionalInterfaceinterface MathOperation {int operation(int a, int b);}@FunctionalInterfaceinterface GreetingService {void sayMessage(String message);}public static void main(String args[]){//老版本寫法MathOperation oldAdd = new MathOperation() {@Overridepublic int operation(int a, int b) {return a+b;}};// jdk8類型聲明MathOperation addition = (int a, int b) -> a + b;// 不用類型聲明MathOperation subtraction = (a, b) -> a - b;// 大括號中的返回語句MathOperation multiplication = (int a, int b) -> { return a * b; };// 沒有大括號及返回語句MathOperation division = (int a, int b) -> a / b;// 不用括號GreetingService greetService1 = message ->System.out.println("Hello " + message);// 用括號GreetingService greetService2 = (message) ->System.out.println("Hello " + message);greetService1.sayMessage("Runoob");greetService2.sayMessage("Google");}}二、函數式接口
1、定義
官方解釋:函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。函數式接口可以被隱式轉換為 lambda 表達式和方法引用。
@FunctionalInterface,用于編譯級錯誤檢查,加上該注解,當你寫的接口不符合函數式接口定義的時候,編譯器會報錯。
2、設計原因
lambda語法只能用函數式接口,為方便檢查函數式接口,給了這個@FunctionalInterface注解
3、使用
@FunctionalInterfaceinterface GreetingService {void sayMessage(String message); } //使用Lambda表達式來表示該接口的一個實現 GreetingService greetService1 = message -> System.out.println("Hello " + message);三、方法引用
1、定義/設計原因
官方解釋:通過方法的名字來指向一個方法。可以使語言的構造更緊湊簡潔,減少冗余代碼。
個人解釋:方法引用是一種更簡潔易懂的Lambda表達式。直接訪問類或者實例的方法或者構造方法。
2、使用
先創建個接口和類
//函數式接口 @FunctionalInterface public interface Supplier<T> {T get(); }class Car {public static Car create(final Supplier<Car> supplier) {return supplier.get();}public static void collide(final Car car) {System.out.println("Collided " + car.toString());}public void repair() {System.out.println("Repaired " + this.toString());} }開始使用方法引用:
@Testpublic void MethodReferenceTest() { // 1、舊方法寫法 // final Car oldCar = Car.create(new Supplier<Car>() { // @Override // public Car get() { // return new Car(); // } // }); // 2、jdk8的lambda // final Car oldCar1 = Car.create(() -> new Car());//3、jdk8寫法//構造器引用 Class::newfinal Car newCar = Car.create(Car::new);//該方法返回的 List 與傳入數組是映射關系(視圖):set/get 操作直接作用于數組;直接修改數組,list 也會改變final List<Car> cars = Arrays.asList(newCar); /*-----------------------------分割線---------------------------------------*/// 1、舊方法寫法 // for (Car car : cars) { // Car.collide(car); // } // 2、jdk8的forEach // cars.forEach(new Consumer<Car>() { // @Override // public void accept(Car car) { // Car.collide(car); // } // }); // 3、jdk8的lambda // cars.forEach(car -> Car.collide(car));//4、jdk8方法引用寫法//類名的方法引用 Class::static_method 或者 Class::methodcars.forEach(Car::collide); /*-----------------------------分割線----------------------------------------*/final Car police = Car.create(Car::new);// 1、jdk8的lambda // cars.forEach(car -> police.follow(car));//2、jdk8方法引用寫法//特定對象的方法引用 instance::methodcars.forEach(police::follow);}/*-----------------------------分割線---------------------------------------*/String[] stringsArray= {"4","5"}; // 1、舊方法寫法 // Arrays.sort(stringsArray, new Comparator<String>() { // @Override // public int compare(String s1, String s2) { // return s1.compareToIgnoreCase(s2); // } // }); // 2、jdk8的lambda // Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2));//3、jdk8的方法引用Arrays.sort(stringsArray, String::compareToIgnoreCase);四、接口的默認方法
1、定義
官方解釋:默認方法就是接口可以有實現方法,而且不需要實現類去實現其方法。我們只需在方法名前面加個 default 關鍵字即可實現默認方法。
2、設計原因
問:為什么要有這個特性?
答:首先,之前的接口是個雙刃劍,好處是面向抽象而不是面向具體編程,缺陷是,當需要修改接口時候,需要修改全部實現該接口的類,通常能想到的解決辦法是在JDK里給相關的接口添加新的方法及實現。然而,對于已經發布的版本,是沒法在給接口添加新方法的同時不影響已有的實現。所以引進的默認方法。他們的目的是為了解決接口的修改與現有的實現不兼容的問題。
3、使用
(1)接口的默認方法
最基本使用,接口通過default定義默認方法,實現類無需實現該方法
如果一個類實現了多個接口,且這些接口有相同的默認方法,則可以通過
重寫接口的默認方法,或者使用 super 來調用指定接口的默認方法
(2)接口的靜態默認方法
不實例化接口的時候也可以用,個人感覺失去了接口的本質,但是妥協舊代碼是這樣的啦
五、Stream
1、定義
官方解釋:讓你以一種聲明的方式處理數據。將要處理的元素集合看作一種流, 流在管道中傳輸, 并且可以在管道的節點上進行處理, 比如篩選, 排序,聚合等。元素流在管道中經過中間操作的處理,最后由最終操作得到前面處理的結果。Stream API可以極大提高Java程序員的生產力,讓程序員寫出高效率、干凈、簡潔的代碼。
個人解釋:把數組通過.stream()或者.parallelStream()轉換成流,然后通過filter、map、distinct、sorted、limit等方法進行中間處理,最后通過collect、forEach、count得出最終結果。
2、設計原因
簡化數組處理
2、使用
public static void main(String[] args) {List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5, 1, 9, 10, 4, 1);/*=======================返回Stream<T>==========================*///1、filter過濾strings.stream().filter(string -> !string.isEmpty());//2、map映射每個元素到對應的結果numbers.stream().map(i -> i * i);//3、distinct去重numbers.stream().distinct();//4、sorted排序numbers.stream().sorted();//4、limit限制數量numbers.stream().limit(5);//5、并行處理,主要適用于大數據量的數組strings.parallelStream();/*=======================對流進行轉換或處理的==========================*///1、collect轉換成列表或字符串,Collectors 可將流轉換成集合和聚合元素List<String> collect = strings.stream().collect(Collectors.toList());String collectStr = strings.stream().collect(Collectors.joining(", "));//2、forEach迭代流中的每個數據strings.stream().forEach(System.out::println);//3、count統計數量long count = strings.stream().count();/*=======================拓展IntStream,LongStream,DoubleStream==========================*///1.1、mapToInt將Stream轉換成IntStream, summaryStatistics是對IntStream數據進行匯總統計的方法,(LongStream,DoubleStream同理)IntSummaryStatistics summary = numbers.stream().mapToInt(x ->x).summaryStatistics();System.out.println(summary.getAverage());System.out.println(summary.getCount());System.out.println(summary.getMax());System.out.println(summary.getMin());System.out.println(summary.getSum());//1.2、IntStream,LongStream創建區間方式是一樣的int[] range1 = IntStream.rangeClosed(13, 15).toArray();//生產區間 [a,b] range1=[13,14,15]int[] range2 = IntStream.range(13, 15).toArray();//生產區間 [a,b) range2=[13,14]double[] doubles = DoubleStream.of(5.33, 2.34, 5.32, 2.31, 3.51).toArray(); //doubles=[5.33, 2.34, 5.32, 2.31, 3.51]//1.2、IntStream的統計方法(LongStream,DoubleStream同理)double average = IntStream.range(13, 15).average().getAsDouble();//average=13.5int max = IntStream.range(13, 15).max().getAsInt(); //max=14int min = IntStream.range(13, 15).min().getAsInt(); //min=13int sum = IntStream.range(13, 15).sum(); //sum=27}六、Optional 類
1、定義
官方解釋:Optional 類是一個可以為null的容器對象。如果值存在則isPresent()方法會返回true,調用get()方法會返回該對象。Optional 是個容器:它可以保存類型T的值,或者僅僅保存null。
個人解釋:換言之就是把變量轉成Optional對象,其中null都轉成Optional.empty()(就是一個空的Optional對象),然后就可以對Optional對象進行操作。好處就是發現null可選擇拋出異常。
2、設計原因
不用顯式進行空值檢測。解決空指針異常。避免null。
3、使用
public class OptionalTest {public static void main(String args[]){handleParam(null,1);//后面兩個參數自己隨意寫}//處理參數舉例子static void handleParam(String a,Integer b){//對于處理string參數Optional<String> aOpt = Optional.ofNullable(a); //允許參數空。如果非空返回一個包含引用Optional實例,否則返回Optional.empty()。System.out.println(aOpt.isPresent());//輸出aOpt是否為空a=aOpt.orElse("defaultValue");//如果為空,就給一個默認值defaultValueSystem.out.println(a);//同理對于處理int參數Optional<Integer> bOpt = Optional.of(b);//不允許參數空,不然會拋出異常b=bOpt.get();//get的時候不允許變量為空System.out.println(b);} }六、日期時間類
1、定義
加強對日期與時間的處理。
2、設計原因
在舊版的 Java 中,日期時間 API 存在諸多問題
- (1)非線程安全?? java.util.Date 是非線程安全的,所有的日期類都是可變的,這是Java日期類最大的問題之一。
- (2)設計很差?? Java的日期/時間類的定義并不一致,在java.util和java.sql的包中都有日期類,此外用于格式化和解析的類在java.text包中定義。
java.util.Date同時包含日期和時間,而java.sql.Date僅包含日期,將其納入java.sql包并不合理。另外這兩個類都有相同的名字,這本身就是一個非常糟糕的設計。 - (3)時區處理麻煩?? 日期類并不提供國際化,沒有時區支持,因此Java引入了java.util.Calendar和java.util.TimeZone類,但他們同樣存在上述所有的問題。
3、使用
public static void testTime() {// 當前詳細時間LocalDateTime currentTime = LocalDateTime.now(); //currentTime = 2019-05-30T15:05:46.408// 當前年月日LocalDate date1 = currentTime.toLocalDate(); //date1 = 2019-05-30//獲取詳細時間的月日秒Month month = currentTime.getMonth();//month=MAYint day = currentTime.getDayOfMonth();//day=30int seconds = currentTime.getSecond();//seconds=46//替換詳細時間的年月LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);//date2 = 2012-05-10T15:05:46.408//自定義年月日LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);//date3= 2014-12-12//自定義時分LocalTime date4 = LocalTime.of(22, 15); //date4 = 22:15//解析字符串LocalTime date5 = LocalTime.parse("20:15:30"); //date5 = 20:15:30LocalDateTime date6 = LocalDateTime.parse("2019-05-30T15:05:46.408");//date6 = 2019-05-30T15:05:46.408// 獲取當前時間日期ZonedDateTime date7 = ZonedDateTime.parse("2015-12-03T10:15:30+05:30[Asia/Shanghai]");//date6=2015-12-03T10:15:30+08:00[Asia/Shanghai]// 獲取時區IDZoneId id = ZoneId.of("Europe/Paris");//id= Europe/Paris//獲取默認時區ZoneId defaultZone = ZoneId.systemDefault();//defaultZone=sia/Shanghai}七、Base64
1、定義
官方解釋:Base64工具類提供了一套靜態方法獲取下面三種BASE64編碼器和解碼器:
- 基本:輸出被映射到一組字符A-Za-z0-9+/,編碼不添加任何行標,輸出的解碼僅支持A-Za-z0-9+/。
- URL:輸出映射到一組字符A-Za-z0-9+_,輸出是URL和文件。
- MIME:輸出隱射到MIME友好格式。輸出每行不超過76字符,并且使用'\r'并跟隨'\n'作為分割。編碼輸出最后沒有行分割。
2、使用
public static void main(String args[]) {try {// 使用基本編碼String base64encodedString = Base64.getEncoder().encodeToString("我是測試字符串".getBytes("utf-8"));//base64encodedString = "5oiR5piv5rWL6K+V5a2X56ym5Liy"// 解碼byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);String base64decodedStr= new String(base64decodedBytes, "utf-8");//base64decodedStr = "我是測試字符串"//使用URL編碼String urlEncodedString = Base64.getUrlEncoder().encodeToString("testUrl?java8".getBytes("utf-8"));//urlEncodedString = "VHV0b3JpYWxzUG9pbnQ_amF2YTg="//使用MIME編碼String mimeEncodedString = Base64.getMimeEncoder().encodeToString(("QWERTYUIOP-ASDFGHJKL-ZXCVBNM").getBytes("utf-8"));//mimeEncodedString = "UVdFUlRZVUlPUC1BU0RGR0hKS0wtWlhDVkJOTQ=="}catch(UnsupportedEncodingException e){System.out.println("Error :" + e.getMessage());}}轉載于:https://www.cnblogs.com/ranandrun/p/java8.html
總結
以上是生活随笔為你收集整理的浓缩版java8新特性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Go-Web框架-Beego架构(二)
- 下一篇: 迭代器 生成器 装饰器 匿名函数