JAVA8新特性(上篇)

本文详细介绍了Java8的三大重要特性:Lambda表达式、Collector和Optional。Lambda允许将函数作为基本运算单元,简化了代码;Collector提供了可变的聚合操作,方便数据处理;Optional作为容器对象,有效解决了空指针问题。通过案例展示了这些特性的使用方法和优势。
摘要由CSDN通过智能技术生成

司内小分享, boss让我整理一下JAVA8新特性, 噢噢噢噢!!!还有这好事儿, 正好趁着这个机会好好学习下. 基于我不写笔记学不下去的习惯(分享也要有文档), 就出现了本篇内容. 主要讲使用条件和方式, 原理请自行Google

上篇: Lambda表达式, Collector, Optional
下篇: Stream流, LocalDateTime

说明: 测试中生成box测试数据均为一下方法生成

public static List<Box> generateBoxes() {
    List<Box> boxes = new ArrayList<>();
    boxes.add(new Box().setName("黄色箱子").setColor("yellow").setSize(5));
    boxes.add(new Box().setName("绿色箱子").setColor("green").setSize(8));
    boxes.add(new Box().setName("红色箱子").setColor("red").setSize(2));
    boxes.add(new Box().setName("黑色箱子").setColor("black").setSize(6));
    boxes.add(new Box().setName("紫色箱子").setColor("purple").setSize(10));
    boxes.add(new Box().setName("蓝色箱子").setColor("blue").setSize(1));
    return boxes;
}

一. Lambda表达式

1.1 描述

函数式编程: 允许把函数作为基本运算单元, 可以作为方法的参数,又称闭包.
方法引用: 是指如果某个方法签名和接口恰好一致(只看参数类型和返回类型,不看方法名称,也不看类的继承关系),就可以直接传入方法引用。

1.2 要求
  1. Lambda
    函数式接口: 有且只有一个必须实现方法的接口(由于JAVA8中接口可以有了默认实现, 所以定义了一个 @FunctionalInterface 注解作为函数式接口的标记)
    如:ComparatorRunnable以及四大函数式接口Consumer(返回void)、Function(返回映射泛型)、Predicate(返回boolean)、Supplier(返回定义的泛型)
    Lambda表达式可以直接访问外部域变量, 但只能引用标记了 final 的外层局部变 量,不能lambda 内部修改定义在域外的局部变量.
  2. 方法引用
    如果某个方法签名和接口恰好一致,就可以直接传入方法引用
  3. 四大函数式接口
    简单的讲就是四类函数容器(容器的概念和思想很重要啊)
1.3 格式

Lambda表达式: “->
方法引用: “::

1.4 特征
  1. Lambda:
    可选类型声明: 不需要声明参数类型,编译器可以统一识别参数值。
    可选的参数圆括号: 一个参数无需定义圆括号,但无参数或者多个参数需要定义圆括 号。
    可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
    可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需 要指定表达式返回了一个数值。
  2. 方法引用
    1)在使用lambda表达式时, 如果匿名函数的返回值类型和参数类型都已经确定, 则可以将任何符合要求的方法以方法引用的方式传入
    2)第一不关心方法名; 第二不关心类的继承关系; 第三不关心方法实现
1.5 案例

以数组、集合排序为例

  1. Lambda
private static void lambda() {
    System.out.println("源数据boxes_1:");
    List<Box> boxes = GenerateUtil.generateBoxes();
    System.out.println(boxes);
    System.out.println("java7排序:");
    // 本质是创建匿名内部类
    // 编译时会生成Xxx$n.class
    boxes.sort(new Comparator<Box>() {
        @Override
        public int compare(Box o1, Box o2) {
            return o1.getSize() - o2.getSize();
        }
    });
    System.out.println(boxes);
    System.out.println("=======================================");
    System.out.println("源数据boxes_1");
    List<Box> boxes2 = GenerateUtil.generateBoxes();
    System.out.println(boxes2);
    System.out.println("java8排序:");
    // 本质是匿名函数
    boxes2.sort((box1, box2) -> box1.getSize() - box2.getSize());
    System.out.println(boxes2);
	// 特别的, 可以用来创建函数式接口的实例
    Comparator<Box> comparator = (o1, o2) -> o1.getSize() - o2.getSize();
}
  1. 方法引用
public static int ohMyGod(Integer num1, Integer num2) {
	// 为了与原数字排序方式混淆, 此处使用倒序排序
    return num2 - num1;
}

private static void methodReference() {
    Integer[] numbers = {5, 8, 2, 3, 4, 1, 9, 0};
    Arrays.sort(numbers, LambdaDemo::ohMyGod);
//        Arrays.sort(numbers, Math::max);
    System.out.println(Arrays.toString(numbers));
}

如上: ohMyGod的方法返回值和参数与compare方法一致, 此处就可以使用方法引用, Mathmax方法也符合要求, 也可以使用. 这两个方法名字, 继承和实现关系, 方法实现都不相同, 但不影响使用.

二. CollectorCollectors

2.1 描述

Collector: 可变的聚合操作, 定义一个可变容器, 将新输入的元素添加到可变容器中(可以认为是可变容器的操作容器)
Collectors: 收集器工具类, 定义部分常用收集器

2.2 原理

有三个泛型:
T: 元素类型
A: 可变容器类型
R: 结果容器类型
有五个方法:
Supplier: 创建新的结果容器
Accumulator: 合并元素到结果容器中
Combiner: 合并两个结果容器
Finisher: 将结果容器转为最终表示
Characteristics: 给collector设置特征值

工作原理即使用Collector中定义的方法对内容进行可达到目的性的操作

2.3 特征

有三个特征值:
CONCURRENT: 表示结果容器只有一个
UNORDERED: 表示流中的元素无序
IDENTITY_FINISH: 表示中间结果容器类型与最终结果类型一致

2.4 案例

Collector

  1. 自定义一个实现
public class MyCollector<T> implements Collector<T, List<T>, List<T>> {
	// 创建一个新容器
    @Override
    public Supplier<List<T>> supplier() {
        System.out.println("supplier execute");
        return ArrayList::new;
    }
	// 向容器中添加元素
    @Override
    public BiConsumer<List<T>, T> accumulator() {
        System.out.println("accumulator execute");
        return List::add;
    }
	// 容器合并
    @Override
    public BinaryOperator<List<T>> combiner() {
        System.out.println("combiner execute");
        return (container1, container2) -> {
            container1.addAll(container2);
            return container1;
        };
    }
	// 结果容器
    @Override
    public Function<List<T>, List<T>> finisher() {
        System.out.println("finisher execute");
        return (result) -> result;
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.unmodifiableSet(EnumSet
                .of(Collector.Characteristics.IDENTITY_FINISH));
    }
}
  1. 自定义一个操作
public static <T, A, R> R operate(T[] ts1, A ts2, Collector<T, A, R> collector) {
    // 获取一个新容器
    A a = collector.supplier().get();
    BiConsumer<A, T> accumulator = collector.accumulator();
    // 向新容器中添加元素
    for (T t : ts1) {
    	// 遇到c时便不再继续添加
        if ("c".equals(t)) {
            break;
        }
        accumulator.accept(a, t);
    }
    BinaryOperator<A> combiner = collector.combiner();
    // 合并容器操作
    A apply = combiner.apply(a, ts2);
    Function<A, R> finisher = collector.finisher();
    // 容器转为结果操作
    return finisher.apply(apply);
}
  1. 执行
private static void myCollector() {
	// 创建一个数组和一个集合, 进行操作
    String[] strings = {"a", "b", "c", "d"};
    List<String> strs = new ArrayList<>(Arrays.asList("e", "f", "g"));
    List<String> operate = Operations.operate(strings, strs, new MyCollector<>());
    System.out.println(operate);
}
  1. 结果
    执行结果
    Collectors
    工具集不做过多介绍
    常用的方法: toXxx, groupBy, joining, reducing
    大部分的容器操作都可以通过下篇的Stream流实现

三. Optional

3.1 描述

容器对象, 容器中的值可以为null
定义对象检测方法和对象处理方法, 用于进行对象检测(空值检测), 空值问题的解决方 案

3.2 案例
  1. 创建
    Optional.of: 不允许为null 值的创建方式, 会报空指针异常
    Optional.ofNullable: 允许为null 值的创建方式
    Optional.empty: 值为null 的创建方式(Optional内部维护的空值对象)
Optional<Box> box = Optional.of(new Box());
Optional<Box> box1 = Optional.ofNullable(new Box());
Optional<Box> box2 = Optional.empty();
  1. null值调用
    orElse: 当前处理容器中的Optional值为null时, 则将orElse的参数作为返回值
    orElseGet: 当前处理容器中的Optional值为 null时, 则将orElseGet中定义的方法返回值作为方法返回值
    orElseThrow: 当前处理容器中的Optional值为null时, 则将orElseThrow中定义的方法返回的异常抛出
private static void orElse() {
    Box b = null;
    Box box1 = Optional.ofNullable(b).orElse(new Box().setName("1"));
    Box box2 = Optional.ofNullable(b).orElseGet(() -> new Box().setName("2"));
    Box box = Optional.ofNullable(b).orElseThrow(() -> new RuntimeException("box 不存在!"));
}
  1. 映射值
    map: 根据参数定义的函数, 获取值对象的相应映射值, 创建映射值的Optional容器并返回
    flagMap: 参数定义的函数的返回值必须是Optional容器, 方法的返回值结果都已映射值对象的Optional容器
Optional<Box> box = Optional.of(new Box().setName("1"));
Optional<String> s1 = box.map((b) -> b.getName());
Optional<String> s2 = box.flatMap((b) -> Optional.ofNullable(b.getName()));
  1. 判空
    isPresent: 判断空值
    ifPresent: 判断空值, 在判断不为null时进行处理操作
Optional<Box> box = Optional.empty();
Random random = new Random();
int i = random.nextInt();
if (i % 2 == 0) {
    box = Optional.of(new Box().setName("1"));
}
System.out.println(box.isPresent() ? "不为 null" : "为 null");
box.ifPresent(System.out::println);
  1. 筛选
    filter: 对容器中的值进行过滤; 如果存在值符合条件, 则返回这个Optional容器, 如果不存在, 返回Optionalempty对象
double random = Math.random() * 10;
Optional<Box> box = Optional.of(new Box().setName("1").setSize((int) random));
Optional<Box> box1 = box.filter(b -> b.getSize() > 4);
System.out.println(box1);

空指针解决方案演示:

User user = new User();
String s = Optional.ofNullable(user)
        .map(User::getAddress)
//         .orElse(new Address())
        .map(Address::getProvince)
//         .orElseGet(Province::new)
        .flatMap((p -> {
            City city = new City();
            p.setCity(city);
            return Optional.of(city);
        }))
        .map(City::getStreet)
        .orElseThrow(() -> new RuntimeException("容器中值为 null"));

方式一: 添加默认值的方式
方式二: 抛异常的方式(map方法在某次返回empry之后, 后续的所有操作都是对 empry的操作, 除非使用flatMap进行手动创建新的数据容器)

日 期 : 2022 − 02 − 12 \color{#00FF00}{日期:2022-02-12} 20220212

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值