Java8新特性

Java8新特性

1.Lambda表达式

箭头表达式 -> 左边参数 右边lambda体

Runnable runnable = ()-> {
   System.out.println("Lambda");
};

2.函数式接口

  • 接口中只有一个抽象方法的接口 可以用@Functionallterface声明检测
四大核心内置函数式接口
  • Consumer :消费型接口

    ​ void accept(T t)

    Consumer<String> consumer = (a) -> System.out.println("消费型接口" + a);
    consumer.accept("hello");
    
  • Supplier : 供给型接口

    ​ T get()

    Supplier<Integer> supplier = () -> (int) (Math.random() * 10);
    System.out.println(supplier.get());
    
  • Function<T,R> :函数型接口

    ​ R apply(T t)

    Function<String,Integer> function = (s) -> s.length();
    System.out.println(function.apply("asdad"));
    
  • Predicate : 断言型接口

    ​ boolean test(T t)

    Predicate<Integer> predicate = (i) -> i > 10;
    System.out.println(predicate.test(9));
    
其他函数式接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wjb7hnoz-1611213725262)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201221155701485.png)]

3.引用

3.1. 方法引用

​ :若 Lambda 表达式体中的内容已有方法实现,则我们可以使用"方法引用"

Lambda 表达实体中调用方法的参数列表、返回类型必须和函数式接口中抽象方法保持一致

语法格式

  • 对象::实例方法名

    //Consumer<String> consumer = (s) -> System.out.println(s);
    Consumer<String> consumer = System.out::println;
    consumer.accept("hello");
    
  • 类::静态方法名

    //Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
    Comparator<Integer> comparator = Integer::compare;
    System.out.println(comparator.compare(1, 2));
    
  • 类::实例方法名

    Lambda 参数列表中的第一个参数是方法的调用者,第二个参数是方法的参数时,才能使用 ClassName :: Method

    //BiPredicate<String, String> biPredicate = (x, y) -> x.equals(y);
    BiPredicate<String,String> biPredicate = String::equals;
    System.out.println(biPredicate.test("a","b"));
    
3.2. 构造器引用

语法格式: ClassName::new

需要调用的构造器的参数列表要与函数时接口中抽象方法的参数列表保持一致

//Supplier<User> user = () -> new User();
Supplier<User> user = User::new;
3.3. 数组引用

语法格式: Type[]::new

//Function<Integer, String[]> fun = (x) -> new String[x];
Function<Integer,String[]> fun2 = String[]::new;

4.Stream API

4.1. 创建流(Stream)

Stream:是数据渠道,用于操作数据源(数组、集合)所生成的元素序列

集合讲的是数据 流讲的是计算

注意:

  • Stream 自己不会存贮数据

  • Stream 不会改变数据源,会产生一个新的Stream

  • Stream 操作是延迟的。 这意味着他们会等到需要结果的时候才执行

Stream操作的三个步骤

  • 创建Stream:一个数据源(数组、集合) 获取一个流

  • 中间操作:中间链操作,对数据源的数据进行处理

  • 终止操作(终端操作):一个终止操作,执行中间操作链,并产生结果

创建流

//1.集合流
//  - Collection.stream() 串行流  - Collection.parallelStream() 并行流
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();

//2.数组流
//Arrays.stream(array)
String[] strings = new String[10];
Stream<String> stream2 = Arrays.stream(strings);

//3.Stream 静态方法
//Stream.of(...)
Stream<Integer> stream3 = Stream.of(1, 2, 3);

//4.无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.forEach(System.out::println);

//生成
Stream.generate(() -> Math.random())
    .limit(5)
    .forEach(System.out::println);
4.2. 中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理。而在终止操作的时候一次性全部处理,称为”惰性求值“

  • 内部迭代:迭代操作由 Stream API 完成
  • 外部迭代:我们通过迭代器完成

中间操作: 短路,达到满足条件后不再内部迭代

筛选与切片:

  • filter:接收 Lambda ,从流中排除某些元素
  • limit:截断流,使其元素不超过给定数量
  • skip(n):跳过元素,返回一个舍弃了前n个元素的流;若流中元素不足n个,则返回一个空流;与 limit(n) 互补
  • distinct:筛选,通过流所生成的 hashCode() 与 equals() 取除重复元素

映射:

  • map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
  • flatMap:接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流

排序:

  • sorted():自然排序 (Comparable)
  • sorted(Comparator c):定制排序 (Comparator )
4.3. 终止操作

查找/匹配:

  • allMatch:检查是否匹配所有元素

  • anyMatch:检查是否至少匹配一个元素

  • noneMatch:检查是否没有匹配所有元素

  • findFirst:返回第一个元素

  • findAny:返回当前流中的任意元素

  • count:返回流中元素的总个数

  • max:返回流中最大值

  • min:返回流中最小值

规约/收集

  • 归约:reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来,得到一个值
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Integer sum = list.stream()
    .reduce(0, (x, y) -> x + y);
System.out.println(sum);
  • 收集:collect 将流转换成其他形式;接收一个 Collector 接口的实现,用于给流中元素做汇总的方法 (Collectors 工具类)

    集合转换。 例如Collectors.toList(),Collectors.toSet()

    函数。 Collectors.counting()、Collectors.averagingDouble()、Collectors.summingDouble()、Collectors.maxBy()、Collectors.minBy()、Collectors.groupingBy()[map 接收,还可以多级分组]、Collectors.partitioningBy()[分区,map接收]、Collectors.summarizingDouble()、Collectors.joining()

4.4. 并行流
  • 并行流:就是把一个内容分成几个数据块,并用不同的线程分别处理每个数据块的流

  • Java 8 中将并行进行了优化,我们可以很容易的对数据进行操作;Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与串行流之间切换

Fork/Join框架:在必要情况下将一个大任务,进行拆分(fork)成若干个不可再拆分的小任务,再将一个个小任务运算的结果进行join汇总

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xWvt9XSJ-1611213725267)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201229110618728.png)]

Fork/Join实例:

public class ForkJoinCalculate extends RecursiveTask<Long> {

    private static final long serialVersionUID = 1234567890L;

    private long start;
    private long end;

    private static final long THRESHPLD = 10000;

    public ForkJoinCalculate(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        long length = end - start;

        if (length <= THRESHPLD) {
            long sum = 0;
            for (long i = start; i <= end; i++) {
                sum += i;
            }
        } else {
            long middle = (start + end) / 2;

            ForkJoinCalculate left = new ForkJoinCalculate(start, end);
            left.fork(); //拆分子任务 压入线程队列

            ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end);
            right.fork();

            return left.join() + right.join();
        }

        return null;
    }
}

public class TestForkJoin {

    /**
     * ForkJoin 框架
     */
    @Test
    public void test01(){
        Instant start = Instant.now();

        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinCalculate task = new ForkJoinCalculate(0, 100000000L);

        Long sum = pool.invoke(task);
        System.out.println(sum);

        Instant end = Instant.now();
        System.out.println(Duration.between(start, end).getNano());
    }

    /**
     * 普通 for循环
     */
    @Test
    public void test02(){
        Instant start = Instant.now();

        Long sum = 0L;
        for (long i = 0; i < 100000000L; i++) {
            sum += i;
        }

        Instant end = Instant.now();
        System.out.println(Duration.between(start, end).getNano());
    }
}

Java8 串行流、并行流

//串行流(单线程):切换为并行流 parallel()
//并行流:切换为串行流 sequential()
LongStream.rangeClosed(0, 100000000L)
    .parallel() //底层:ForkJoin
    .reduce(0, Long::sum);

5.Optional

**定义:**Optional 类 (java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在用 Optional 可以更好的表达这个概念;并且可以避免空指针异常

常用方法:

  • Optional.of(T t):创建一个 Optional 实例
  • Optional.empty(T t):创建一个空的 Optional 实例
  • Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则空实例
  • isPresent():判断是否包含某值
  • orElse(T t):如果调用对象包含值,返回该值,否则返回 t
  • orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回 s 获取的值
  • map(Function f):如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.empty()
  • flatmap(Function mapper):与 map 相似,要求返回值必须是 Optional

6.接口中的默认方法和静态方法

接口默认方法的‘类优先’原则

若一个接口中定义了默认方法,而另一个父类或接口中也定义了该同名方法时,选择父类中的方法。接口冲突必须覆盖方法来解决冲突。

7.Date/Time API

  • LoaclDate、LocalTime、LocalDateTime 不可变对象,ISO-8601日历的系统时间
  • Instant:以 Unix 元年 1970-01-01 00:00:00 到某个时间之间的毫秒值 Instant.now()默认获取UTC时区 toEpochMilli() 转换毫秒值
  • Duration:计算两个时间之间的间隔
  • Period:计算两个日期之间的间隔
  • TemporalAdjuster 时间校正器 TemporalAdjusters 提供大量TemporalAdjuster的实现
  • DateTimeFormatter:格式化时间 / 日期
  • ZonedDate、ZonedTime、ZonedDateTime
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值