JDK1.8,Java8常用新特性

A.Lamdba表達式

1.Java8概述

Java8,也就是jdk1.8,是意義深遠的一個新版本

是Java5之後一個大的版本升級,讓Java語言和庫彷彿獲得了新生

新特性包含:

a.隨着大數據的興起,函數式編程在處理大數據上的優勢開始體現,引入了Lambada函數式編程

b.使用Stream徹底改變了集合使用方式:只關注結果,不關心過程

c.新的客戶端圖形化工具界面庫:JavaFX

d.良好設計的日期/時間API

e.增強的併發/並行API

f.Java與JS交互引擎 -nashorn

g.其他特性

2.什麼是Lambda表達式

帶有參數變量的表達式,是一段可以傳遞的代碼,可以被一次或多次執行

是一種精簡的字面寫法,其實就是把匿名內部類中“一定”要做的工作省略掉

然後由JVM通過推導把簡化的表達式還原

格式:  (parameters參數) -> expression表達式或方法體

paramaters:

類似方法中的形參列表,這裏的參數是函數式接口裏的參數

->:可理解爲“被用於”的意思

方法體:

可以是表達式也可以代碼塊,是函數式接口裏方法的實現

如果負責運算的代碼無法用表達式表示,可以使用編寫方法實現

但必須用{}包圍並按需明確使用 return語句

需求:對字符串數組按字符串長度排序

 

package org.xxxx.demo01;
 
import java.util.Arrays;
import java.util.Comparator;
 
public class Demo01 {
	public static void main(String[] args) {
		// 定義字符串數組
		String[] strArr = { "abc", "cd", "abce", "a" };
 
		// 傳統方法
		// 匿名內部類
		Arrays.sort(strArr, new Comparator<String>() {
 
			@Override
			public int compare(String s1, String s2) {
				return Integer.compare(s2.length(), s1.length());
			}
		});
 
		// 輸出排序結果
		for (String s : strArr) {
			System.out.println(s);
		}
		System.out.println("---------------------");
 
		// Lambda表達式
		Arrays.sort(strArr, (s1, s2) -> Integer.compare(s2.length(), s1.length()));
 
		// 輸出
		for (String s : strArr) {
			System.out.println(s);
		}

需求:用Lambda實現多線程


package org.xxxx.demo01;
 
public class Demo01 {
	public static void main(String[] args) {
		// Lambda表達式
		new Thread(() -> System.out.println(1 + "hello world")).start();
 
		System.out.println("----------------");
 
		// 方法體
		new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				System.out.println(2 + "hello world");
			}
		}).start();
	}
}

3.何時使用

通過上面的兩個需求,發現Lamdba表達式很簡單,那何時使用呢

需要顯示創建函數式接口對象的地方,都可以使用

實際上函數式接口的轉換是Lambda表達式唯一能做的事情

即lambda必須和Functional Interface配套使用

主要用於替換以前廣泛使用的內部匿名類,各種回調

比如事件響應器、傳入Thread類的Runnable等

4.函數式接口分類

a.系統與定義函數接口(Comparator, Runnable)

b.用戶自定義函數接口(註解必須有,表達式是直接通過參數列表來實現的,只能有一個有效方法)


@FunctionalInterface
public interface MyInterface {
	String info(String tip);
}

 

5.公共定義的函數式接口

從jdk1.8開始爲了方便用戶開發專門提供了一個新的包:java.util.function

在這個包裏面針對於用戶有可能做的函數式接口做了一個公共定義

最爲核心的有四個接口:

a.功能性接口:Function<T, R>

有輸入參數,有返回值

是對接收一個T類型參數,返回R類型的結果的方法的抽象

通過調用apply方法執行內容

需求:給定一個字符串,返回字符串長度

package org.xxxx.demo01;
 
import java.util.function.Function;
 
public class Demo01 {
	public static void main(String[] args) {
		// 定義字符串
		String str = "helloworld";
		
		// 調用方法
		// 在調用的時候寫方法體,方法比較靈活
		int length = testFun(str, (s) -> s.length());
		
		System.out.println(length);
	}
	
	// 方法
	/**
	 * 
	 * @param str 輸入參數
	 * @param fun 表達式 String 爲輸入類型,Integer爲輸出類型
	 * @return 返回字符串長度
	 */
	public static int testFun(String str, Function<String, Integer> fun) {
		// 執行
		Integer length = fun.apply(str);
		
		return length;
	}
}

 

b.消費型接口:Consumer<T>

有輸入參數,沒返回值

對應的方法類型爲接收一個參數,沒有返回值

一般來說使用Consumer接口往往伴隨着一些期望狀態的改變

或者事件的發生,典型的forEach就是使用的Consumer接口

雖然沒有任何的返回值,但是向控制檯輸出結果

Consumer 使用accept對參數執行行爲

需求:輸出字符串


package org.xxxx.demo01;
 
import java.util.function.Consumer;
 
public class Demo01 {
	public static void main(String[] args) {
		// 創建字符串
		String str = "hello world";
		
		// 調用
		testCon(str, (s) -> System.out.println(s));
	}
	
	/**
	 * 
	 * @param str 傳入參數
	 * @param con
	 */
	public static void testCon(String str, Consumer<String> con) {
		// 執行
		con.accept(str);
	}
	
}

 

c.供給型接口:Supplier<T>

無傳入參數,有返回值

該接口對應的方法類型不接受參數,但是提供一個返回值

使用get()方法獲得這個返回值

package org.xxxx.demo01;
 
import java.util.function.Supplier;
 
public class Demo01 {
	public static void main(String[] args) {
		// 創建字符串
		String str = "hello world";
		
		// 調用
		String sup = testSup(() -> str);
		
		System.out.println(sup);
	}
	
	/**
	 * 
	 * @param sup
	 * @return
	 */
	public static String testSup(Supplier<String> sup) {
		// 執行
		String s = sup.get();
		return s;
	}
	
}

 

d.斷言型接口:Predicate<T>

有傳入參數,有返回值Boolean

該接口對應的方法爲接收一個參數,返回一個Boolean類型值

多用於判斷與過濾,使用test()方法執行這段行爲

需求:輸入字符串,判斷長度是否大於0

package org.xxxx.demo01;
 
import java.util.function.Predicate;
 
public class Demo01 {
	public static void main(String[] args) {
		// 創建字符串
		String str = "hello world";
		
		// 調用
		boolean flag = testPre(str, (s) -> s.length() > 0);
		
		System.out.println(flag);
	}
	
	/**
	 * 
	 * @param str
	 * @param pre
	 * @return
	 */
	public static boolean testPre(String str, Predicate<String> pre) {
		// 執行
		boolean flag = pre.test(str);
		
		return flag;
	}
	
}

 

6.Lambda的優點

a.極大的減少代碼冗餘,同時可讀性也好過冗長的匿名內部類

b.與集合類批處理操作結合,實現內部迭代,並充分利用現代多核CPU進行並行計算。之前集合類的迭代都是外部的,即客戶代碼。而內部迭代意味着由Java類庫來進行迭代,而不是客戶代碼

7.和匿名內部類的區別

a.在lambda中,this不是指向lambda表達式產生的那個對象,而是它的外部對象

b.Java 編譯器編譯 Lambda 表達式並將他們轉化爲類裏面的私有函數,它使用 Java 7 中新加的 invokedynamic 指令動態綁定該方法,但每一個匿名內部類編譯器會爲其創建一個類文件

B.方法引用

1.概述

某些lambda表達式裏面僅僅是調用了一個已存在的方法,在這種情況下

直接通過方法名稱引用方法的形式可讀性更高一些,這種形式就是方法引用

方法引用是一種更簡潔易懂的lambda 表達式替換

其唯一用途就是支持Lambda的簡寫

函數接口中抽象方法的參數列表,必須與方法引用方法的參數列表保持一致

方法引用中::後只是方法名,不能加();

forEach()也是jdk8的新特性

比如:list.forEach((s) -> System.out.println(s));---list.forEach(Syetem.out::println);

2.類靜態方法引用

求絕對值,使用Function實現

package org.xxxx.demo01;
 
import java.util.function.Function;
 
public class Demo01 {
	public static void main(String[] args) {
		// 調用
		long l1 = testAbs(-10L, (s) -> Math.abs(s));
		
		// 改進
		long l2 = testAbs(-10, Math::abs);
		
		System.out.println(l1);
		System.out.println(l2);
	}
	
	public static long testAbs(long s, Function<Long, Long> fun) {
		Long l = fun.apply(s);
		return l;
	}
}

 

3.實例方法引用

循環集合中元素,使用forEach方法

(s) -> System.out.println(s)的類型是Consumer類型

其accept接受參數和println一致


package org.xxxx.demo01;
 
import java.util.ArrayList;
import java.util.List;
 
public class Demo01 {
	public static void main(String[] args) {
		// 創建集合
		List<String> list = new ArrayList<>();
		
		// 添加元素
		list.add("e");
		list.add("c");
		list.add("a");
		list.add("d");
		list.add("b");
		
		// 排序
		list.sort((s1, s2) -> s1.compareTo(s2));
		
		// 遍歷
		list.forEach((s) -> System.out.println(s));
		list.forEach(System.out::println);
	}
}

 

4.構造方法引用

在引用構造器的時候,構造器參數列表要與接口中抽象方法的參數列表一致

格式爲 類名::new


package org.xxxx.demo01;
 
import java.util.function.Supplier;
 
public class Demo01 {
	public static void main(String[] args) {
		getString(String :: new);
	}
	
	public static void getString(Supplier<String> su) {
		String s = su.get();
		System.out.println(s == null);
	}
}

 

5.任意對象的實例方法

若Lambda表達式的參數列表的第一個參數,是實例方法的調用者

第二個參數(或無參)是實例方法的參數時,就可以使用這種方法

參考第3條中的排序

C.Stream流

1.思考

計算字符串List中長度大於2的元素的數量

分析:使用增強for循環

a.代碼冗餘

b.實現並行計算很麻煩

c.代碼無法及時傳遞程序員的意圖 ,必須讀完代碼

2.外部迭代

 forEach工作原理:代碼底層使用Iterator進行迭代的,是串行化操作

3.內部迭代

4.Stream概述

是用函數式編程方式在集合類上進行復雜操作的工具,更像一個高級版本的 Iterator

原始版本的 Iterator,用戶只能顯式地一個一個遍歷元素並對其執行某些操作

高級版本的 Stream,用戶只要給出需要對其包含的元素執行什麼操作

Stream 會隱式地在內部進行遍歷,做出相應的數據轉換

而和迭代器又不同的是,Stream 可以並行化操作

藉助於 Lambda 表達式,極大的提高編程效率和程序可讀性

5.常用操作

a.forEach

迭代集合中元素。接收一個 Lambda 表達式

然後在 Stream 的每一個元素上執行該表達式

此操作是及早求值方法

b.collect(toList()) 

由Stream 裏的值生成一個列表,是一個及早求值操作

很多Stream 操作都是惰性求值,因此調用Stream 一系列方法之後

還需最後再調用一個類似collect 的及早求值方法返回集合

開篇的例子:(再將符合要求的字符串放到一個新的集合裏)

使用filter過濾器:遍歷數據並檢查其中的元素

package org.xxxx.demo01;
 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
 
public class Demo01 {
	public static void main(String[] args) {
		// 創建集合
		List<String> list = new ArrayList<>();
 
		// 添加元素
		list.add("sdf");
		list.add("a");
		list.add("asdf");
		list.add("d");
		list.add("basdfgh");
 
		// 統計長度大於2的
		long count = list.stream().filter((s) -> s.length() > 2).count();
 
		// 將符合要求的放入集合
		List<String> list2 = list.stream().filter((s) -> s.length() > 2).collect(Collectors.toList());
 
		System.out.println(count);
		list2.forEach(System.out :: println);
	}
 
}

 

6.map

如果有一個函數可以將一種類型的值轉換成另外一種類型

map 操作就可以使用該函數,將一個流中的值轉換成一個新的流

需求:將字符串全轉換成大寫

package org.xxxx.demo01;
 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
 
public class Demo01 {
	public static void main(String[] args) {
		// 創建集合
		List<String> list = new ArrayList<>();
 
		// 添加元素
		list.add("sdf");
		list.add("a");
		list.add("asdf");
		list.add("d");
		list.add("basdfgh");
		
		// 轉換爲大寫
		List<String> list2 = list.stream().map((s) -> s.toUpperCase()).collect(Collectors.toList());
		
		list2.forEach(System.out :: println);
 
	}
 
}

 

7.filter

遍歷數據並檢查其中的元素。例如獲取字符串List中以數字開始的字符集合

package org.xxxx.demo01;
 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
 
public class Demo01 {
	public static void main(String[] args) {
		// 創建集合
		List<String> list = new ArrayList<>();
 
		// 添加元素
		list.add("1sdf");
		list.add("a");
		list.add("2asdf");
		list.add("d");
		list.add("basdfgh");
 
		// 獲取數字開頭的
		List<String> list2 = list.stream().filter((s) -> Character.isDigit(s.charAt(0))).collect(Collectors.toList());
 
		list2.forEach(System.out::println);
	}
 
}

 

8.flatMap 

可用Stream 替換值, 然後將多個Stream 連接成一個Stream

map 操作可用一個新的值代替Stream 中的值

若用戶希望讓map操作有點變化

生成一個新的Stream 對象取而代之則flatMap適用

假設有一個包含多個列表的流,現在希望得到所有數字的序列

package org.xxxx.demo01;
 
import java.util.Arrays;
import java.util.stream.Stream;
 
public class Demo01 {
	public static void main(String[] args) {
 
		Stream<?> flatMap = Stream.of(Arrays.asList("a", "b"), Arrays.asList(1, 2, 3)).flatMap((s) -> s.stream());
		flatMap.forEach(System.out :: println);
	}
 
}

 

9.max和min

獲取Stream中最大值或最小值,獲取字符串List中長度最長的字符串長度

package org.xxxx.demo01;
 
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
 
public class Demo01 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		
		list.add("abc");
		list.add("ab");
		list.add("abcd");
		list.add("abcde");
		
		// 獲取最大值
		int max = list.stream().map((s) -> s.length()).max(Integer :: compareTo).get();
		System.out.println(max);
		
		// 獲取最小值,另一種方法
		int min = list.stream().min(Comparator.comparing((s) -> s.length())).get().length();
		System.out.println(min);
	}
 
}

 

10.reduce

通過指定的函數把stream中的多個元素匯聚爲一個元素,min max等是它的特例

格式:reduce(初始值,(r, i) -> r + i) 或者 reduce((r, i) -> r + "*" i)

計算1~100的和

package org.xxxx.demo01;
 
import java.util.ArrayList;
import java.util.List;
 
public class Demo01 {
	public static void main(String[] args) {
		List<Long> list = new ArrayList<>();
		
		// 封裝到集合
		for (long i = 1; i <= 100; i++) {
			list.add(i);
		}
		
		// 計算
		// reduce:參1,和的初始值
		Long sum = list.stream().parallel().reduce(0L, (r, l) -> r + l);
		
		System.out.println(sum);
	}
 

 

11.練習

a.獲取Student集合中年齡小於20歲的集合中年齡最大的學生信息

Student類省略

package org.xxxx.demo01;
 
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
 
public class Demo01 {
	public static void main(String[] args) {
		List<Student> list = new ArrayList<>();
 
		Student s1 = new Student("張三", 21);
		Student s2 = new Student("李四", 19);
		Student s3 = new Student("王五", 18);
		Student s4 = new Student("程六", 17);
		Student s5 = new Student("趙七", 20);
 
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);
 
		// 篩選
		Student student = list.stream().filter((s) -> s.getAge() < 20).max(Comparator.comparing((s) -> s.getAge()))
				.get();
		System.out.println(student);
	}
 
}

 b.查找集合中以a開頭的字符的長度集合

package org.xxxx.demo01;
 
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
public class Demo01 {
	public static void main(String[] args) {
		List<Integer> list = Stream.of("abc", "b", "a", "abcd").filter((s) -> s.startsWith("a")).map((s) -> s.length())
				.collect(Collectors.toList());
		System.out.println(list);
	}
 
}

D.並行API

1.概述

在Java7之前,並行處理數據基本是通過多線程來解決

a.將數據分成部分

b.給每個子部分分配一個子線程

c.等待所有的子線程全部結束

d.合併子線程

這樣的並行數據處理不穩定、易出錯,在Java8中Stream接口應用分支/合併框架

將一個數據內容分成多個數據塊,並用不同的線程分別處理每個數據塊流

Stream有串行和並行兩種,串行Stream上的操作是在一個線程中依次完成

而並行Stream則是在多個線程上同時執行

並行是每個cpu運行一個程序

2.使用方法

通常編寫並行代碼很難而且容易出錯,

但使用 Stream API 無需編寫一行多線程的代碼

就可以很方便地寫出高性能的併發程序 

a.調用Stream的parallel()方法

b.調用Collection的parallelStream()方法

c.parallel() 與 sequential() 可在並行流與順序流之間切換

package org.xxxx.demo01;
 
import java.util.ArrayList;
import java.util.List;
 
public class Demo01 {
	public static void main(String[] args) {
		List<Long> list = new ArrayList<>();
		
		// 封裝到集合
		for (long i = 1; i <= 100; i++) {
			list.add(i);
		}
		
		// 計算
		// reduce:參1,和的初始值
		Long sum = list.stream().parallel().reduce(0L, (r, l) -> r + l);
		
		System.out.println(sum);
	}
 
}

 

3.使用並行的建議

a.儘量使用基本類型的流  IntStream, LongStream, and DoubleStream

b.有些操作使用併發流的性能會比順序流的性能更差,比如limit,findFirst,依賴元素順序的操作在併發流中是極其消耗性能的.findAny的性能就會好很多,因爲不依賴順序

c.考慮流中計算的性能(Q)和操作的性能(N)的對比, Q表示單個處理所需的時間, N表示需要處理的數量,如果Q的值越大, 使用併發流的性能就會越高

d.數據量不大時使用併發流,性能得不到提升

e.考慮數據結構:併發流需要對數據進行分解,不同的數據結構被分解的性能時不一樣的

f.傳遞給並行流的函數都是線程安全的,無副作用

4.何時需要並行編程

a.是否需要並行

弄清楚你要解決的問題是什麼,數據量有多大,計算的特點是什麼

並不是所有的問題都適合使用併發,比如當數據量不大時

順序執行往往比並行執行更快。

準備線程池和其它相關資源也是需要時間的

但當任務涉及到I/O操作並且任務之間不互相依賴時,那麼適合並行化

b.任務之間是否是獨立的?是否會引起任何競態條件

如果任務之間是獨立的

並且代碼中不涉及到對同一個對象的某個狀態或者某個變量的更新操作

那麼就表明代碼是可以被並行化的

c.結果是否取決於任務的調用順序

由於在並行環境中任務的執行順序是不確定的

因此對於依賴於順序的任務而言,並行化也許不能給出正確的結果

E.Time日期時間

1.舊的日期時間缺點

a.非線程安全

 java.util.Date不是線程安全的

因此開發者必須在使用日期處理併發性問題

新的日期時間API是不可變的,並且沒有setter方法

b.設計不佳

默認的開始日期從1900年,開始每月從1天從0開始,所以沒有統一

不直接使用方法操作日期。新的API提供了這樣操作實用方法

c. 困難的時區處理

開發人員必須編寫大量的代碼來處理時區的問題

新的API設計開發保持特定領域設計

2.Instat

a.概述

時間戳,即時間軸上的一個點

從元年1970-1-1 00:00:00到現在的nanosecond數

b. Instant.now();獲取當前時間

package org.xxxx.demo01;
 
import java.time.Instant;
 
public class Demo01 {
	public static void main(String[] args) {
		// 獲取當前時間
		Instant now = Instant.now();
		
		// T代表東西經0°經線區時:倫敦時間
		System.out.println(now);// 2017-11-25T14:06:57.079Z
	}
 
}

 c.Instant.ofEpochMilli(new Date().getTime()); 舊日期轉爲新日期

package org.xxxx.demo01;
 
import java.time.Instant;
import java.util.Date;
 
public class Demo01 {
	public static void main(String[] args) {
		// 獲取當前時間
		Instant instant = Instant.ofEpochMilli(new Date().getTime());
		System.out.println(instant);
	}
 
}

d. Instant.parse();日期文本格式轉換爲時間格式

package org.xxxx.demo01;
 
import java.time.Instant;
 
public class Demo01 {
	public static void main(String[] args) {
		// 獲取當前時間
		Instant instant = Instant.parse("1993-02-06T10:12:35Z");
		System.out.println(instant);
	}
 
}

3.LocalDate

表示不帶時區的日期,比如2014-01-14

a.LocalDateTime.now();獲取當前日期時間

b.now.minusDays(2);將當前日期時間減去兩天

c.LocalDateTime.of(2016, 10, 23);構造一個指定日期時間的對象

package org.xxxx.demo01;
 
import java.time.LocalDate;
 
public class Demo01 {
	public static void main(String[] args) {
		// 當前時間
		LocalDate now = LocalDate.now();
		System.out.println(now);
		
		// 往前推兩天
		LocalDate date = now.minusDays(2);
		System.out.println(date);
		
		// 制定一個日期
		LocalDate localDate = LocalDate.of(1993, 2, 6);
		System.out.println(localDate);
	}
 
}

 

4.LocalTime

表示不帶時區的時間

a. LocalTime.now();當前時間

b. LocalTime.of(22, 33);確定的時間

c.LocalTime.ofSecondOfDay(4503); 一天中的第4503秒

package org.xxxx.demo01;
 
import java.time.LocalTime;
 
public class Demo01 {
	public static void main(String[] args) {
		// 當前時間
		LocalTime now = LocalTime.now();
		System.out.println(now);
		
		// 22:33
		LocalTime localTime = LocalTime.of(22, 33);
		System.out.println(localTime);
		
		// 一天中的4503秒
		LocalTime ofDay = LocalTime.ofSecondOfDay(4503);
		System.out.println(ofDay);
	}
 
}

 

5.LocalDateTim

 是LocalDate和LocalTime的組合體,表示的是不帶時區的日期及時間

a.LocalDateTime.now();當前時間

b.localDateTime.plusHours(25).plusMinutes(3); 當前時間加上25小時3分鐘

c.LocalDateTime.of(2014, 1, 20, 3, 30, 20);轉換

package org.xxxx.demo01;
 
import java.time.LocalDateTime;
 
public class Demo01 {
	public static void main(String[] args) {
		// 當前時間
		LocalDateTime now = LocalDateTime.now();
		System.out.println(now);
 
		// 當前時間加上25小時3分鐘
		LocalDateTime plusMinutes = now.plusHours(25).plusMinutes(3);
		System.out.println(plusMinutes);
 
		// 轉換
		LocalDateTime of = LocalDateTime.of(1993, 2, 6, 11, 23, 30);
		System.out.println(of);
	}
 
}

 

6.ZoneDateTime

含有時區信息的時間

a.ZonedDateTime.now();獲取包含時區的當前日期時間

b.ZonedDateTime.of(LocalDateTime.of(2014, 1, 20, 3, 30, 20), ZoneId.of("+08"));創建時區的日期時間對象


package org.xxxx.demo01;
 
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
 
public class Demo01 {
	public static void main(String[] args) {
		// 當前時間
		ZonedDateTime now = ZonedDateTime.now();
		System.out.println(now);
 
		// 創建時區的日期時間對象
		ZonedDateTime of = ZonedDateTime.of(LocalDateTime.of(1993, 2, 6, 11, 23, 30), ZoneId.of("+08"));
		System.out.println(of);
	}
 
}

 

7.DateTimeFormatter

格式化日期和解析日期格式字符串。DateTimeFormatter是不可變類

a.格式化:日期對象轉換爲格式字符串

package org.xxxx.demo01;
 
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
 
public class Demo01 {
	public static void main(String[] args) {
		// 格式化
		String time = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss").format(LocalDateTime.now());
		System.out.println(time);
	}
 
}

 b.解析:格式字符串轉換爲日期對象

package org.xxxx.demo01;
 
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
 
public class Demo01 {
	public static void main(String[] args) {
		// 格式化
		LocalDateTime parse = LocalDateTime.parse("2017.01.01 08:08:08", DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss"));
		System.out.println(parse);
	}
 
}

8. 遺留代碼操作

a.Date --> Instant

b.Calendar-->Instant

package org.xxxx.demo01;
 
import java.time.Instant;
import java.util.Calendar;
import java.util.Date;
 
public class Demo01 {
	public static void main(String[] args) {
		Instant timestamp = new Date().toInstant(); 
		
		Instant instant = Calendar.getInstance().toInstant();
		
		System.out.println(timestamp);
		System.out.println(instant);
	}
 
}

F.其他

1.默認方法

接口和它的實現類保持兼容非常重要

因爲你開發的類庫可能正在被多個開發者廣泛的使用着

若上層接口需要做改變的時候(如增加新的空方法)

下層接口就需要實現新增的方法,在某些情況下,變得不靈活

因此:使用默認方法

接口中定義的default修飾的有具體實現的方法,是給接口增加的公用方法

是對象方法,需要使用對象來進行訪問

添加默認方法,對以前代碼不會有影響,避免其實現類都做出相應的改動

且default方法通常使用已經實現類已存在的方法進行定義

2.問:

如果一個接口中定義一個默認方法

另外一個父類或接口中定義同名方法(不管是否default)時候,子類如何處理

a.選擇父類方法。當父類提供具體實現時,接口同名同參方法被忽略

b.覆蓋父類方法。當一個父接口提供默認方法,另一個父接口提供同名同參方法時候

3.靜態方法

接口中定義的static修飾的有具體實現的方法

類似於default方法,但在實現類中不能覆蓋(override)該方法

接口的static方法只對接口裏的方法可見,和其他靜態方法類似

可以使用接口名來調用接口中的靜態方法

接口的static方法有利於提供通用的方法,比如判空檢查,集合排序等

可以移除工具類中方法到接口static方法中

例如:sList.sort((s,t)->Integer.compare(s.length(), t.length()));

轉換爲靜態方法:sList.sort(Comparator.comparing(String::length));

4.String新增join(字符串集合或數組)方法

使用指定連接符連接多個字符串

package org.xxxx.demo01;
 
public class Demo01 {
	public static void main(String[] args) {
		String[] str = {"a", "b", "c"};
		
		String join = String.join("-", str);
		System.out.println(join);
	}
}

 

5.可能錯過的Java7特性

try--with-resources

在 JDK 7 之前,文件資源需要手動finally中關閉

try-with-resources 能夠很容易地關閉在 try-catch 語句塊中使用的資源

所謂的資源(resource)是指在程序完成後,必須關閉的對象

try-with-resources 語句確保了每個資源在語句結束時關閉

所有實現了 java.lang.AutoCloseable 接口的對象可以使用作爲資源

在try( ...)裏聲明的資源,會在try-catch代碼塊結束後自動關閉掉

 

 

 

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