一、Lambda表達式
1、基本語法
(parameters) -> expression
(parameters) -> { statements; }
ThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
// Lambda表達式取代匿名函數(shù)
executor.execute(() -> {
System.out.println("線程執(zhí)行事務(wù)");
});
executor.execute(() -> System.out.println("線程執(zhí)行事務(wù)"));
2、函數(shù)式接口
在接受函數(shù)式接口的地方才可以使用Lambda表達式。Java8自帶一些常用的函數(shù)式接口,在java.util.function包中:
// Predicate接口定義一個test的抽象方法,接受泛型T對象,并返回一個boolean
Predicate<String> predicate = (str) -> str.contains("a");
System.out.println(predicate.test("abc"));
// Consumer接口定義一個accept的抽象方法,接受泛型T對象,沒有返回值
Consumer<String> consumer = (str) -> System.out.println(str);
consumer.accept("abc");
// Function接口定義一個apply的抽象方法,接受泛型T對象,返回泛型R對象
Function<String, String> function = (str) -> str.toUpperCase();
System.out.println(function.apply("abc"));
// Supplier接口定義一個get的抽象方法,沒有參數(shù),返回泛型R對象
Supplier<String> supplier = () -> "abc";
System.out.println(supplier.get());
// 另外,還專門提供給原始類型的接口,避免自動裝箱,如:IntPredicate、IntConsumer、IntFunction、IntSupplier
// 接受兩個參數(shù)的接口,如:BiPredicate、BiConsumer、BiFunction
有需要三個參數(shù)以上的接口,可以自行定義新的函數(shù)式接口:
public interface MyFunction<T, U, V, R> {
R apply(T t, U u, V v);
}
// 使用自行定義的函數(shù)式接口
MyFunction<String, String, String, String> myFunction = (str1, str2, str3) -> str1 + str2 + str3;
System.out.println(myFunction.apply("a", "b", "c"));
3、方法引用
// 相當于 (String str) -> str.toUpperCase()
String::toUpperCase
// 相當于 (User user) -> user.getName()
User::getName
4、環(huán)繞執(zhí)行模式的例子
public class JedisClient {
public String set(String key, String value) {
return getClientAndAutoClose((jedis) -> {
return jedis.set(key, value);
});
}
public String get(String key) {
return getClientAndAutoClose((jedis) -> {
return jedis.get(key);
});
}
// 統(tǒng)一進行資源關(guān)閉
private <T> T getClientAndAutoClose(Function<Jedis, T> function) {
Jedis jedis = RedisManager.getJedisPool().getResource();
try {
return function.apply(jedis);
}finally {
if (jedis != null) {
jedis.close();
}
}
}
}
二、stream流
List<String> list = Lists.newArrayList("abc", "efg", "cba", "wa", "ba");
list.stream()
.filter(s -> s.contains("a"))
.map(String::toUpperCase)
.limit(3)
.sorted()
.forEach(System.out::println);
1、中間操作
中間操作形成一條流水線,此時還不會執(zhí)行任何處理。類似builder模式。
filter:篩選出滿足條件的數(shù)據(jù)。
distinct:去重,根據(jù)對象的hashCode和equals方法。
limit:截取指定數(shù)量的數(shù)據(jù)。
skip:忽略前面n個數(shù)據(jù)。
map:對數(shù)據(jù)做映射,例如使用User::getName,從user對象轉(zhuǎn)成name。
2、終端操作
終端操作會觸發(fā)執(zhí)行流水線,并能生成結(jié)果。
forEach:對流中每個數(shù)據(jù)遍歷進行處理。
collect:收集,把流轉(zhuǎn)成一個對應(yīng)的輸出,如集合:collect(Collectors.toList())。
count:統(tǒng)計流中數(shù)據(jù)的個數(shù)。
allMatch、anyMatch、noneMatch:匹配Lambda條件,返回boolean。
findAny、findFirst:查找滿足條件的數(shù)據(jù),返回Optional。
reduce:規(guī)約,reduce接受兩個參數(shù):一個是初始值,一個是BinaryOperator<T>來將兩個數(shù)據(jù)合成一個,如累計:reduce(0, (a, b) -> a + b)。
3、Collectors靜態(tài)方法
Collectors提供了很多靜態(tài)方法,可在stream().collect中使用。
List<String> list = Lists.newArrayList("abc", "efg", "cba", "wa", "ba");
// 將流的數(shù)據(jù)收集到list
List<String> list1 = list.stream().collect(Collectors.toList());
// 將流的數(shù)據(jù)收集到set,刪除重復項
Set<String> set = list.stream().collect(Collectors.toSet());
// 將流的數(shù)據(jù)進行分組,可以按對象某個屬性,此處用String的對象本身
Map<String, List<String>> group = list.stream().collect(Collectors.groupingBy(Function.identity()));
// 將流的數(shù)據(jù)收集到map,key為toString生成的字符串,value為對象本身,遇到重復的key則取第一個值
Map<String, String> map = list.stream().collect(Collectors.toMap(String::toString, Function.identity(), (v1, v2) -> v1));
// 分隔符連接對象的toString生成的字符串
String join = list.stream().collect(Collectors.joining(","));
// 統(tǒng)計流的數(shù)據(jù)個數(shù)
Long count = list.stream().collect(Collectors.counting());
// 統(tǒng)計流的數(shù)據(jù)某個整數(shù)屬性的總和
Integer summing = list.stream().collect(Collectors.summingInt(String::length));
三、其他類庫的更新
1、Optional
// 可以為不存在的對象提供默認值
User user = null;
Optional<User> userOpt = Optional.ofNullable(user);
User user2 = userOpt.orElse(new User(0, "DEFAULT"));
System.out.println(user2.getName());
// 通過方法提供默認值
User user3 = userOpt.orElseGet(() -> new User(0, "DEFAULT"));
System.out.println(user3.getName());
2、CompletableFuture
// 異步執(zhí)行api,使用默認線程池ForkJoinPool,不推薦
CompletableFuture.runAsync(() -> {
});
// 推薦使用自定義線程池,隔離資源,按需分配線程數(shù)
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
ThreadPoolConfig.corePoolSize,
ThreadPoolConfig.maximumPoolSize,
ThreadPoolConfig.keepAliveTime,
TimeUnit.MILLISECONDS,
new LinkedBlockingDeque<>(ThreadPoolConfig.queueSize),
new ThreadPoolExecutor.DiscardOldestPolicy()
);
CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> { }, threadPoolExecutor);
3、新的日期和時間API
// 獲取當前日期
LocalDate now = LocalDate.now();
// 獲取昨天的日期
LocalDate yestday = now.minusDays(1);
// 日期轉(zhuǎn)換
LocalDate date = LocalDate.parse("2024-01-01", DateTimeFormatter.ISO_DATE);
// 獲取當前時間
LocalTime localTime = LocalTime.now();
// 時間轉(zhuǎn)換
LocalTime time = LocalTime.parse("12:00:00", DateTimeFormatter.ISO_TIME);
// 獲取當前日期時間
LocalDateTime localDateTime = LocalDateTime.now();
// 獲取昨天的日期時間
LocalDateTime beforeDatetime = localDateTime.minusDays(1);
// 便于機器使用的日期和時間
Instant instant = Instant.now();
// 時間間隔
Duration duration = Duration.between(beforeDatetime, localDateTime);
System.out.println(duration.getSeconds() + "秒");
// 日期間隔
Period period = Period.between(yestday, now);
System.out.println(period.getDays() + "天");
4、集合
Map<String, Integer> map = new HashMap<>();
// 獲取時指定默認值
Integer value = map.getOrDefault("a", 0);
// 若map中不存在鍵"a",則添加鍵值對("a", 1)
map.putIfAbsent("a", 1);
// 若map中不存在鍵"b",則添加鍵值對("b", 2)
map.computeIfAbsent("b", v -> 2);
// 若map中存在鍵"b",則將其對應(yīng)的值加1
map.computeIfPresent("b", (k, v) -> v + 1);
System.out.println(map);
List<String> list = Lists.newArrayList("abc", "bcd", "cde");
// 所有元素替換
list.replaceAll(String::toUpperCase);
// 根據(jù)Lambda條件刪除元素
list.removeIf(s -> s.contains("B"));
System.out.println(list);
5、并發(fā)
// 部分上鎖,線程安全
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
AtomicInteger atomicInteger = new AtomicInteger(0);
// 更新,返回更新前的值
int before = atomicInteger.getAndUpdate(i -> i + 1);
System.out.println(before);
// 更新,返回更新后的值
int after = atomicInteger.updateAndGet(i -> i + 1);
System.out.println(after);
// 更新,取最大值,返回更新前的值
int before2 = atomicInteger.getAndAccumulate(10, Integer::max);
System.out.println(before2);
// 更新,取最大值,返回更新后的值
int after2 = atomicInteger.accumulateAndGet(20, Integer::max);
System.out.println(after2);
// 支持多線程中累加
LongAdder longAdder = new LongAdder();
longAdder.add(1);
longAdder.add(2);
long sum = longAdder.sum();
System.out.println(sum);