原文鏈接
非常簡單地整理了一下Java 8 中出現(xiàn)的新特性,Lambda 部分的例子借鑒了這里 度硝。
Lambda 表達式
Java 8 中最大特性,函數(shù)式編程
語法
Lambda 表達式:
parameter -> expression body
- 可選參數(shù)類型聲明 - 不需要聲明參數(shù)類型寿冕,編譯器可以自動推斷
- 可選小括號 - 只有一個參數(shù)時可以省略左側(cè)的括號蕊程,多參數(shù)時小括號是必須的
- 可選大括號 - 當(dāng)函數(shù)體只有一條語句時可以省略大括號
- 可選return關(guān)鍵字 - 函數(shù)體只有一條語句時,編譯器會自動返回結(jié)果
字符串排序 pre Java 8 實現(xiàn):
List<String> strings = Arrays.asList("ab", "a", "bd", "bc", "c", "ca");
Collections.sort(strings, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
System.out.println(strings);
out : [a, ab, bc, bd, c, ca]
如果用 Lambda 表達式:
List<String> stringsLambda = Arrays.asList("ab", "a", "bd", "bc", "c", "ca");
Collections.sort(stringsLambda, (a, b) -> a.compareTo(b));
System.out.println(stringsLambda);
可選參數(shù)類型聲明:(a, b)
等價于 (String a, String b)
可選小括號:此處有兩個參數(shù)驼唱,不可省略
可選大括號藻茂、return關(guān)鍵字:a.compareTo(b)
等價于 {return a.compareTo(b);}
Lambda 范圍
可以使用 final 類型的變量
public class Java8Tester {
final static String salutation = "Hello! ";
public static void main(String args[]) {
GreetingService greetService1 = message -> System.out.println(salutation + message);
greetService1.sayMessage("Mahesh");
}
interface GreetingService {
void sayMessage(String message);
}
}
Method references
Method references 可以通過名稱指向方法,使用符號 ::
玫恳,可以指向:
- 靜態(tài)方法
- 實例方法
- 使用operator的構(gòu)造函數(shù)
TreeSet::new
List names = new ArrayList();
names.add("Alice");
names.add("Bob");
names.add("Chirs");
names.forEach(System.out::println);
out:
Alice
Bob
Chris
Functional interfaces
Functional interfaces 具有單一功能辨赐,舉例來說 Comparable
接口僅僅有一個用于比較大小的方法CompareTo
, Java 8 中定義了很多 Functional interfaces,以便在 lambda表達式 中廣泛使用京办。
Predicate <T>
是一個包含一個方法test(Object)
的實用接口掀序,這個方法返回一個布爾值,用來表示傳入對象的測試結(jié)果是 true 或 false惭婿。
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
for(Integer n: list) {
if(predicate.test(n)) {
System.out.print(n + " ");
}
}
System.out.println();
}
測試一下:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println("Print all numbers:");
eval(list, n->true);
System.out.println("Print even numbers:");
eval(list, n-> n%2 == 0 );
System.out.println("Print numbers greater than 3:");
eval(list, n-> n > 3 );
out :
Print all numbers:
1 2 3 4 5 6 7 8 9
Print even numbers:
2 4 6 8
Print numbers greater than 3:
4 5 6 7 8 9
Default Methods
Default Methods不恭,可以讓原有接口使用 Lambda 表達式。
比如财饥,List
和Collection
接口都沒有聲明 forEach
方法换吧,強行加上這類方法又會破壞集合原有的實現(xiàn)框架。
語法
public interface vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}
Multiple Defaults
當(dāng)接口中有 default 函數(shù)時钥星,有可能一個類實現(xiàn)了2個接口式散,而這2個接口中包含了同名的 default 函數(shù)
public interface vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}
public interface fourWheeler {
default void print() {
System.out.println("I am a four wheeler!");
}
}
第一種解決辦法:方法重寫
public class car implements vehicle, fourWheeler {
default void print() {
System.out.println("I am a four wheeler car vehicle!");
}
}
第二種解決辦法:通過super
調(diào)用特定接口的default方法
public class car implements vehicle, fourWheeler {
default void print() {
vehicle.super.print();
}
}
Static Default Methods
接口同時可以擁有靜態(tài)函數(shù)
public interface vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
static void blowHorn() {
System.out.println("Blowing horn!!!");
}
}
Stream
Stream 是一個抽象層的東西,使用Stream可以像SQL語句那樣操作數(shù)據(jù)(Stream 并不能處理SQL語句):
SELECT max(salary), employee_id FROM Employee
上面的SQL語句可以直接返回最高工資員工的工資和ID打颤,而使用 Collections 集合框架暴拄,則必須遍歷和多次check才能查找出上面的信息。
Stream 的另一個好處就是高效编饺,為避免并發(fā)下容易產(chǎn)生的錯誤乖篷,Java 8 中引入 Stream 的概念,讓我們可以直接使用多核系統(tǒng)而不用考慮具體的代碼實現(xiàn)透且。
Stream 表示一系列來自Source
的對象
- 元素序列 - Stream 提供一個元素的集合撕蔼,其中的元素連續(xù)排列,且類型確定秽誊。
- 源Source - Stream 可以把集合類鲸沮、Arrays、I/O源當(dāng)做源锅论。
- Aggregate operations - Stream 支持集合運算:filter讼溺、map、limit最易、reduce怒坯、find、match等等
- Pipelining - 多數(shù) stream 操作返回 stream 本身藻懒,所以其操作結(jié)果可以用流水線的方式處理剔猿。這些操作可以叫 intermediate operations,它們接收輸入嬉荆、處理归敬、并將結(jié)果返回。
collect()
操作是一個末端操作鄙早,通常在 pipelining 操作結(jié)束時出現(xiàn)以標(biāo)記流的結(jié)束汪茧。 - 自動迭代 - 在源元素內(nèi)部遍歷,與需要顯示迭代的集合類不同蝶锋。
生成 Stream
Collection 接口有兩個方法生成 Stream
-
stream()
返回一個將當(dāng)前集合內(nèi)容作為源的 sequential stream -
parallelStream()
返回一個將當(dāng)前集合內(nèi)容作為源的 parallel Stream
Collectors
一個 Stream 經(jīng)過流操作之后還是 Stream 對象陆爽,可以通過 Collectors
將流處理的結(jié)果轉(zhuǎn)換為List
或 String
。下面例子中生成Stream對象扳缕,沒有做任何流操作慌闭,再將其轉(zhuǎn)換為List,故filtered
和 strings
內(nèi)容一致躯舔。
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().collect(Collectors.toList());
另外驴剔,Collectors
也可以將不同流操作的結(jié)果合并起來。
String mergedString = strings.stream().collect(Collectors.joining(", "));
System.out.println("Merged String: " + mergedString);
//out : Merged String: abc, , bc, efg, abcd, , jkl
map
把每一個元素映射為相應(yīng)的結(jié)果粥庄。下面例子中將數(shù)字映射為其平方丧失,并打印不重復(fù)的值
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream()
.map( i -> i*i)
.distinct()
.collect(Collectors.toList());
System.out.println(squaresList); // [9, 4, 49, 25]
filter
濾除不符合條件 (保留符合條件)的元素,filter(paramters -> condition)
limit
限制Stream的大小惜互,limit(5)
流中元素不夠5個時不報錯布讹,取當(dāng)前所有元素琳拭。
sorted
排序
將濾除空字符串,取前5個元素描验,并排序:
List<String> strings = Arrays.asList("123", "", "456", " ", "78", "", "9");
List<String> result = strings.stream()
.filter(str -> !str.isEmpty())
.limit(5)
.sorted()
.collect(Collectors.toList());
System.out.println(result); //[ , 123, 456, 78, 9]
forEach
Stream 提供了遍歷元素的新方法forEach
白嘁,通過它打印10個隨機數(shù):
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
random.ints()
會返回一個 Stream對象
并行處理
做并行處理時可選用 parallelStream
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
int count = strings.parallelStream().filter(string -> string.isEmpty()).count();
統(tǒng)計計算
流處理結(jié)束后,可以計算統(tǒng)計數(shù)據(jù)
List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
IntSummaryStatistics stats = integers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest number in List : " + stats.getMax());
System.out.println("Lowest number in List : " + stats.getMin());
System.out.println("Sum of all numbers : " + stats.getSum());
System.out.println("Average of all numbers : " + stats.getAverage());
out:
Highest number in List : 19
Lowest number in List : 1
Sum of all numbers : 85
Average of all numbers : 9.444444444444445
Optional Class
Optional 是一個包含非null對象的容器膘流, Optional 對象用值的缺失來表示null絮缅。
Optional 類有很多實用方法,可以將一個值處理為可用或不可用狀態(tài)呼股,從而不用進行是否為空值的檢查耕魄。類似于Guava中的Optional。
java.util.Optional
定義如下:
public final class Optional<T> extends Object
案例:
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args){
OptionalTest optionalTest = new OptionalTest();
Integer value1 = null;
Integer value2 = new Integer(10);
Optional<Integer> a = Optional.ofNullable(value1);
Optional<Integer> b = Optional.of(value2);
System.out.println(optionalTest.sum(a,b));
}
private Integer sum(Optional<Integer> a, Optional<Integer> b) {
System.out.println("First parameter is present: " + a.isPresent());
System.out.println("Second parameter is present: " + b.isPresent());
Integer value1 = a.orElse(new Integer(0));
Integer value2 = b.get();
return value1 + value2;
}
}
out:
First parameter is present: false
Second parameter is present: true
10
新的 Date/Time API
原有時間API
- 線程不安全
java.util.Date
線程不安全彭谁,新的時間API是不可變的吸奴,且沒有setter方法 - 設(shè)計糟糕
原有時間API起始1900,月份從1開始马靠,日期從0開始奄抽,沒有一致性。新API中提供了很多實用的方法甩鳄。 - 時區(qū)處理復(fù)雜
java.time
- Local 簡化的 date-time API
- Zoned 專門處理多時區(qū)的 date-time API
LocalDateTime
逞度、LocalDate
、LocalTime
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
System.out.println(localDateTime.getDayOfMonth());
LocalDate localDate = localDateTime.toLocalDate().withMonth(2);
System.out.println(localDate);
LocalDate date = LocalDate.of(1978, Month.SEPTEMBER, 21);
System.out.println(date);
LocalTime time = LocalTime.of(22, 15);
System.out.println(time);
LocalTime time2 = LocalTime.parse("20:15:30");
更多內(nèi)容詳見 [更多內(nèi)容詳見 Java8 Tutorial 妙啃。