Java8常用特性小结

Java16已经横空出世了,大家现在用的哪一版呢?不出所料,大多数都还在用Java8。

Oracle JDK 开始对 Java SE 8(8u201/202) 之后的版本进行商用收费,也就是说后续版本的JDK不再开源了,所以开源社区紧跟着推出了OpenJDK,MariaDB(主要是担心Oracle把Mysql也闭源了)等替代备选方案。

一是JDK可能要面临闭源,二是基于Java8的J2EE服务太庞大了,更换JDK不单单是要承受巨大的业务代码脱胎换骨般重构升级成本,还要承担JDK升级不可预知的安全稳定性风险。

最新的未必就是最好的最实用的!这也就是Java8持续盛行至今的一些原因吧。

既然大家都还在用Java8,那就简单说说Java8的一些常用特性。

1. Lambda表达式

JDK8之前繁琐的匿名内部类,现在可以通过Lambda表达式(也称闭包)简洁高效地编码实现,也称函数式编程。

orderDetails.forEach(orderDetail -> orderDetail.setOrderId(order.getId()));

上面示例的代码可以显示指定参数类型,如果Lambda表达式的函数体超过一行代码,可以加上花括号,如下:

orderDetails.forEach((OrderDetail orderDetail) -> {
    orderDetail.setOrderId(order.getId());
    orderDetail.setCreateTime(order.getCreateTime());
});

Lambda表达式,现在前后端开发基本都在用,前端有的叫箭头函数。

2. 函数式接口

带有 @FunctionalInterface 注解的接口类为函数式接口,仅起标记的作用,

可以隐式转换为Lambda表达式。

函数式接口:只有一个普通函数的接口(默认方法及静态方法除外)。

具有代表性的函数式接口有:

java.util.function.Function    // 函数方法 

java.util.function.Consumer  // 消费者

java.util.function.Supplier     // 提供者

java.util.function.Predicate   // 断言判断

应用示例:

public static <D extends Domain> Map<Integer, D> listToMap(List<D> resources){
    if(CollectionUtils.isNotEmpty(resources)){
        return resources.stream().collect(
                Collectors.toMap(D::getId, Function.identity(), (key1, key2) -> key2));
    }
    return Collections.emptyMap();
}
Function.identity() // 返回对象本身

  (key1, key2) -> key2 // 表示当map的key重复时,value取最新值,即覆盖处理

3. 接口默认方法及静态方法

JDK8中对接口的功能做了扩展,以往只支持定义抽象方法,现在可以定义default修饰的默认方法及static修饰的静态方法,下面各自举例说明一下。

默认方法

默认方法的功能可以被子类直接继承使用,如果不能满足子类功能,子类可以覆写默认方法。

public interface BaseRepository<S extends Domain> extends JpaSpecificationExecutor<S>,   JpaRepository<S, Integer> {

    default Specification<S> getSpecification(S example) {
        return (root, criteriaQuery, criteriaBuilder) -> {
            Path<Integer> id = root.get("id");
            Path<Date> createTime = root.get("createTime");
            Path<Byte> delFlag = root.get("delFlag");

            List<Predicate> predicateList = new ArrayList<>();

            if (example.getId() != null && example.getId() > 0) {
                predicateList.add(criteriaBuilder.equal(id, example.getId()));
            }
            if (example.getDelFlag() != null) {
                predicateList.add(criteriaBuilder.equal(delFlag,   example.getDelFlag()));
            }
            if (StringUtils.isNotEmpty(example.getFromDate())) {
                predicateList.add(criteriaBuilder.greaterThanOrEqualTo(createTime, DateUtil.parseYMDHMS(example.getFromDate() + " 00:00:00")));
            }
            if (StringUtils.isNotEmpty(example.getToDate())) {
                predicateList.add(criteriaBuilder.lessThanOrEqualTo(createTime, DateUtil.parseYMDHMS(example.getToDate() + " 23:59:59")));
            }

            return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));
        };
    }

}

静态方法:

子类可以直接调用,不能覆写

@FunctionalInterface
public interface Function<T, R> {
        static <T> Function<T, T> identity() { return t -> t; }
}

4. 方法引用

HashMap<Integer, Set<Integer>> userActionMap = userActionList.stream().collect(
        Collectors.groupingBy(UserAction::getBizId, HashMap::new,   Collectors.mapping(UserAction::getUserId, Collectors.toSet())))

UserAction::getBizId  // 成员方法引用

HashMap::new // 无参构造器引用,分组后用HashMap作为数据结果收集器

Collectors.groupingBy // 分组聚合,如本例的按userAction.bizId字段分组

Collectors.mapping // 分组数据的value值映射处理,如本例取userAction.userId,存放到set集合

分组排序应用示例:

public static Map<String, Long> tokenize(String content){
    if(StringUtils.isNotEmpty(content)){
        List<String> tokens = process(content);

        Map<String, Long> items = tokens.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        return items.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new));
    }

    return Collections.emptyMap();
}

5. Stream 流式操作

List<List<User>> userList = getUserByGroup();

Predicate<User> predicate = user -> StringUtils.isNotEmpty(user.getUserName());

userList.stream().filter(predicate)
.flatMap(Collection::stream).collect(Collectors.toList())

一些常用API说明:

  • filter:过滤
  • map:将函数转为其他流或提取信息
  • mapToInt:提取值,并转为int类型;如:userList.mapToLong(User::getScore).sum();
  • flatMap:返回一个stream,flatMap将流中的当前元素替换为此返回流拆解的流元素,如本例将List<List<User>> 双重集合拆分成扁平化流,流元素即为User对象
  • distinct:去重复
  • sorted:排序
  • limit:取前几个;userList.stream().limit(10).collect(Collectors.toList());
  • skip:跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。如:userList.stream().skip(10).collect(Collectors.toList());
  • collect:接口中的方法,定义了如何对流结果进行操作:如:.collect(Collectors.toList())
  • anyMatch:检查至少一个匹配(返回类型boolean)
  • noneMatch:检查是否没有匹配的元素
  • findFirst:返回第一个结果(返回类型:Optional)
  • findAny:返回任意个结果

 组合排序问题:

ComparaUser> comparator =
        Comparator.comparing(User::getScore, Comparator.nullsLast(Double::compareTo))
        .thenComparing(User::getUpdateTime, Comparator.nullsLast(Date::compareTo))
        .thenComparing(User::getId).reversed();

Comparator.nullsLast 即空值元素排最后,reversed()表示逆序排列。

以上排序规则为:先按用户积分倒序,积分相同的,按用户更新时间倒序,更新时间也相同的,再按用户ID倒序。

上述例子中,reversed()方法是作用于全字段的,即score,updateTime,id 都倒序,如果在score或updateTime排序后再加上reversed()方法则为按score或updateTime升序排列(类似于负负得正)

未完待续。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值