使用java8有一段時間了, 簡單記錄一下
Lambda
Lambda類似于匿名內(nèi)部類,一個簡單的小栗子:
new Thread(() -> {
System.out.println("hello, Lambda");
}).start();
可以看到使用Lambda更簡潔
lambda表達(dá)式和內(nèi)部類有點類似,可以訪問類屬性,final方法局部變量.
注意 :更改lambda表達(dá)式中的變量不是線程安全的.
對于只包含一個抽象方法的接口, 可以通過lambda表達(dá)式創(chuàng)建該接口對象.這種接口稱為函數(shù)式接口.
(接口可以重新聲明Object類的方法,如ToString, clone, equals, 這些不是抽象方法, java8的default方法也不是) :
Comparator<Integer> c = (final Integer t1, final Integer t2) -> {return Integer.compare(t1, t2);};
上面栗子中, final是為了演示添加的,可以省略, 參數(shù)類型Integer java可以推導(dǎo)出來.
方法體中, 因為只要一句代碼,所以return和{}可以省略
Comparator<Integer> c = (t1, t2) -> Integer.compare(t1, t2);
甚至是
Comparator<Integer> c = Integer::compare;
上面使用了方法引用, 使用::
操作符引用一個方法敬惦,有三種方式
- 類::靜態(tài)方法, 調(diào)用參數(shù)作為靜態(tài)方法的參數(shù)
Integer::parseInt
等價于s -> Integer.parseInt(s)
, 對象對象s作為parseInt參數(shù) - 類::實例方法, 第一個參數(shù)就是執(zhí)行方法的對象
Object::toString
等價于o -> o.toString()
, 直接調(diào)用調(diào)用對象o的toString方法 - 構(gòu)造方法
java8提供了許多常用的函數(shù)式接口
這些函數(shù)式接口可以作為類屬性,方法參數(shù),甚至返回值
如, 提供一個解析xml的接口, 由用戶判斷一個節(jié)點是否要處理, 如果要處理, 就交由用戶進(jìn)行處理. 可以使用如下方法定義:
public void handle(Predicate<Node> p, Consumer<Node> c)
而不用只定義NodeCheck, NodeHanler等接口
Optional
使用Optional可以有效的減小null的判斷,特別是map的取值谣拣,如從一個Map<String, Object> map
獲取"amount"的值并轉(zhuǎn)化為int(假定map或map.get("amount")都可能為null),
以往的寫法:
Integer i = null;
Object o = map.get("amount");
if(o != null) {
String s = o.toString();
if(s != null) {
i = Integer.parseInt(s);
}
}
而使用Optional則非常簡潔
Integer i = optional.map(k -> k.get("amount")).map(o -> o.toString()).map(s -> Integer.parseInt(s)).orElse(null);
個人覺得:雖然Optional使用方便,但始終覺得方法定義Optional<User> getUser(String code)
沒有User getUser(String code)
直觀
stream
對于stream, 先來看個小栗子, 對一個List<Integer> list
, 過濾掉其中的奇數(shù):
list = list.stream().filter(i -> i % 2 == 0).collect(Collectors.toList());
上面栗子中尝江,可以分為3步:
-
list.stream()
創(chuàng)建一個stream -
filter(Predicate<? super T> predicate)
進(jìn)行過濾操作, 僅保留predicate返回true的元素 -
collect(Collector<? super T, A, R> collector)
進(jìn)行結(jié)果收集
除了filter, java8還提供了常用的元素處理方案:
- map 對stream中元素的類型轉(zhuǎn)換
- limit 取前n個元素
- skip 丟棄前n個元素
- distinct 丟棄重復(fù)的方法
- sort 排序
收集結(jié)果
- toArray 到數(shù)組
- collect(Collectors.toList()) 到List
- collect(Collectors.toMap) 到Map
還有其他的聚合方案
- count
- max
- min
- findFirst
- findAny
- allMatch
- noneMatch
還可以使用stream分組
對于上個栗子中的list, 現(xiàn)在按奇偶數(shù)分成兩組:
Map<Boolean, List<Integer>> oddMap = list.stream().collect(Collectors.partitioningBy(i -> i % 2 == 0));
根據(jù)屬性分組
Map<String, List<User>> cityGroup = list.stream().collect(Collectors.groupingBy(User::getCity));
這是個很有用的特性, 因為我們常常要進(jìn)行分組操作出嘹, 如對于一組user, 可以按地區(qū), 用戶等級等屬性進(jìn)行分組.
注意
可以很方便將list轉(zhuǎn)成map
Map<String, User> users = userList.stream().collect(Collectors.toMap(User::getCode, c -> c));
但如果userList中用兩個User.getCode()返回結(jié)果相同, 則會拋出異常java.lang.IllegalStateException: Duplicate key 1
可以使用userList.stream().collect(Collectors.toMap(User::getCode, c -> c, (a, b) -> a))
解決這個問題,它表示凭需,當(dāng)兩個User.getCode()結(jié)果相同時辙谜,取第一個User俺榆。
時間api
java8還有個比較大的改動,就是時間API筷弦。
java8加入了LocalDate和LocalTime肋演, 它們使用的是ISO8601標(biāo)準(zhǔn)時間格式,和時區(qū)無關(guān)烂琴,和unix時間戳類似.
unix時間戳表示從1970年1月1日(UTC/GMT的午夜)開始所經(jīng)過的秒數(shù)。 也是說, 一個unix時間戳n蜕乡, 對于每個地區(qū)奸绷, 它都表示該地區(qū)從1970年1月1日(UTC/GMT的午夜)開始經(jīng)過n秒后的時間。
如1507564800表示2017/10/10 00:00:00
, 如果在北京, 則表示北京時間2017/10/10 00:00:00
, 如果在倫敦, 則表示倫敦時間2017/10/10 00:00:00
(北京時間和倫敦時間時差八小時, 此時北京時間是2017/10/10 08:00:00
)
LocalDate和LocalTime同理层玲。
// 當(dāng)前時間
LocalDate now = LocalDate.now();
// 當(dāng)前時間加一天号醉, 并按常用格式y(tǒng)yyy-MM-dd格式化
now.plusDays(1).format(DateTimeFormatter.BASIC_ISO_DATE);
// 當(dāng)前時間減一天, 并按指定格式格式化
now.minusMonths(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
// 字符串轉(zhuǎn)時間
LocalDate date = LocalDate.parse("2019-01-26", DateTimeFormatter.ISO_DATE);
// 時間比較
now.isAfter(date);
LocalDate與Date轉(zhuǎn)換
// 時區(qū)ZoneId LocalDate時區(qū)不相關(guān), Date時區(qū), 兩者轉(zhuǎn)化需使用ZoneId
ZoneId zoneId = ZoneId.systemDefault();
LocalDate localDate = LocalDate.now();
// localDate轉(zhuǎn)ZonedDateTime
ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
// ZonedDateTime轉(zhuǎn)Date
Date date = Date.from(zdt.toInstant());
Date nowDate = new Date();
// Instant:nanosecond表示的時間戳
Instant instant = nowDate.toInstant();
// instant轉(zhuǎn)ZonedDateTime
ZonedDateTime nowZonedDate = instant.atZone(zoneId);
// ZonedDateTime轉(zhuǎn)LocalDate
LocalDate nowLocalDate = nowZonedDate.toLocalDate();
java7的新特性
簡單記錄一下java7比較重要的新特性
Path
java7新增了Path類, 可以便捷的對目錄進(jìn)行操作
當(dāng)前resources目錄結(jié)構(gòu)為
|-- resources
|-- local.properties
|-- xml
|-- local.xml
看一個小栗子
@Test
public void testPath() throws URISyntaxException {
// 獲取local.properties文件
URI localProUri = this.getClass().getClassLoader().getResource("local.properties").toURI();
// 轉(zhuǎn)換為Path對象, 指向 .../resources/test/local.properties
Path localProPath = Paths.get(localProUri);
// 解析localProPath兄弟目錄, 指向 .../resources/test/xml
Path xmlPath = localProPath.resolveSibling("xml");
// 解析xmlPath目錄目錄, 指向 .../resources/test/xml/local.xml
Path localXmlPath = xmlPath.resolve("local.xml");
// 轉(zhuǎn)換為絕對路徑
localXmlPath.toAbsolutePath();
// 獲取文件名
localXmlPath.getFileName();
// 獲取根目錄
localXmlPath.getRoot();
// 獲取父目錄
localXmlPath.getParent();
}
Files
java7也新增了Files類辛块, 可以對文件進(jìn)行讀取畔派,寫入, 復(fù)制润绵,移動等操作
@Test
public void testFileRead() throws URISyntaxException, IOException {
Path localProPath = Paths.get(this.getClass().getClassLoader().getResource("local.properties").toURI());
// 讀取文件中所以的字節(jié)
byte[] localProBytes = Files.readAllBytes(localProPath);
}
@Test
public void testFileCopy() throws URISyntaxException, IOException {
Path localProPath = Paths.get(this.getClass().getClassLoader().getResource("local.properties").toURI());
// 復(fù)制文件, StandardCopyOption.REPLACE_EXISTING表示替換已存在的文件
Path targetPath = Files.copy(localProPath, localProPath.getParent().resolve("dev.properties"), StandardCopyOption.REPLACE_EXISTING);
}
@Test
public void testAppend() throws URISyntaxException, IOException {
Path localProPath = Paths.get(this.getClass().getClassLoader().getResource("local.properties").toURI());
// 追加文件,StandardOpenOption.APPEND表示追加
Files.write(localProPath, "group=local".getBytes(), StandardOpenOption.APPEND);
}
這個有點類似于org.apache.commons.io.FileUtils類了线椰。
try-with-resources
AutoCloseable是java7添加的接口, 實現(xiàn)了該接口的資源類可以使用try-with-resources語法
try (InputStream inputStream = new FileInputStream("local.properties")) {
...
} catch (IOException e) {
e.printStackTrace();
}
對比一下原來的寫法
InputStream inputStream = null;
try {
inputStream = new FileInputStream("local.properties");
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if(inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
捕獲多個異常
java7中可以在同一個catch分支中捕獲多個異常類型尘盼。引用《寫給大忙人看的JavaSE8》中的一個栗子:
try {
...
} catch(FileNotFoundException | UnknownHostException ex) {
// 處理丟失文件和未知主機的異常
} catch() {
// 處理所有的IO異常
}
Objects
java7新增了Objects類憨愉, 提供一些常用的Object操作, 如deepEquals卿捎,isNull配紫,nonNull,requireNonNull等午阵。