一、Lambda表达式
1、基本语法
(parameters) -> expression
(parameters) -> { statements; }
ThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
// Lambda表达式取代匿名函数
executor.execute(() -> {
System.out.println("线程执行事务");
});
executor.execute(() -> System.out.println("线程执行事务"));
2、函数式接口
在接受函数式接口的地方才可以使用Lambda表达式。Java8自带一些常用的函数式接口,在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的抽象方法,没有参数,返回泛型R对象
Supplier<String> supplier = () -> "abc";
System.out.println(supplier.get());
// 另外,还专门提供给原始类型的接口,避免自动装箱,如:IntPredicate、IntConsumer、IntFunction、IntSupplier
// 接受两个参数的接口,如:BiPredicate、BiConsumer、BiFunction
有需要三个参数以上的接口,可以自行定义新的函数式接口:
public interface MyFunction<T, U, V, R> {
R apply(T t, U u, V v);
}
// 使用自行定义的函数式接口
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、环绕执行模式的例子
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);
});
}
// 统一进行资源关闭
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、中间操作
中间操作形成一条流水线,此时还不会执行任何处理。类似builder模式。
filter:筛选出满足条件的数据。
distinct:去重,根据对象的hashCode和equals方法。
limit:截取指定数量的数据。
skip:忽略前面n个数据。
map:对数据做映射,例如使用User::getName,从user对象转成name。
2、终端操作
终端操作会触发执行流水线,并能生成结果。
forEach:对流中每个数据遍历进行处理。
collect:收集,把流转成一个对应的输出,如集合:collect(Collectors.toList())。
count:统计流中数据的个数。
allMatch、anyMatch、noneMatch:匹配Lambda条件,返回boolean。
findAny、findFirst:查找满足条件的数据,返回Optional。
reduce:规约,reduce接受两个参数:一个是初始值,一个是BinaryOperator<T>来将两个数据合成一个,如累计:reduce(0, (a, b) -> a + b)。
3、Collectors静态方法
Collectors提供了很多静态方法,可在stream().collect中使用。
List<String> list = Lists.newArrayList("abc", "efg", "cba", "wa", "ba");
// 将流的数据收集到list
List<String> list1 = list.stream().collect(Collectors.toList());
// 将流的数据收集到set,删除重复项
Set<String> set = list.stream().collect(Collectors.toSet());
// 将流的数据进行分组,可以按对象某个属性,此处用String的对象本身
Map<String, List<String>> group = list.stream().collect(Collectors.groupingBy(Function.identity()));
// 将流的数据收集到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(","));
// 统计流的数据个数
Long count = list.stream().collect(Collectors.counting());
// 统计流的数据某个整数属性的总和
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
// 异步执行api,使用默认线程池ForkJoinPool,不推荐
CompletableFuture.runAsync(() -> {
});
// 推荐使用自定义线程池,隔离资源,按需分配线程数
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);
// 日期转换
LocalDate date = LocalDate.parse("2024-01-01", DateTimeFormatter.ISO_DATE);
// 获取当前时间
LocalTime localTime = LocalTime.now();
// 时间转换
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",则将其对应的值加1
map.computeIfPresent("b", (k, v) -> v + 1);
System.out.println(map);
List<String> list = Lists.newArrayList("abc", "bcd", "cde");
// 所有元素替换
list.replaceAll(String::toUpperCase);
// 根据Lambda条件删除元素
list.removeIf(s -> s.contains("B"));
System.out.println(list);
5、并发
// 部分上锁,线程安全
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);