重溫 javaSE
前言:有地基才能有高樓大廈
目錄- 重溫 javaSE
- 認識java
- Java基礎
- 1、資料型別
- 1.1 基本資料型別:
- 1.2 參考資料型別
- 1.3 基本資料型別的包裝類
- 1.4 基本型別與包裝類互相轉換
- 1.5 自動裝箱與拆箱
- 1.6 Byte,Short,Integer,Long快取
- 2、訪問修飾符
- 3、final關鍵字
- 4、static關鍵字
- 5、例外
- 5.1 Exception
- 5.2 處理例外
- 5.3 自定義例外
- 6、邏輯運算子
- 7、泛型
- 8、多載和重寫
- 9、abstract關鍵字
- 10、interface關鍵字(介面)
- 10.1 interface和abstract的區別
- 11、繼承
- 11.1 為什么要使用繼承?
- 11.2 實作繼承
- 11.3 this和super
- 12、implements
- 13、多型
- 14、String類
- 14.1 豐富的建構式
- 14.2 不可變有什么好處?
- 14.3 雙引號創建方式和其他創建方式的不同
- 14.4 intern方法
- 14.5 StringBuffer和StringBuilder
- 15、內部類
- 16、java 是值傳遞
- 17、類的初始化順序
- 18、++a 和 a++
- 18、jdk8特性
- Lambda
- lamdba方法參考
- Stream API
- 串行Stream:
- 并行Stream:
- 并行Stream 原理(frok join pool):
- Optional類
- 日期時間API
- Lambda
- 19、列舉類
- 1、資料型別
- java集合
- Java多執行緒
- java IO
- java 反射
- 陸續更新...
認識java
-
java是一門強型別的語言
1.1 什么叫強型別什么叫弱型別呢?-
強型別:
強制資料型別定義的語言,也就是說,一旦一個變數被指定了某個資料型別,如果不經過強制轉換,那么它就永遠是這個資料型別了,舉個例子:如果你定義了一個整形變數 a,那么程式根本不可能將 a 當作字串型別處理,強型別定義語言是型別安全的語言, -
弱型別
資料型別可以被忽略的語言,它與強型別定義語言相反, 一個變數可以賦不同資料型別的值,
強型別定義語言在速度上可能略遜色于弱型別定義語言,但是強型別定義語言帶來的嚴謹性能夠有效的避免許多錯誤,例如:JavaScript
1.2 強型別和弱型別各有什么優勢?
- 強型別:
強型別定義語言嚴謹性能避免不必要的錯誤 - 弱型別:
編譯速度快,開發敏捷
-
-
java是靜態語言
2.1 什么叫靜態語言什么叫動態語言?-
靜態語言
(1)變數的型別在編譯的時候確定
(2)變數的型別在運行時不能修改
(3)這樣編譯器就可以確定運行時需要的記憶體總量 -
動態語言
(1)變數的型別在運行的時候確定
(2)變數的型別在運行可以修改
-
-
java是跨平臺的語言
一套代碼跑各個平臺 -
java是面向程序的語言
4.1 面向程序和面向物件的優缺點- 面向程序性能比面向物件高, 因為類呼叫時需要實體化,開銷比較大,比較消耗資源,所以當性能是最重要的考量因素的時候,比如單片機、嵌入式開發、Linux/Unix 等一般采用面向程序開發,但是,面向程序沒有面向物件易維護、易復用、易擴展,
- 面向物件 :面向物件易維護、易復用、易擴展, 因為面向物件有封裝、繼承、多型性的特性,所以可以設計出低耦合的系統,使系統更加靈活、更加易于維護,但是,面向物件性能比面向程序低,
Java基礎
1、資料型別
1.1 基本資料型別:
byte short char int float double long boolean

注意:整形默認為int,如果數值不屬于int范圍,會報錯,整形后面加L代表是long資料,浮點型顯性默認為double,浮點數高精度型別不能直接賦值給低精度型別,會造成精度損失,編譯不通過,必須加F,加F代表是float資料
例如:
long value = https://www.cnblogs.com/isyuesen/p/9223372036854775807; //錯誤寫法
long value = https://www.cnblogs.com/isyuesen/p/9223372036854775807L; //正確寫法相等于long value = (long)9223372036854775807L;
float f = 1000.1; // 錯誤寫法編譯不通過
float f = 1000.1F; // 正確寫法相等于 float f = (float)1000.1;
1.2 參考資料型別
所有的非基本資料型別都是參考資料型別
1.3 基本資料型別的包裝類


1.4 基本型別與包裝類互相轉換
// 基礎型別轉成包裝類
Long l = new Long(1000L);
Long l2 = Long.valueOf(100L); // 包裝類.valueOf(基本資料型別變數)
// 包裝類轉成基本型別
long basicL = l.longValue(); // 包裝類變數.基本資料型別value()
1.5 自動裝箱與拆箱
Integer i = 10; //裝箱 相當于Integer i = Integer.valueOf(10)
int n = i; //拆箱 相當于int n = i.intValue()
1.6 Byte,Short,Integer,Long快取
對于兩個非new生成的Integer物件,進行比較時,如果兩個變數的值在區間-128到127之間,是同一個物件則為true,如果不在這區間,則為false
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false
答案在原始碼中很容易找到,裝箱是呼叫的valueOf方法,原始碼如下
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
我們看到如果是在IntegerCache.low和IntegerCache.high之間,都是回傳的同一個物件,這些物件在加載類的時候就已經創建好了
注意:Float,Double并沒有實作常量池技術,
2、訪問修飾符
| 名稱 | 中文簡稱 | 類內部是否可以訪問 | 同包是否可以訪問 | 不同包是否可以訪問 | 子類是否可以訪問 |
|---|---|---|---|---|---|
| privalte | 私有的 | 可以 | 不可以 | 不可以 | 不可以 |
| default | 默認不寫 | 可以 | 可以 | 不可以 | 不可以 |
| protected | 受保護的 | 可以 | 可以 | 不可以 | 可以 |
| public | 公開的 | 可以 | 可以 | 可以 | 可以 |
3、final關鍵字
- final類,不可被繼承
- final方法,不可被重寫,可以被多載,private 方法是隱式的 final
- final引數,不可改變引數的指向,如下:

- final變數,不可改變,被稱為常量
4、static關鍵字
static靜態、可以修飾屬性,方法,還可以定義代碼塊,被修飾的元素隸屬于類,被類的所有物件共享,
- static方法:一般稱作靜態方法,由于靜態方法不依賴于任何物件就可以進行訪問,因此對于靜態方法來說,是沒有this的,因為它不依附于任何物件,既然都沒有物件,就談不上this了,并且由于這個特性,在靜態方法中不能訪問類的非靜態成員變數和非靜態成員方法,因為非靜態成員方法/變數都是必須依賴具體的物件才能夠被呼叫
- static變數:也稱作靜態變數,靜態變數和非靜態變數的區別是:靜態變數被所有的物件所共享,在記憶體中只有一個副本,它當且僅當在類初次加載時會被初始化,而非靜態變數是物件所擁有的,在創建物件的時候被初始化,存在多個副本,各個物件擁有的副本互不影響,
- static代碼塊:static代碼塊可以置于類中的任何地方,類中可以有多個static塊, 在類初次被加載的時候,會按照static塊的順序來執行每個static塊,并且只會執行一次== ,因此,很多時候會將一些只需要進行一次的初始化操作都放在static代碼塊中進行,
- static類:static類只能是內部類
5、例外

頂層類 Throwable 派生出兩個重要的子類, Error 和 Exception
Error:Error的錯誤是致命的,一但發生Error JVM就會停止
Exeption:Exeption不會停止JVM,
5.1 Exception
例外又分為,運行時例外,和編譯例外
5.2 處理例外
-
try-catch-finaly(捕獲)
try (如果有資源需要在代碼塊執行完釋放可以把變數宣告在這里,前提是資源要實作AutoCloseable介面) { // 可能發生例外的代碼 } catch (Exception e ) { // 發生例外處理的代碼 } finally { // 不管發不發生例外都會執行的代碼塊 }注意點:
如果catch里面有return,return陳述句會在finally代碼塊的最后執行
catch可以有多個 -
throw throws (拋出例外,交給上層處理)
throw主動拋出例外
if () { throw new NumberFormatException("主動拋出") }throws 定義可能會發生的例外
public Integer test() throws NumberFormatException() { }
5.3 自定義例外
在我們日常開發中,大部分例外是夠用的,但是又些時候需要我們自己去繼承RuntimeExecption類定義一個自己的例外來滿足需求
6、邏輯運算子

邏輯運算子:先走一遍,在判斷
&、|、^、!短路邏輯運算子:一但符合條件,后面的判斷不走
&&、||
7、泛型
泛型不支持基本資料型別,用包裝類代替
為什么要使用泛型?
-
保證了型別的安全性,
-
消除強制轉換
List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0); // 使用泛型 List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); // no cast
泛型通配符:
- 上界通配符:<? extends T> 只能是T或者是T的子類
- 下界通配符:<? super T> 只能是T或者是T的父類
- 無界通配符:<?> 任何型別
8、多載和重寫
多載:方法名稱都相同,方法引數順序、引數型別、引數個數不一樣
重寫:只有繼承才會有重寫,方法名稱,方法引數順序、引數型別、引數個數都一致,重寫的訪問修飾符必須大于等于父類
9、abstract關鍵字
abstract類:天生就是為了規范來被子類繼承的,不能被實體化,不能用final修飾(因為可以abstract類就是要用來繼承的),與介面不同的是,abstract可以有普通成員變數、方法,
abstract方法:abstract方法必須存在abstract類中,不能用private、static修飾(因為子類必須要重寫),abstract方法必須被重寫
10、interface關鍵字(介面)
介面是一種特殊的抽象類,這種抽象類中只包含常量和方法的定義,而沒有變數和方法的實作,interface只能用在類上,介面中的所有方法都是abstract的,子類必須重寫,
10.1 interface和abstract的區別
interface是強調實作功能可以多實作,interface里面的方法都是abstract的,實作的子類全部要重寫,沒有構造器
abstract是強調所屬關系只能單繼承,abstract類可以存在非abstract的方法,子類可以選擇是否要重寫、有構造器
11、繼承
11.1 為什么要使用繼承?
- 提高代碼的重用性,
- 類與類之間產生了關系,是多型的前提
11.2 實作繼承
關鍵字extends,我們可以讓一個類和另一個類建立起父子關系.例如
// Student稱為子類(派生類),People稱為父類(基類或超類)
// 當子類繼承父類后,就可以直接使用父類公共的屬性和方法了
public class Student extends People {}
注意:
final 的方法子類不可重寫
private default 方法、屬性、子類不可訪問
11.3 this和super
this:是自身的一個物件,代表物件本身
- 普通直接參考當前物件本身
- 形參和成員名重名,用this來區分
- 參考構造方法,this(引數) ,應該為建構式中的第一條陳述句,呼叫的事1本類中另外一種形式的構造方法
super:可以理解為是指向自己超(父)類物件,這個超類指的是離自己最近的一個父類
- 普通的直接參考,與this類似,只不過它是父類物件,可以通過它呼叫父類成員
- 子類中的成員變數或方法與父類中的成員變數或方法同名,可以使用super區分
- 參考構造方法,super(引數):呼叫父類中的某一個構造方法(應該為構造方法中的第一條陳述句)
12、implements
implements用來實作介面,可以多實作,以逗號分割
13、多型
實作多型的條件
- 必須要有子類繼承父類的繼承關系
- 子類需要對父類中的一些方法進行重寫,然后呼叫方法時就會呼叫子類重寫的方法而不是原本父類的方法
- 在多型中需要將子類的參考賦給父類物件,只有這樣該參考才能夠具備技能呼叫父類的方法和子類的方法
例如:
public class Duo {
public void test () {
System.out.println("Duo");
}
}
public class Duo2 extends Duo {
@Override
public void test() {
System.out.println("Duo2");
}
}
public class Demo {
public static void main(String[] args) {
Duo duo = new Duo2();
duo.test(); // 輸出 Duo2
Duo duo = new Duo();
duo.test(); // 輸出 Duo
}
}
14、String類
String不是基本資料型別,它在內部存盤了一個 final char陣列

String 類是不可改變的,所以你一旦創建了 String 物件,那它的值就無法改變了,如果需要對字串做很多修改,那么應該選擇使用 StringBuffer / StringBuilder
14.1 豐富的建構式

14.2 不可變有什么好處?
- 字串常量池的設計需要
String常量池是方法區的一個特殊的儲存區,當新建一個字串(雙引號方式)的時候,如果此字串在常量池中早已存在,會回傳一個已經存在字串的參考,而不是新建一個物件, - hashCode不會變
在開發中,我們經常用String去做Map的Key,String的hashCode不會變,Map就不用重新獲取hashCode
14.3 雙引號創建方式和其他創建方式的不同
String str1 = "abc";
String str2 = "abc";
String str3 = "abc";
String str4 = new String("abc");
String str5 = new String("abc");

雙引號這種方式創建String,會判斷字串常量池中,有沒有這個常量,如果有的話,直接參考,如果沒有創建常量
其他的創建方式會在堆里創建物件,堆再參考常量池的常量,回傳堆里的參考
14.4 intern方法

我們看到這是個native方法,被native修飾的方法,都是和作業系統的打交道的方法,我們看不到,不能修改
呼叫intern方法,會判斷字串常量池中是否用,有的話直接回傳字串常量池中的參考,如果沒有就創建,回傳字串常量池的參考,證明如下:
String a = "a";
String b = new String("a");
System.out.println(a == b); // false
String c = b.intern();
System.out.println(a == c); // false
14.5 StringBuffer和StringBuilder
這兩者相同點:可變字串類,內部都維護了一個char[] value;,有擴容機制,capacity()方法可以回傳實際的長度
這兩者區別:StringBuffer內部使用synchronized 關鍵字進行修飾,所以是執行緒安全的,StringBuilder執行緒不安全

15、內部類
public class Demo {
// 成員內部類
class inner1 {}
// 靜態內部類
static class inner2 {}
public void demoMethod() {
// 方法內部類
class inner3 {}
// 匿名內部類
new Thread(new Runnable() {
@Override
public void run() {
}
});
}
}
1、成員內部類特點:
成員內部類實體需要通過外部類,如new Demo().new inner1(),成員內部類可以訪問外部類的所有屬性方法
2、區域內部類特點:
區域內部類:作用域只能是在方法內
3、靜態內部類特點:
不依賴外部類實體,外部類.new 靜態內部類()new創建物件,只能訪問外部類的靜態屬性,可以擁有自己的成員屬,通俗意思就是,定義了一個類,這個類可以訪問外部類static的成員屬性和方法
4、匿名內部類特點:
匿名內部類不能定義任何靜態成員、方法和類,通常用來實作一個介面,訪問區域變數,這個區域變數必須是final
16、java 是值傳遞
首先看下面代碼
public class Employee {
public String name=null;
public Employee(String n){
this.name=n;
}
//將兩個Employee物件交換
public static void swap(Employee e1,Employee e2){
Employee temp = e1;
e1 = e2;
e2 = temp;
System.out.println(e1.name+" "+e2.name); //列印結果:李四 張三
}
public static void main(String[] args) {
Employee worker = new Employee("張三");
Employee manager = new Employee("李四");
swap(worker,manager);
System.out.println(worker.name + " " + manager.name); //列印結果仍然是: 張三 李四
}
}
通過上面的代碼,發現形參上的交換,并沒有改變實參,所以一定不是參考傳遞,實際它是地址copy,在swap方法中,我們實際上是改變了地址值,不會影響原實參的地址參考,
我們再來看看一段代碼
public class Employee {
public StringBuilder name=null;
public Employee(StringBuilder n){
this.name=n;
}
//將兩個Employee物件交換
public static void swap(Employee e1,Employee e2){
e1.name.append("交換");
e2.name.append("交換");
}
public static void main(String[] args) {
Employee worker = new Employee(new StringBuilder("張三"));
Employee manager = new Employee(new StringBuilder("李四"));
swap(worker,manager);
System.out.println(worker.name.toString());
System.out.println(worker.name.toString()+" "+manager.name.toString()); //張三交換 李四交換
}
}
結果是改變了實參,用通俗的話就是,相當于有形參實參引數是指向同一個地址的,打個比方就是有兩把鑰匙,兩把鑰匙都可以進入房子,備用鑰匙進去,把電冰箱換成了洗衣機,然后主要鑰匙再進去肯定是電冰箱換成了洗衣機,但是第一段代碼的情況是這樣的,有兩把鑰匙,備用鑰匙又重新進鍋爐,融化,變成了可以打開其他房子的鑰匙,把其他房子的電冰箱換成了洗衣機,肯定是不會影響到主要鑰匙的房子的,判斷是否發生改變的核心就是看看是否發生了地址的改變,
17、類的初始化順序
- 初始化父類的靜態成員
- 初始化父類的靜態代碼塊
- 初始化子類的靜態成員
- 初始化子類的靜態代碼塊
- 初始化父類的非靜態成員
- 初始化父類的非靜態代碼塊
- 初始化父類的構造方法
- 初始化子類的非靜態成員
- 初始化子類的非靜態代碼塊
- 初始化子類的構造方法
(靜態成員 -> 靜態代碼塊) ->( 非靜態成員變數 -> 非靜態代碼塊 - > 構造方法)
18、++a 和 a++
++a:先自己+1,再參與運算
a++:參與運算再自己+1
我們看看++a和a++的運算元堆疊,上代碼:
public class Demo {
public static void main(String[] args) {
int a = 1;
// 1 + 3
int b = a++ + ++a;
System.out.println(b); // 4
System.out.println(a); // 3
}
}
運算元堆疊:
0 iconst_1 // 入堆疊一個1的值
1 istore_1 // a存入區域變數表第一個位置
2 iload_1 // 加載區域變數表第一個位置到堆疊 a = 1
3 iinc 1 by 1 // 區域變數表第一個位置自增+1,增加前a=1,增加后a=2
6 iinc 1 by 1 // 區域變數表第一個位置自增+1,此時 a=2,再自增+1, a=3
9 iload_1 // 加載區域變數表第一個位置 a=3
10 iadd // 相加
11 istore_2 // b存入到區域變數表2的位置
12 getstatic #2 <java/lang/System.out> //列印
15 iload_2
16 invokevirtual #3 <java/io/PrintStream.println>
19 return
18、jdk8特性
Lambda
JDK7之前有些情況,我們需要實作一個介面作為引數傳入,我們不得不,寫一個類來實作介面,而這個介面我們只需要用一次,代碼會變得臃腫,lambda的到來,就是為了解決這個問題,
在lamdba沒有出現之前,我們想要實作一個介面只有一個方法的時候,從繁到簡的演變程序:
@FunctionalInterface
public interface LambdaInterface {
void test();
}
public interface Run {
void test(LambdaInterface);
}
1、定義一個專門的類來實作
public class LamdbaImpl implements LambdaInterface {
@Override
public void test() {
}
}
public class LamdbaDemo {
public static void main(String[] args) {
Run.test(new LamdbaImpl())
}
}
2、靜態成員內部類
public class LamdbaDemo {
static class LamdbaInner implements LambdaInterface {
@Override
public void test() {
}
}
public static void main(String[] args) {
Run.test(new LamdbaInner())
}
}
3、區域內部類
public class LamdbaDemo {
public static void main(String[] args) {
class LamdbaInner implements LambdaInterface {
@Override
public void test() {
}
}
Run.test(new LamdbaInner())
}
}
4、匿名內部類
public class LamdbaDemo {
public void test() {
LambdaInterface lambdaInterface = new LambdaInterface() {
@Override
public void test() {
}
};
Run.test(lambdaInterface)
}
}
5、lamdba
public class LamdbaDemo {
public void test() {
Run.test(()->{
})
}
}
使用lamdba會可以讓我們的代碼簡潔很多,但是同時也會降低可讀性,阿里巴巴開發手冊中,規定了不允許用lamdba,
tips:在介面中添加了 @FunctionalInterface 的介面,只允許有一個抽象方法,否則編譯器也會報錯,可以擁有若干個默認方法,
注意點:lamdba內部訪問外部方法內的變數必須是final的
例如:
public class LamdbaDemo {
public static void main(String[] args) {
int i = 1;
new Thread(()-> {
i++; // error
System.out.println(i);
}).start();
}
}
lamdba方法參考
-
參考靜態方法:
參考靜態方法,介面 = Class名::靜態方法名,如果介面的回傳型別為void,靜態方法的回傳型別可以為任意的,如果介面的回傳型別不為void,靜態方法的回傳型別需要和介面一致,介面和靜態方法的引數型別,順序必須一樣,
public class LamdbaDemo { public static void main(String[] args) { // Person person = food -> { // LamdbaDemo.eat(food); // }; Person person = LamdbaDemo::eat; person.eat("1"); } static String eat(String food) { System.out.println(food); return food; } } interface Person { void eat(String food); } -
參考實體方法:
參考實體方法,介面 = Class名::成員方法名,如果介面的回傳型別為void,成員方法的回傳型別可以為任意的,如果介面的回傳型別不為void,靜態方法的回傳型別需要和介面一致,介面和方法的引數型別,從第二開始算起,順序必須一樣,因為第一個引數是實體物件,
public class LamdbaDemo { public static void main(String[] args) { Person person = LamdbaDemo::eat; person.eat(new LamdbaDemo(), "niu"); } public String eat(String food) { System.out.println(food); return food; } } interface Person { void eat(LamdbaDemo lamdbaDemo, String food); } -
參考this
參考this和實體方法的區別就是,實體就是this,可以省略不寫public class LamdbaDemo { public void test() { Person person = this::eat; person.eat("niu"); } public String eat(String food) { System.out.println(food); return food; } } interface Person { void eat(String food); }
Stream API
stream是優化集合處理的優化,它是鏈式的,對于處理資料比較大的時候,效率很高,對于資料量比較小,直接使用普通的for效率比較高
Stream和Collection集合的區別:
- Collection是一種靜態的記憶體資料結構,而Stream是有關計算的
- 前者是主要面向記憶體的,存盤在記憶體中;后者主要是面向CPU,通過CPU實作計算.
- 集合講的是資料,Stream講的是計算
串行Stream:
這位老哥寫的還可以,點擊跳轉
并行Stream:
多個執行緒來處理流,將一個大任務,分而治之分成很多個執行緒去執行(fork/join原理)
獲取并行流的方式:
-
通過已有的串行流獲取并行流
List<Integer> integers = Arrays.asList(1,2,3,4); Stream<Integer> stream = integers.stream(); // 通過已有的串行流獲取并行流 Stream<Integer> parallel = stream.parallel(); -
直接獲取
List<Integer> integers = Arrays.asList(1,2,3,4); // 直接獲取 Stream<Integer> stream = integers.parallelStream();
并行流的執行緒安全問題:
ArrayList<Integer> integers = new ArrayList<>();
// 添加一萬個資料到integers
for (int i = 0; i < 10000; i++) {
integers.add(new Random().nextInt(1000));
}
ArrayList<Integer> integers2 = new ArrayList<>();
// 獲取integers的并行流
integers.parallelStream().forEach(x -> {
// Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
integers2.add(x);
});
System.out.println(integers2.size());
解決方式:
- 加鎖
- 使用并發容器
- 使用collect生成List
并行Stream 原理(frok join pool):
Fork/Join框架是Java 7提供的一個用于并行執行任務的框架, 核心思想就是把大任務分割成若干個小任務,最侄訓總每個小任務結果后得到大任務結果
Fork/Join框架使用一個巧妙的演算法來平衡執行緒的負載,稱為作業竊取(work-stealing)演算法,作業竊取的運行流程圖如下:

fork join屬于并發編程系列:看這篇文章,點擊跳轉
Optional類
optional類是為了解決我們日常開發中多嵌套判斷是否為null而存在的,看一個例子:
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Country country = address.getCountry();
if (country != null) {
String isocode = country.getIsocode();
if (isocode != null) {
return isocode.toUpperCase();
}
}
}
}
這樣的代碼非常的難維護,如果我們換成Optional
首先,重構類,使其 getter 方法回傳 Optional 參考:
public class User {
private Address address;
public Optional<Address> getAddress() {
return Optional.ofNullable(address);
}
// ...
}
public class Address {
private Country country;
public Optional<Country> getCountry() {
return Optional.ofNullable(country);
}
// ...
}
現在我們可以這樣寫
User user = new User("[email protected]", "1234");
String result = Optional.ofNullable(user)
.flatMap(u -> u.getAddress())
.flatMap(a -> a.getCountry())
.map(c -> c.getIsocode())
.orElse("default");
方法:

日期時間API
簡單來說就是,jdk7之前的日期api不健全,執行緒不安全,不豐富,現在新增了幾個類,都是執行緒安全的
- LocalDate
- LocalTime
- LocalDateTime
- Instant
- Duration 計算時間差
- Period 計算日期差
- TemporalAdjuster 時間調節器,比如,獲得下個星期日,當月的最后一天或下一年的第一天的日期
- ZonedDateTime 支持時區的日期時間類
可以很清晰的看出ZonedDateTime相當于LocalDateTime+ZoneId

這篇文章寫的很好:點擊跳轉
19、列舉類
如果我們需要定義一組常量,最好是是使用列舉類
特點:可以進行排序,構造方法是私有的,不能再繼承類,
方法:
java集合
文章太長了,放在我另一篇博客中了,點擊跳轉
Java多執行緒
待更新
java IO
待更新
java 反射
待更新
陸續更新...
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/472266.html
標籤:其他
