Java8新特性

一、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);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • JAVA8新特性 速度更快 Lambda表達式 Stream API 便于并行 最大化的減少空指針異常 速度更快 ...
    Levi_wen閱讀 208評論 0 0
  • 目錄結(jié)構(gòu) 介紹 Java語言的新特性2.1 Lambdas表達式與Functional接口2.2 接口的默認與靜態(tài)...
    夜風月圓閱讀 576評論 0 2
  • Java 8自Java 5(發(fā)行于2004)以來最具革命性的版本。Java 8 為Java語言、編譯器、類庫、開發(fā)...
    huoyl0410閱讀 724評論 1 2
  • 2019年9月19日java13已正式發(fā)布,感嘆java社區(qū)強大,經(jīng)久不衰。由于國內(nèi)偏保守,新東西總要放一放,讓其...
    CodingAndLiving閱讀 910評論 0 1
  • 為什么使用 Lambda 表達式 Lambda 是一個匿名函數(shù),我們可以把 Lambda 表達式理解為是一段可以傳...
    強某某閱讀 15,036評論 0 15

友情鏈接更多精彩內(nèi)容