Lambda 是一個匿名函數,我們可以把 Lambda 表達式理解爲是一段可以傳遞的程式碼(將程式碼像數據一樣進行傳遞)
使用它可以寫出更簡潔、更靈活的程式碼。作爲一種更緊湊的程式碼風格,使Java的語言表達能力得到了提升
Lambda表達式的本質是:作爲函數式介面的範例
//匯入的包有;import org.junit.Test;import java.util.Comparator;
public class LambdaTest1 {
@Test
public void test1(){
Runnable r1 = new Runnable(){
@Override
public void run() {
System.out.println("我愛北京天安門");
}
};
r1.run();
//Lambad表達式寫法
Runnable r2 = () -> System.out.println("我愛北京天安門");
r2.run();
}
@Test
public void test2(){
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int compare1 = com1.compare(12,21);
System.out.println(compare1);
//Lambda表達式
Comparator<Integer> com2 = (o1,o2) ->Integer.compare(o1,o2);
int compare2 = com2.compare(12,21);
System.out.println(compare2);
//方法參照
Comparator<Integer> com3 = Integer :: compare;
int compare3 = com3.compare(12,21);
System.out.println(compare3);
}
}
舉例:(o1,o2) -> Integer.compare(o1,o2)
格式:
語法格式:
語法格式一:無參,無返回值
語法格式二:Lambda需要一個參數,但是沒有返回值
語法格式三:數據型別可以省略,因爲可由編譯器推斷得出,稱爲「型別推斷」
語法格式四:Lambda若只需要一個參數時,參數的小括號可以省略
語法格式五:Lambda需要兩個或以上的參數,多條執行語句,並且可以有返回值
語法格式六:當Lambda體只有一條語句時,return與大括號若有,都可以省略
總的來說,語法格式爲:
//匯入的包有:import org.junit.Test;import java.util.Comparator;import java.util.function.Consumer;
public class LambdaTest2 {
@Test
public void test1(){
//語法格式一:無參,無返回值
Runnable r1 = new Runnable(){
@Override
public void run() {
System.out.println("我愛北京天安門");
}
};
r1.run();
System.out.println("***************************");
//Lambad表達式寫法
Runnable r2 = () -> {
System.out.println("我愛北京天安門");
};
r2.run();
}
@Test
public void test2(){
//語法格式二:Lambda需要一個參數,但是沒有返回值
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("今天是個好日子");
System.out.println("***************************");
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
con1.accept("今天是個好日子");
}
@Test
public void test3(){
//語法格式三:數據型別可以省略,因爲可由編譯器推斷得出,稱爲「型別推斷」
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
con1.accept("今天是個好日子");
System.out.println("***************************");
Consumer<String> con2 = (s) -> {
System.out.println(s);
};
con2.accept("今天是個好日子");
}
@Test
public void test4(){
//語法格式四:Lambda若只需要一個參數時,參數的小括號可以省略
Consumer<String> con1 = (s) -> {
System.out.println(s);
};
con1.accept("今天是個好日子");
System.out.println("***************************");
Consumer<String> con2 = s -> {
System.out.println(s);
};
con2.accept("今天是個好日子");
}
@Test
public void test5(){
//語法格式五:Lambda需要兩個或以上的參數,多條執行語句,並且可以有返回值
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
};
System.out.println("*******************");
Comparator<Integer> com2 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
}
@Test
public void test6(){
//語法格式六:當Lambda體只有一條語句時,return與大括號若有,都可以省略
Comparator<Integer> com1 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println("*******************");
Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);
}
}
使用情景:當要傳遞給Lambda體的操作,已經有實現的方法了,可以使用方法參照
方法參照本質:其本質爲Lambda表達式,而Lambda表達式是爲函數式介面的範例,所以方法參照,也是函數式介面的範例
使用格式:類(物件) :: 方法名
具體使用情況:
物件 :: 非靜態方法(實體方法)
類 :: 靜態方法
類 :: 非靜態方法
使用要求:要求介面中抽象方法的形參列表和返回值型別,與方法參照的方法的形參列表和返回值型別相同,但當類呼叫非靜態方法時,可以不相同
構造器參照
和方法參照類似,函數式介面的抽象方法的形參列表和構造器的形參列表一致。抽象方法的返回值型別即爲構造器所屬類的型別
陣列參照
可以把陣列看做是一個特殊的類,則寫法與構造器參照一致
什麼是Stream API
Stream的操作步驟
注意事項
Stream的範例化有四種方式:
//匯入的包有:import org.junit.Test;import java.util.Arrays;import java.util.List;import java.util.stream.IntStream;import java.util.stream.Stream;
public class StreamTest {
//建立Stream方式一:通過集合
@Test
public void test1(){
//先建立一個集合
List<Employee> employees = EmployeeData.getEmployees();
//default Stream<E> stream() : 返回一個順序流
Stream<Employee> stream = employees.stream();
//default Stream<E> parallelStream() : 返回一個並行流
Stream<Employee> parallelStream = employees.parallelStream();
}
//建立Stream方式二:通過陣列
@Test
public void test2(){
int[] arr = new int[]{1,2,3,4,5,6};
//呼叫Array類的static <T> Stream<T> stream(T[] array): 返回一個流
IntStream stream = Arrays.stream(arr);
Employee e1 = new Employee(1001,"Tom");
Employee e2 = new Employee(1002,"Jerry");
Employee[] arr1 = new Employee[]{e1,e2};
//常見的陣列可以,自定義的陣列arr1也行
Stream<Employee> stream1 = Arrays.stream(arr1);
}
//建立Stream方式三:通過Stream的of()
@Test
public void test3(){
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
}
}
篩選與切片
//篩選與切片
@Test
public void test1(){
List<Employee> list = EmployeeData.getEmployees();
//filter(Predicate p):接收Lambda,從流中排除某些元素
Stream<Employee> stream = list.stream();
//查詢員工表中薪資大於7000的員工資訊
stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);
//limit(n):截斷流,使其元素不超過給定數量
list.stream().limit(3).forEach(System.out::println);
//skip(n):跳過元素,返回一個扔掉了前n個元素的流,若流中元素不足n個,則返回一個空流
list.stream().skip(3).forEach(System.out::println);
//distinct():篩選,通過流所生成元素的hashCode()和equals()去除重複元素
list.stream().distinct().forEach(System.out::println);
}
對映
//對映
@Test
public void test2(){
//接收一個函數作爲參數,該函數會被應用到每個元素上,並將其對映成一個新的元素
List<String> list = Arrays.asList("aa","bb","cc","dd");
list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
}
排序
//排序
@Test
public void test3(){
//sorted():自然排序
List<Integer> list = Arrays.asList(12,45,-8,2,56,34);
list.stream().sorted().forEach(System.out::println);
//使用自然排序的條件是:所指定泛型要實現Comparable介面
//sorted(Comparator com):定製排序
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted((e1,e2) -> Integer.compare(e1.getAge(),e2.getAge()))
.forEach(System.out::println);
}
匹配與查詢
//匹配與查詢
@Test
public void test1(){
List<Employee> employees = EmployeeData.getEmployees();
//allMatch(Predicate p):檢查是否匹配所有元素:所有員工年齡是否大於18
boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
System.out.println(allMatch);
//anyMatch(Predicate p):檢查是否至少匹配一個元素:是否存在員工工資大於1000
boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 1000);
System.out.println(anyMatch);
//noneMatch(Predicate p):檢查是否沒有匹配所有元素:是否存在員工姓「雷」
boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));
System.out.println(noneMatch);
//findFirst():返回第一個元素
Optional<Employee> employee = employees.stream().findFirst();
System.out.println(employee);
//findAny():返回當前流中的任意元素
Optional<Employee> employee1 = employees.stream().findAny();
System.out.println(employee1);
//count():返迴流中元素總個數
long count = employees.stream().count();
System.out.println(count);
//max(Comparator c):返迴流中最大值:返回最高的工資
Optional<Double> maxSalary = employees.stream().map(e -> e.getSalary()).max(Double::compare);
System.out.println(maxSalary);
//min(Comparator c):返迴流中最小值:返回最低的工資
Optional<Employee> minSalary = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(minSalary);
//forEach(Consumer c):內部迭代
// 使用 Collection 介面需要使用者去做迭代,稱爲外部迭代
// 相反,Stream API 使用內部迭代——它幫你把迭代做了
employees.stream().forEach(System.out::println);
}
歸約
//規約
@Test
public void test2(){
//reduce(T iden, BinaryOperator b) 可以將流中元素反覆 反復結合起來,得到一個值。返回 T
//練習:計算1-10的自然數的和
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream().reduce(0, Integer::sum);
System.out.println(sum);
//reduce(BinaryOperator b) 可以將流中元素反覆 反復結合起來,得到一個值。返回 Optional<T>
//練習:計算公司所有員工工資的總和
List<Employee> employees = EmployeeData.getEmployees();
Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
Optional<Double> sumMoney = salaryStream.reduce((d1, d2) -> d1 + d2);
System.out.println(sumMoney);
}
收集
//收集
@Test
public void test3(){
//collect(Collector c)將流轉換爲其他形式。接收一個 Collector介面的實現,用於給Stream中元素做彙總的方法
//練習:查詢工資大於6000的員工,結果返回爲一個List或Set
//結果返回爲一個List
List<Employee> employees = EmployeeData.getEmployees();
List<Employee> list = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
list.forEach(System.out::println);
//結果返回爲一個Set
Set<Employee> set = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
list.forEach(System.out::println);
}
Optional< T > 類(java.util.Optional) 是一個容器類,它可以儲存型別T的值,代表這個值存在。或者僅僅儲存null,表示這個值不存在。
原來用 null 表示一個值不存在,現在 Optional 可以更好的表達這個概念。並且可以避免空指針異常
Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測:
舉例說明Optional類: