1、Lambda
Lambda 表達式是 Java 8 引入的一種新特性,允許你以更加簡潔的方式編寫匿名函數,從而使代碼更簡潔和易讀。Lambda 表達式的語法格式如下:
(parameters) -> expression
(parameters) -> { statements; }
1.1、基本語法
-
無參數
() -> System.out.println("Hello, World!"); - 一個參數,無需括號
x -> x * x - 多個參數,需要括號
(a, b) -> a + b - 帶類型的多個參數
(int a, int b) -> a + b -
多行語句,需要大括號
(int a, int b) -> { int sum = a + b; return sum; }
1.2、使用示例
- 使用 Lambda 表達式代替匿名類
傳統的匿名內部類:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello, World!");
}
}).start();
使用 Lambda 表達式:
new Thread(() -> System.out.println("Hello, World!")).start();
- 使用 Lambda 表達式進行集合操作
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));
- 使用 Lambda 表達式進行排序
傳統方式:
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
使用 Lambda 表達式:
Collections.sort(names, (a, b) -> a.compareTo(b));
2、與函數式接口結合
Lambda 表達式通常與函數式接口結合使用。函數式接口是僅包含一個抽象方法的接口,可以使用 @FunctionalInterface 註解來標識。例如:
@FunctionalInterface
interface MyFunctionalInterface {
void doSomething();
}
public class LambdaExample {
public static void main(String[] args) {
MyFunctionalInterface func = () -> System.out.println("Doing something");
func.doSomething();
}
}
public static int sum(int num1, int num2, Accumulator accumulator) {
return accumulator.add(num1, num2);
}
@FunctionalInterface
public interface Accumulator {
int add(int o1, int o2);
}
public static void main(String[] args) {
Runnable runnable = () -> System.out.println("hello world");
new Thread(runnable).start();
List<Integer> nums = Arrays.asList(1, 2, 3);
List<Integer> doubleNums = nums.stream().map(x -> x * x).collect(Collectors.toList());
int result = sum(1,2, (a, b) -> a + b);
System.out.println(result);
}
3、常見的函數式接口
java 8 提供了一些常見的函數式接口,可以直接用於 Lambda 表達式:
- Consumer<T>:接受一個輸入參數並且不返回結果的操作
Consumer<String> printer = s -> System.out.println(s);
printer.accept("Hello");
- Supplier<T>:無輸入參數但返回一個結果的操作
Supplier<String> supplier = () -> "Hello";
System.out.println(supplier.get());
- Function<T, R>:接受一個輸入參數並返回一個結果的操作
Function<Integer, String> intToString = i -> "Number: " + i;
System.out.println(intToString.apply(5));
- Predicate<T>:接受一個輸入參數並返回一個布爾值的操作
Predicate<String> isEmpty = s -> s.isEmpty();
System.out.println(isEmpty.test("Hello")); // false
4、變量作用域
Lambda 表達式可以使用外部的局部變量,但這些變量必須是最終的或實際上的最終變量(即在 Lambda 表達式中不能修改這些變量)
String greeting = "Hello";
Consumer<String> greeter = name -> System.out.println(greeting + ", " + name);
greeter.accept("World");
// greeting = "Hi"; // 編譯錯誤
5、新的日期和時間 API
java 8 引入了全新的日期和時間 API (java.time 包),提供了更好用和更靈活的日期和時間處理方法
LocalDate today = LocalDate.now();
System.out.println("today :" + today.toString());
LocalDate date = LocalDate.of(1989, Month.MARCH, 23);
System.out.println("date : " + date.toString());
LocalDateTime dateTime = LocalDateTime.now();
System.out.println("dateTime : " + dateTime);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatDateTime = dateTime.format(formatter);
System.out.println("formatDateTime : " + formatDateTime);
輸出 :
today :2024-07-09
date : 1989-03-23
dateTime : 2024-07-09T10:03:56.416
formatDateTime : 2024-07-09 10:03:56
6、Stream API使用
數據模擬
List<Person> peoples = Arrays.asList(
new Person("Alice", 30, "New York1"),
new Person("Alice", 31, "New York2"),
new Person("Bob", 20, "San Francisco"),
new Person("Charlie", 25, "Los Angeles"),
new Person("David", 15, "Chicago"),
new Person("Eve", 35, "Boston")
);
6.1、過濾年齡大於30的姓名,同時大寫轉換為List
List<String> result = peoples.stream()
.filter(person -> person.getAge() >= 30)
.map(Person::getName)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
result.forEach(System.out::println);
6.2、分組
Map<String, List<Person>> namePersons = peoples.stream()
.collect(Collectors.groupingBy(Person::getName));
namePersons.forEach((name, persons) -> {
System.out.println(name + ":" + persons);
});
6.3、List轉換為Map
無name重複的場景
Map<String, Person> personMap = peoples.stream()
.collect(Collectors.toMap(Person::getName, person -> person));
System.out.println(personMap);
有name重複的場景,處理鍵衝突(例如 : 使用相同的鍵合併值)
Map<String, Person> nameToPersonMapWithMerge = peoples.stream()
.collect(Collectors.toMap(
Person::getName,
person -> person,
(existing, replacement) -> replacement
));
nameToPersonMapWithMerge.forEach((name, person) -> {
System.out.println(name + ":" + person);
});
7、Optional
Optional 類是 Java 8 引入的一個重要特性,用於處理可能為空(null)的值。它通過顯式地表示值可能存在或不存在,從而減少了 NullPointerException 的風險,並使代碼更加易讀和易維護
Optional<Address> address = Optional.ofNullable(new Address("New York", "5th Avenue"));
Person person = new Person("John", address);
// 使用 map 和 flatMap 獲取嵌套值
Optional<String> city = person.getAddress()
.map(Address::getCity);
city.ifPresent(System.out::println); // 輸出:New York
// 使用 orElse 提供默認值
String street = person.getAddress()
.map(Address::getStreet)
.orElse("Unknown Street");
System.out.println(street); // 輸出:5th Avenue
// 使用 orElseThrow 拋出異常
String cityName = person.getAddress()
.map(Address::getCity)
.orElseThrow(() -> new IllegalArgumentException("City not found"));
System.out.println(cityName); // 輸出:New York
// 處理空的 Optional
Optional<Address> emptyAddress = Optional.empty();
Person personWithoutAddress = new Person("Jane", emptyAddress);
String cityNameOrDefault = personWithoutAddress.getAddress()
.map(Address::getCity)
.orElse("Default City");
System.out.println(cityNameOrDefault); // 輸出:Default City
8、map computeIfPresent & computeIfAbsent
Map<String, Integer> maps = new HashMap<>();
// 使用 computeIfAbsent 插入值,computeIfAbsent 方法在鍵缺失時進行計算並插入值
maps.computeIfAbsent("Apple", key -> 10);
maps.computeIfAbsent("Banana", key -> 20);
// 使用 computeIfPresent 更新值,computeIfPresent 方法在鍵存在時更新值
maps.computeIfPresent("Apple", (key, value) -> value * 2);
maps.computeIfPresent("Banana", (key, value) -> value + 5);
maps.forEach((key, value) -> System.out.println(key + ":" + value));
9、CompletableFuture
CompletableFuture 是 Java 8 中引入的一個類,用於支持異步編程和併發任務。它不僅實現了 Future 接口,還提供了許多用於任務組合和處理的方法。理解 CompletableFuture 的底層原理有助於更好地使用和優化它
9.1、基本結構
CompletableFuture 通過一系列內部狀態來跟蹤任務的執行狀態。主要的狀態有:
- 未完成 (Incomplete): 任務尚未完成
- 正常完成 (Normal completion): 任務已經成功完成
- 異常完成 (Exceptional completion): 任務因異常而失敗
這些狀態由一個內部的 volatile 變量來管理,該變量確保多線程環境中的可見性和一致性
9.1、任務執行
CompletableFuture 可以通過以下幾種方式執行任務:
- 默認線程池: 默認情況下,CompletableFuture 使用一個由 ForkJoinPool.commonPool() 提供的公共線程池。這個線程池是一個全局的、共享的、併發的線程池,適用於大多數異步任務
- 自定義線程池: 你也可以指定一個自定義的線程池,通過提供一個 Executor 實例來執行任務
示例:使用默認線程池和自定義線程池
如感興趣,點贊加關注,謝謝!!!