Java8 新特性

Java 8新特性

简介

  • 速度更快(JVM空间、数据结构的变化)
  • 代码更少(Lambda表达式使得代码更加简洁化)
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常Optional
  • 最核心的为Lambda表达式与Stream API

主要内容

1、Lambda表达式

​ Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可传递的代码(将代码像数据一样进行传递),可以写出更简洁,更灵活的代码,作为一种更紧凑的代码风格,使Java语言表达能力得到了提升

表达式语法示例
import org.junit.jupiter.api.Test;

import java.util.Comparator;
import java.util.function.Consumer;

/**
 * Lambda 表达式的基础语法:Java8中引入了一个新的操作符 “->” 该操作符成为箭头操作符或lambda操作符
 *                                              箭头操作符将 Lambda 表达式拆分成两份
 * 左侧:Lambda 表达式的参数列表
 * 右侧:Lambda 表达式中所需执行的功能。即Lambda体
 *
 * 语法格式一:无参数。无返回值:() -> System.out.println("Hello Lambda!");
 * 语法格式二:有一个参数,并且无返回值:(x) -> System.out.println(x);
 * 语法格式三:若只有一个参数,小括号可以不写  x -> System.out.println(x);
 * 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
 *              Comparator<Integer> com = (x,y) -> {
 *             System.out.println("函数时接口"+(x+y));
 *             return Integer.compare(1,10);
 *         };
 * 语法格式五:若Lambda体中只有一条语句,return和大括号都可有省略不写
 * 语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即“类型推断”
 *
 *
 * @author World
 * @since 2021/7/20 17:40
 */
public class LambdaTest2 {
    @Test
    public void test01() {
        // 匿名内部类
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello world");
            }
        };
        r.run();

        System.out.println("----------------------");
        // Lambda表达式
        Runnable r1 = () -> System.out.println("Hello Lambda!");
        r1.run();
    }

    @Test
    public void tes02(){
        Consumer<String> con = (x) -> System.out.println(x);
        con.accept("hello world");
    }

    @Test
    public void test03(){
        Comparator<Integer> com = (x,y) -> {
            System.out.println("函数时接口"+(x+y));
            return Integer.compare(1,10);
        };
    }

    @Test
    public void test04(){
        Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
    }

    //运算
    @Test
    public void test06(){
        Integer num = operation(10, (x) -> x * x);
        Integer num1 = operation(10, (x) -> x + 100);
        System.out.println(num);
        System.out.println(num1);
    }

    public Integer operation(Integer num,MyFun myFun){
        return myFun.getValue(num);
    }
}

接口:

@FunctionalInterface
public interface MyFun {

    public Integer getValue(Integer num);

}
public interface MyPredicate<T> {

    public boolean test(T t);

}
练习:

实体类(Employee):

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Employee {

    private int id;
    private String name;
    private int age;
    private double salary;

接口:

public interface MyFunction {

    public String getValue(String str);

}
public interface MyFunction2<T,R> {

    public R getValue(T t1,T t2);

}

代码:

import cn.jsl.test.Employee;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;


/**
 * @author World
 * @since 2021/7/20 20:52
 */
public class LambdaTest {

  List<Employee> employees = Arrays.asList(
            new Employee(1,"张三",18,3333.33),
            new Employee(2,"李四",35,4444.44),
            new Employee(3,"王五",37,5555.55)
    );

    @Test
    public void test01() {
        Collections.sort(employees,(e1,e2) -> {
            if(e1.getAge() == e2.getAge()) {
                return e1.getName().compareTo(e2.getName());
            }else{
                return Integer.compare(e1.getAge(),e2.getAge());
            }
        });
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }

    @Test
    public void test02() {
        String trimStr = strHandler("\t\t\t Hello World  ", (str) -> str.trim());
        System.out.println(trimStr);

        String abc = strHandler("abc", (str) -> str.toUpperCase());
        System.out.println(abc);

        String string = strHandler("哈哈哈嘿嘿嘿呵呵呵", (str) -> str.substring(3, 6));
        System.out.println(string);
    }

    /**
     * 处理字符串
     * @return 处理字符串
     */
    public String strHandler(String str, MyFunction myFunction) {
        return myFunction.getValue(str);
    }

    @Test
    public void test03() {
        op(100L,200L, (x,y) -> x + y);

        op(10L,10L, (x,y) -> x * y);
    }

    /**
     * 处理两个Long型数据
     */
    public void op(Long l1,Long l2,MyFunction2<Long,Long> myFunction) {
        System.out.println(myFunction.getValue(l1,l2));
    }
}

2、函数式接口

四大内置核心函数式接口

在这里插入图片描述

在这里插入图片描述

示例:
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 *
 * 四大核心函数式接口:
 * Consumer<T> : 消费型接口  void accept(T t);
 *
 * Supplier<T> : 供给型接口  T get();
 *
 * Function<T,R> : 函数型接口 R apply(T t);
 *
 * Predicate<T> : 断言型接口  boolean test(T t);
 *
 * @author World
 * @since 2021/7/21 14:40
 */
public class LambdaTest2 {

    /**
     * 消费型接口
     */
    @Test
    public void test01() {
        happy(10000, (m) -> System.out.println("今天去了趟*灯区,花了"+ m + "元,真是太贵了"));
    }

    public void happy(double money, Consumer<Double> consumer) {
        consumer.accept(money);
    }

    /**
     * 供给型接口
     */
    @Test
    public void tet02() {
        List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));

        for (Integer num : numList) {
            System.out.println(num);
        }

    }

    /**
     * 产生指定个数的证书,并放入集合中
     */
    public List<Integer> getNumList(int num, Supplier<Integer> supplier) {
        List<Integer> list = new ArrayList<>();

        for (int i = 0; i < num; i++) {
            Integer n = supplier.get();
            list.add(n);
        }
        return list;
    }

    /**
     * 函数型接口
     */
    @Test
    public void test02() {
        String trimStr = strHandler("\t\t\t Hello World", (str) -> str.trim());
        System.out.println(trimStr);

        String abc = strHandler("abc", (str) -> str.toUpperCase());
        System.out.println(abc);

        String string = strHandler("哈哈哈嘿嘿嘿呵呵呵", (str) -> str.substring(3, 6));
        System.out.println(string);
    }

    /**
     * 处理字符串
     * @return 处理字符串
     */
    public String strHandler(String str, Function<String,String> function) {
        return function.apply(str);
    }

    @Test
    public void test04() {
        List<String> list = Arrays.asList("hello", "world", "www", "Lambda");
        List<String> stringList = filterStr(list, (s) -> s.length() > 3);

        for (String str : stringList) {
            System.out.println(str);
        }
    }   

    /**
     * 将满足条件的字符串放入集合中
     * @param list
     * @param predicate
     * @return
     */
    public List<String> filterStr(List<String> list, Predicate<String> predicate) {
        List<String> listStr = new ArrayList<>();

        for (String str : list){
            if(predicate.test(str)) {
                listStr.add(str);
            }
        }
        return listStr;
    }
}

3、方法引用与构造器引用

示例:
import cn.jsl.test.Employee;
import org.junit.jupiter.api.Test;

import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.*;

/**
 * @author World
 * @since 2021/7/21 16:14
 *
 * 一、方法引用:若Lambda体中的内容有方法已经实现了,五年可以使用“方法引用”
 *          (可以理解为方法引用式Lambda表达式的另一种表现形式
 *
 * 主要有三种语法:
 * 1、对象::实例方法名
 * 2、类::静态方法名
 * 3、类::实例方法名
 *
 * 注意:
 *  1、Lambda 体中调用方法的参数列表与返回值类型,
 *  要与函数式接口中抽象方法的函数列表和返回值类型保持一致
 *  2、如果 Lambda 参数列表中的第一参数是实例方法的调用者,
 *  而第二个参数是实例方法的参数时,可以使用ClassName::method
 *
 * 二、构造器引用
 * 格式:CLassName::new
 *
 * 注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致
 *
 * 三、数组引用
 * Type::new
 *
 */
public class MethodRefTest {

    /**
     * 对象::实例方法名
     */
    @Test
    public void test01(){
        PrintStream ps1 = System.out;

        Consumer<String > con = (x) -> ps1.println(x);

        PrintStream ps = System.out;
        Consumer<String> con1 = ps::println;

        Consumer<String> con2 = System.out::println;
        con2.accept("abc");
    }

    @Test
    public void test02() {
        Employee emp = new Employee();
        Supplier<String> sup = () -> emp.getName();
        String str = sup.get();
        System.out.println(str);

        Supplier<Integer> sup2 = emp::getAge;
        Integer num = sup2.get();
        System.out.println(num);
    }

    /**
     * 类::静态方法名
     */
    @Test
    public void test03() {
        Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
        Comparator<Integer> com1 = Integer::compare;
    }

    /**
     * 类::实例方法名
     */
    @Test
    public void test04() {
        BiPredicate<String,String> bq = (x,y) -> x.equals(y);
        BiPredicate<String,String> bq2 = String :: equals;
    }

    /**
     * 构造器引用
     */
    @Test
    public void test05(){
        Supplier<Employee> sup = () -> new Employee();

        //构造器引用方式
        Supplier<Employee> sup2 = Employee::new;
        Employee emp = sup2.get();
        System.out.println(emp);
    }

    @Test
    public void test06() {
        Function<Integer,Employee> fun = (x) -> new Employee(x);

        Function<Integer,Employee> fun2 = Employee::new;
        Employee emp = fun2.apply(1);
        System.out.println(emp);

        BiFunction<Integer,Integer,Employee> bf = Employee::new;
    }

    /**
     * 数组引用
     */
    @Test
    public void test07() {
        Function<Integer,String[]> fun = (x) -> new String[x];
        String[] strs = fun.apply(10);
        System.out.println(strs.length);

        Function<Integer,String[]> fun2 = String[]::new;
        String[] strs2 = fun.apply(20);
        System.out.println(strs2.length);
    }
}

写test06()方法时需要在Employee中添加构造,代码如下:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Employee {

    private int id;
    private String name;
    private int age;
    private double salary;

    public Employee(Integer age){
        this.age = age;
    }

    public Employee(Integer id,Integer age){
        this.id = id;
        this.age = age;
    }
}

4、Stream API

​ Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作,简而言之,它提供了一种高效且易于使用的处理数据的方法。

Stream(流)是什么

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

“集合讲的是数据。流讲的是计算”

注意:

​ 1)Stream自己不会存储元素。

​ 2)Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream

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

Stream的操作三个步骤:

在这里插入图片描述

1、创建

在这里插入图片描述

示例:
import cn.jsl.test.Employee;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author World
 * @since 2021/7/21 21:08
 *
 * 一、Stream的三个操作步骤:
 *
 * 1、创建Stream
 * 2、中间操作
 * 3、终止(终端)操作
 *
 */

public class StreamApiTest {

    /**
     * 创建Stream
     */
    @Test
    public void test01() {
        //1、可以通过Collection系列集合提供的stream()或parallelStream()
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        //2、通过Arrays中的静态方法stream()获取数组流
        Employee[] employees = new Employee[10];
        Stream<Employee> stream2 = Arrays.stream(employees);

        //3、通过Stream类中的静态方法of()
        Stream<String> stream3 = Stream.of("aa","bb","cc");

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

        //生成
        Stream.generate(() -> Math.random())
                .limit(10)
                .forEach(System.out::println);
    }
}
2、中间操作
2.1 筛选与切片

在这里插入图片描述

示例:
import cn.jsl.test.Employee;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author World
 * @since 2021/7/22 9:01
 *
 * 一、Stream的三个操作步骤:
 *
 *  1、创建Stream
 *  2、中间操作
 *  3、终止(终端)操作
 */
public class StreamApiTest02 {


    List<Employee> employees = Arrays.asList(
            new Employee(1,"张三",45,3333.33),
            new Employee(2,"李四",18,4444.44),
            new Employee(3,"王五",37,5555.55),
            new Employee(4,"赵六",45,6666.66),
            new Employee(5,"田七",18,7777.77),
            new Employee(6,"刘八",18,8888.88),
            new Employee(7,"陈九",37,9999.99),
            new Employee(7,"陈九",37,9999.99)
    );


    /**
     * 中间操作
     *
     * 筛选与切片
     * filter : 接受Lambda,从流中排除某些元素
     * limit : 截断流,使其元素不少过给定数量
     * skip(n) : 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,
     *              则返回一个空流,与limit(n)互补
     * distinct : 筛选,通过流所生成元素的hashCode()和equals()去除重复元素
     *
     * 内部迭代:迭代操作由Stream API完成
     * filter : 接受Lambda,从流中排除某些元素
     */
    @Test
    public void test01() {
        //中间操作:不会执行任何操作
        Stream<Employee> stream = employees.stream()
                .filter((e) -> {
                    System.out.println("Stream API的中间操作");
                    return e.getAge() > 35;
                });
        //终止操作:一次性执行全部内容,即“惰性求值”
        stream.forEach(System.out::println);
    }

    /**
     * 外部迭代
     */
    @Test
    public void test02() {
        Iterator<Employee> it = employees.iterator();

        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }

    /**
     * limit : 截断流,使其元素不少过给定数量
     */
    @Test
    public void test03() {
        employees.stream()
                .filter((e) -> {
                    System.out.println("短路");
                    return e.getSalary() > 3000;
                })
                .limit(2)
                .forEach(System.out::println);
    }
    /**
     * skip(n) : 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,
     *            则返回一个空流,与limit(n)互补
     */
    @Test
    public void test04() {
        employees.stream()
                .filter((e) -> e.getSalary() > 3000)
                //跳过前两个满足条件的值
                .skip(2)
                .forEach(System.out::println);
    }

    /**
     * distinct : 筛选,通过流所生成元素的hashCode()和equals()去除重复元素
     *
     * 如果实体类Employee中没用lombok,需要自己去生成hashCode方法和equals方法,不然不会生效
     */
    @Test
    public void test05() {
        employees.stream()
                .filter((e) -> e.getSalary() > 8000)
                .distinct()
                .forEach(System.out::println);
    }
}
注意:

​ distinct : 筛选,如果实体类Employee中没用lombok,需要自己去生成hashCode方法和equals方法

2.2 映射

示例:
import cn.jsl.test.Employee;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author World
 * @since 2021/7/22 9:01
 * <p>
 * 一、Stream的三个操作步骤:
 * <p>
 * 1、创建Stream
 * 2、中间操作
 * 3、终止(终端)操作
 */
public class StreamApiTest03 {


    List<Employee> employees = Arrays.asList(
            new Employee(1, "张三", 45, 3333.33),
            new Employee(2, "李四", 18, 4444.44),
            new Employee(3, "王五", 37, 5555.55),
            new Employee(4, "赵六", 45, 6666.66),
            new Employee(5, "田七", 18, 7777.77),
            new Employee(6, "刘八", 18, 8888.88),
            new Employee(7, "陈九", 37, 9999.99),
            new Employee(7, "陈九", 37, 9999.99)
    );

    /**
     * 映射:map——接收Lambda,将元素转换成其他形式活体取信息,接受收个函数作为参数
     * 该函数会被应用到每个元素上,并将其映射成一个新的元素
     * flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有连接城一个流
     */
    @Test
    public void test01() {
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd", "ee");

        list.stream()
                .map((str) -> str.toUpperCase())
                .forEach(System.out::println);

        System.out.println("----------------------------");

        employees.stream()
                .map(Employee::getName)
                .forEach(System.out::println);

        System.out.println("----------------------------");

     /*   Stream<Stream<Character>> stream = list.stream()
                // {a,a},{b,b}
                .map(StreamApiTest03::filterCharacter);

        stream.forEach((sm) -> {
            sm.forEach(System.out::println);
        });*/

        System.out.println("----------------------------");

        Stream<Character> sm = list.stream()
                // {a,a,b,b,c,c}
                .flatMap(StreamApiTest03::filterCharacter);
        sm.forEach(System.out::println);
    }

    @Test
    public void test02() {
        List<String> list = Arrays.asList("aa", "bb", "cc", "ee");

        List list2 = new ArrayList<>();

        list2.add(11);
        list2.add(22);
        list2.addAll(list);

        System.out.println(list2);

    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();

        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }
}
2.3 排序

示例:
 /**
     * 排序:
     * sorted()——自然排序(Comparable)
     * sorted(Comparator)——定制排序(Comparator)
     */
    @Test
    public void test03() {
        List<String> list = Arrays.asList("bb", "aa", "dd", "cc");

        list.stream()
                .sorted()
                .forEach(System.out::println);

        System.out.println("----------------------------");

        employees.stream()
                .sorted((e1, e2) -> {
                    if (e1.getAge().equals(e2.getAge())) {
                        return e1.getName().compareTo(e2.getName());
                    } else {
                        return e1.getAge().compareTo(e2.getAge());
                    }
                }).forEach(System.out::println);
    }
2.4 查找与匹配

在这里插入图片描述

示例:
import cn.jsl.test.Employee;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

/**
 *
 * 终止操作
 *
 * @author World
 * @since 2021/7/22 16:26
 */
public class StreamApiTest04 {

    List<Employee> employees = Arrays.asList(
            new Employee(1, "张三", 45, 3333.33,Employee.Status.BUSY),
            new Employee(2, "李四", 18, 4444.44,Employee.Status.FREE),
            new Employee(3, "王五", 37, 5555.55,Employee.Status.VOCATION),
            new Employee(4, "赵六", 45, 6666.66,Employee.Status.BUSY),
            new Employee(5, "田七", 18, 7777.77,Employee.Status.FREE),
            new Employee(6, "刘八", 18, 8888.88,Employee.Status.VOCATION),
            new Employee(7, "陈九", 37, 9999.99,Employee.Status.BUSY)
    );

    /**
     * 查找与匹配
     *      allMatch——检查是都匹配所有元素
     *      anyMatch——检查是都至少匹配一个元素
     *      noneMatch——检查是否没有匹配所有元素
     *      findFirst——返回第一个元素
     *      findAny——返回当前流中的任意元素
     *
     */
    @Test
    public void test01() {
        boolean b = employees.stream()
                .allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b);

        boolean b1 = employees.stream()
                .anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b1);

        boolean b2 = employees.stream()
                .noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b2);

        Optional<Employee> first = employees.stream()
                //.sorted((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary()))
                .sorted(Comparator.comparingDouble(Employee::getSalary))
                .findFirst();
        System.out.println(first.get());

        Optional<Employee> op = employees.stream()
                .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
                .findAny();
        System.out.println(op.get());
    }

    /**
     * count——返回流中元素的总个数
     * max——返回流中最大值
     * min——返回流中最小值
     */
    @Test
    public void test02() {
        long count = employees.stream()
                .count();
        System.out.println(count);

        Optional<Employee> max = employees.stream()
                .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(max.get());

        Optional<Double> min = employees.stream()
                .map(Employee::getSalary)
                .min(Double::compare);
        System.out.println(min.get());

    }
}

实体类需要进行修改,添加一个状态字段,添加一个枚举

private Status Status;

public enum Status {
   FREE,
   BUSY,
   VOCATION
}
3、终止操作
3.1 归约

在这里插入图片描述

示例:
import cn.jsl.test.Employee;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 *
 * 终止操作
 *
 * @author World
 * @since 2021/7/22 17:37
 */
public class StreamApiTest05 {

    List<Employee> employees = Arrays.asList(
            new Employee(1, "张三", 45, 3333.33,Employee.Status.BUSY),
            new Employee(2, "李四", 18, 4444.44,Employee.Status.FREE),
            new Employee(3, "王五", 37, 5555.55,Employee.Status.VOCATION),
            new Employee(4, "赵六", 45, 6666.66,Employee.Status.BUSY),
            new Employee(5, "田七", 18, 7777.77,Employee.Status.FREE),
            new Employee(6, "刘八", 18, 8888.88,Employee.Status.VOCATION),
            new Employee(7, "陈九", 37, 9999.99,Employee.Status.BUSY),
            new Employee(7, "陈九", 37, 9999.99,Employee.Status.BUSY)
    );

    /**
     * 归约:
     *      reduce(T identity,BinaryOperator) / reduce(BinaryOperator)
     *      可以将流中元素反复结合起来,得到一个值
     */
    @Test
    public void test03() {
        List<Integer> list = Arrays.asList(1,2,3,4,5);

        Integer sum = list.stream()
                .reduce(0, (x, y) -> x + y);
        System.out.println(sum);

        System.out.println("--------------------------------");

        Optional<Double> op = employees.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println(op.get());
    }
}
3.2 收集

在这里插入图片描述

示例:
    /**
     * 收集:
     *      collect——将流转换为其他形式,接收一个Collector接口的实现,
     *      用于给Stream中元素做汇总的方法
     */
    @Test
    public void test04() {
        List<String> collect = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        collect.forEach(System.out::println);

        System.out.println("-------------------------------");

        Set<String> collect1 = employees.stream()
                .map(Employee::getName)
                //去虫,筛选重复
                .collect(Collectors.toSet());
        collect1.forEach(System.out::println);

        System.out.println("-------------------------------");

        //放入特殊集合
        HashSet<String> collect2 = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
        collect2.forEach(System.out::println);
    }

	@Test
    public void test05() {
        //总数
        Long count = employees.stream()
                .collect(Collectors.counting());
        System.out.println(count);

        //平均值
        Double avg = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(avg);

        //总和
        Double sum = employees.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(sum);

        //最大值
        Optional<Employee> max = employees.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(max);

        //最小值
        Optional<Double> min = employees.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(min.get());
    }

    /**
     * 分组
     */
    @Test
    public void test06() {
        Map<Employee.Status, List<Employee>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
    }

    /**
     * 多级分组
     */
    @Test
    public void test07() {
        Map<Employee.Status, Map<String, List<Employee>>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                    if (e.getAge() <= 35) {
                        return "青年";
                    } else if (e.getAge() <= 50) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));
        System.out.println(map);
    }

    /**
     * 分区
     */
    @Test
    public void test08() {
        Map<Boolean, List<Employee>> collect = employees.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
        System.out.println(collect);
    }

    @Test
    public void test09() {
        DoubleSummaryStatistics collect = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(collect.getSum());
        System.out.println(collect.getAverage());
        System.out.println(collect.getMax());
    }
    @Test
    public void test10() {
        String collect = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",", "==", "=="));
        System.out.println(collect);
    }
}

5、并行流与顺序流

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

示例:
import lombok.AllArgsConstructor;

import java.util.concurrent.RecursiveTask;

/**
 * @author World
 * @since 2021/7/23 15:49
 */
@AllArgsConstructor
public class ForkJoinCalculate extends RecursiveTask<Long> {

    private long start;
    private long end;

    private static final long THRESHOLD = 10000;

    @Override
    protected Long compute() {

        long length = end - start;

        if(length <= THRESHOLD) {
            long sum = 0;

            for (long i = start; i < end; i++) {
                sum += i;
            }
            return sum;
        }else {
            long middle = (start + end) / 2;

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

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

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

import org.junit.jupiter.api.Test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;

/**
 * @author World
 * @since 2021/7/23 16:23
 */
public class ForkJoinTest {

    @Test
    public void test01() {
        Instant start = Instant.now();

        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask<Long> 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).toMillis());

    }

    /**
     * 普通for
     */
    @Test
    public void test02() {
        Instant start = Instant.now();
        long sum = 0L;

        for (int i = 0; i < 100000000L; i++) {
            sum += i;
        }
        Instant end = Instant.now();

        System.out.println("耗时为:"+ Duration.between(start,end).toMillis());
    }

    /**
     * java8 并行流
     */
    @Test
    public void test03() {
        Instant start = Instant.now();

        LongStream.rangeClosed(0, 1000000000L)
                .parallel()
                .reduce(0, Long::sum);

        Instant end = Instant.now();

        System.out.println("耗时为:" + Duration.between(start, end).toMillis());
    }
}

6、Optional容器

在这里插入图片描述

示例
import cn.jsl.pojo.Employee;
import org.junit.jupiter.api.Test;

import java.util.Optional;

/**
 * @author World
 * @since 2021/7/23 17:13
 */
public class OptionalTest {

    /**
     * Optional容器类的常用方法:
     * 1. Optional.of(T t) :创建一个Optional实例
     * 2. Optional.empty() :创建一个空的Optional实例
     * 3. optional.ofNullable(T t):若t不为null,创建Optional 实例,否则创建空实例
     * 4. isPresent() :判断是否包含值
     * 5. orElse(T t) :如果调用对象包含值,返回该值,否则返回t
     * 6. orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回s 获取的值
     * 7. map(Function f):如果有值对其处理,并返回处理后的0ptional,否则返回Optional.empty()
     * 8. flatMap(Function mapper):与map类似,要求返回值必须是Optional
     */
    @Test
    public void test01() {
        Optional<Employee> op = Optional.of(null);

        Employee emp = op.get();
        System.out.println(emp);
    }

    @Test
    public void test02() {
        Optional<Employee> op = Optional.empty();
        System.out.println(op.get());
    }

    @Test
    public void test03() {
        Optional<Employee> op = Optional.ofNullable(null);

        //new Employee
       /* if(op.isPresent()) {
            System.out.println(op.get());
        }*/

        /*Employee employee = op.orElse(new Employee(1,"张三",18,999.99, Employee.Status.BUSY));
        System.out.println(employee);*/

        Employee emp = op.orElseGet(() -> new Employee());
        System.out.println(emp);
    }

    @Test
    public void test04() {
        Optional<Employee> op = Optional.ofNullable(new Employee(1,"张三",18,999.99, Employee.Status.BUSY));

        /*Optional<String> str = op.flatMap((e) -> Optional.of(e.getName()));
        System.out.println(str.get());*/

        Optional<String> str2 = op.flatMap((e) -> Optional.of(e.getName()));
        System.out.println(str2.get());
    }
}
例题:

实体类:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 *
 * 男人类
 *
 * @author World
 * @since 2021/7/24 8:30
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Man {

    private Goddess goddess;

}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Optional;

/**
 *
 * 新男人类
 *
 * @author World
 * @since 2021/7/24 8:45
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NewMan {

    private Optional<Goddess> goddess = Optional.empty();

}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 *
 * 女神类
 *
 * @author World
 * @since 2021/7/24 8:30
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goddess {

    private String name;

}

测试:

/**
 * 获取一个男人心中女神的名字
 */
@Test
public void test05() {
    /*Man man = new Man();
        String name = getGoddessName(man);
        System.out.println(name);*/

    Optional<Goddess> goddess = Optional.ofNullable(new Goddess("小波"));
    Optional<NewMan> op = Optional.ofNullable(new NewMan(goddess));
    String str = getGoddessName2(op);
    System.out.println(str);

}

public String getGoddessName2(Optional<NewMan> man) {
    return man.orElse(new NewMan())
        .getGoddess()
        .orElse(new Goddess("小苍"))
        .getName();
}

public String getGoddessName(Man man) {
    if(man != null) {
        Goddess goddess = man.getGoddess();

        if(goddess != null) {
            return goddess.getName();
        }
    }
    return "小苍";
}

7、接口中的默认方法与静态方法

7.1默认方法

在这里插入图片描述

在这里插入图片描述

示例:
/**
 * @author World
 * @since 2021/7/24 10:38
 */
public interface MyFun {

    /**
     * 获取名字
     * @return
     */
    default String getName(){
        return "哈哈哈";
    }
}

/**
 * @author World
 * @since 2021/7/24 10:39
 */
public class MyClass {

    public String getName() {
        return "嘿嘿嘿";
    }
}
/**
 * @author World
 * @since 2021/7/24 10:47
 */
public interface MyInterface {

    /**
     * 获取名字
     * @return
     */
    default String getName() {
        return "呵呵呵";
    }
}
/**
 * @author World
 * @since 2021/7/24 10:48
 */
public class SubClass /*extends MyClass*/ implements MyFun,MyInterface {


    @Override
    public String getName() {
        return MyInterface.super.getName();
    }
}

/**
 * @author World
 * @since 2021/7/24 10:49
 */
public class DefaultInterface {

    public static void main(String[] args) {
        SubClass sc = new SubClass();
        System.out.println(sc.getName());
    }
}
7.2 默认方法
示例:
/**
 * @author World
 * @since 2021/7/24 10:47
 */
public interface MyInterface {

    /**
     * 静态方法
     */
    static void show() {
        System.out.println("静态方法");
    }
}
/**
 * @author World
 * @since 2021/7/24 10:49
 */
public class DefaultInterface {

    public static void main(String[] args) {

        MyInterface.show();
    }
}

8、新时间日期API

在这里插入图片描述

在这里插入图片描述

示例:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 旧
 * @author World
 * @since 2021/7/24 11:19
 */
public class DateFormatThreadLocal {

    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){
      @Override
      protected DateFormat initialValue() {
          return new SimpleDateFormat("yyyyMMdd");
      }
    };
    public static Date convert(String source) throws ParseException {
        return df.get().parse(source);
    }
}
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 旧
 * @author World
 * @since 2021/7/24 11:08
 */
public class SimpleDateFormatTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return DateFormatThreadLocal.convert("20210724");
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);

        List<Future<Date>> result = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            result.add(pool.submit(task));
        }
        for (Future<Date> dateFuture : result) {
            System.out.println(dateFuture.get());
        }
        pool.shutdown();
    }
}
8.1 LocalDate
示例:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * java8新
 * @author World
 * @since 2021/7/24 11:08
 */
public class SimpleDateFormatTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // java8新
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");

        Callable<LocalDate> task = new Callable<LocalDate>() {
            @Override
            public LocalDate call() throws Exception {
                return LocalDate.parse("20210724",dtf);
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);

        List<Future<LocalDate>> result = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            result.add(pool.submit(task));
        }
        for (Future<LocalDate> dateFuture : result) {
            System.out.println(dateFuture.get());
        }
        pool.shutdown();
    }
}
8.2 LocalDateTime
import org.junit.jupiter.api.Test;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;

/**
 * @author World
 * @since 2021/7/24 14:26
 */
public class LocalDateTimeTest {

    /**
     * 1、LocalDate  LocalTime  LocalDateTime
     */
    @Test
    public void test01() {
        //当前时间
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        System.out.println("--------------------------");

        //拼接时间
        LocalDateTime ldt2 = LocalDateTime.of(2021,07,24,  14,29,41);
        System.out.println(ldt2);

        System.out.println("--------------------------");

        //加两年
        LocalDateTime ldt3 = ldt.plusYears(2);
        System.out.println(ldt3);

        System.out.println("--------------------------");

        //减两个月
        LocalDateTime ldt4 = ldt.minusMonths(2);
        System.out.println(ldt4);

        System.out.println("--------------------------");

        System.out.println(ldt.getYear());
        System.out.println(ldt.getMonthValue());
        System.out.println(ldt.getDayOfMonth());
        System.out.println(ldt.getHour());

    }
}
8.3 Instant( 时间戳)

在这里插入图片描述

示例:

 /**
  * 2、Instant: 时间戳(以Unix元年:1970年1月1日00:00:00到某个时间之间的毫秒值)
  */
@Test
public void test03() {
    //默认获取UTC时区
    Instant ins1 = Instant.now();
    System.out.println(ins1);

    System.out.println("--------------------------");

    //设置时区
    OffsetDateTime offsetDateTime = ins1.atOffset(ZoneOffset.ofHours(8));
    System.out.println(offsetDateTime);

    System.out.println("--------------------------");

    //获得自1970-01-01T00:00:00Z的纪元以来的毫秒数
    System.out.println(ins1.toEpochMilli());

    System.out.println("--------------------------");

    //添加xx秒
    Instant instant = Instant.ofEpochSecond(60);
    System.out.println(instant);

}
8.4 Duration和Period

在这里插入图片描述

示例
/**
 * Duration:用于计算两个“时间”间隔
 */
@Test
public void test04() throws InterruptedException {
    Instant inst1 = Instant.now();

    Thread.sleep(1000);

    Instant inst2 = Instant.now();

    Duration duration = Duration.between(inst1,inst2);
    System.out.println(duration.toMillis());

    System.out.println("--------------------------------");

    LocalTime lt1 = LocalTime.now();

    Thread.sleep(1000);

    LocalTime lt2 = LocalTime.now();

    System.out.println(Duration.between(lt1, lt2).toMillis());
}

/**
 * Period:用于计算两个“日期”间隔
 */
@Test
public void test05() {
    LocalDate ld1 = LocalDate.of(2011,1,1);
    LocalDate ld2 = LocalDate.now();

    Period period = Period.between(ld1, ld2);
    System.out.println(period);

    System.out.println(period.getYears());
    System.out.println(period.getMonths());
    System.out.println(period.getDays());

}
8.5 TemporalAdjuster :时间校正器

在这里插入图片描述

示例
/**
 * TemporalAdjuster :时间校正器
 */
@Test
public void test06() {
    LocalDateTime ldt = LocalDateTime.now();
    System.out.println(ldt);

    LocalDateTime ldt2 = ldt.withDayOfMonth(10);
    System.out.println(ldt2);

    LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
    System.out.println(ldt3);

    //自定义下一个工作日
    LocalDateTime ldt4 = ldt.with((l) -> {
        LocalDateTime ldt5 = (LocalDateTime) l;

        DayOfWeek dow = ldt5.getDayOfWeek();

        if(dow.equals(DayOfWeek.FRIDAY)) {
            return ldt5.plusDays(3);
        }else if(dow.equals(DayOfWeek.SATURDAY)) {
            return ldt5.plusDays(2);
        }else {
            return ldt5.plusDays(1);
        }
    });
    System.out.println(ldt4);
}
8.6 DateTimeForMatter: 格式化时间/日期

在这里插入图片描述

示例:
/**
 * DateTimeForMatter: 格式化时间/日期
 */
@Test
public void test07() {
    DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
    LocalDateTime ldt = LocalDateTime.now();

    String strDate = ldt.format(dtf);
    System.out.println(strDate);

    System.out.println("--------------------------------");

    DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    String strDate2 = dtf2.format(ldt);
    System.out.println(strDate2);

    LocalDateTime newDate = LocalDateTime.parse(strDate2,dtf2);
    System.out.println(newDate);

}
8.7 时区处理

在这里插入图片描述

在这里插入图片描述

示例:
/**
 * ZonedDate、ZonedTime、ZonedDateTime
 */
@Test
public void test08() {
    //获取可用区域ID
    Set<String> set = ZoneId.getAvailableZoneIds();
    set.forEach(System.out::println);
}

@Test
public void test09() {
    LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
    System.out.println(ldt);

    LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
    ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Asia/Shanghai"));
    System.out.println(zdt);
}

9、其他新特性

重复注解与类型注解

​ Java 8对注解处理提供了两点改进:可重复的注解及可用于类 型的注解。

示例:
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;

/**
 * @author World
 * @since 2021/7/24 16:59
 */
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String value() default "World";

}
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;

/**
 * @author World
 * @since 2021/7/24 17:05
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {

    MyAnnotation[] value();

}
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;

/**
 *
 * 重复注解与类型注解
 *
 * @author World
 * @since 2021/7/24 17:03
 */
public class AnnotationTest {

    @MyAnnotation("Hello")
    @MyAnnotation("Chen")
    public  void show(@MyAnnotation("hhh") String string) {}
    
    @Test
    public void test01() throws NoSuchMethodException {
        Class<AnnotationTest> clazz = AnnotationTest.class;
        Method m1 = clazz.getMethod("show");

        MyAnnotation[] mas = m1.getAnnotationsByType(MyAnnotation.class);

        for (MyAnnotation myAnnotation : mas) {
            System.out.println(myAnnotation.value());
        }
    }
}

lDateTime ldt = LocalDateTime.now(ZoneId.of(“Europe/Tallinn”));
System.out.println(ldt);

LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(zdt);

}


### 9、其他新特性

##### 重复注解与类型注解

​		Java 8对注解处理提供了两点改进:可重复的注解及可用于类 型的注解。

###### 示例:

```java
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;

/**
 * @author World
 * @since 2021/7/24 16:59
 */
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String value() default "World";

}
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;

/**
 * @author World
 * @since 2021/7/24 17:05
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {

    MyAnnotation[] value();

}
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;

/**
 *
 * 重复注解与类型注解
 *
 * @author World
 * @since 2021/7/24 17:03
 */
public class AnnotationTest {

    @MyAnnotation("Hello")
    @MyAnnotation("Chen")
    public  void show(@MyAnnotation("hhh") String string) {}
    
    @Test
    public void test01() throws NoSuchMethodException {
        Class<AnnotationTest> clazz = AnnotationTest.class;
        Method m1 = clazz.getMethod("show");

        MyAnnotation[] mas = m1.getAnnotationsByType(MyAnnotation.class);

        for (MyAnnotation myAnnotation : mas) {
            System.out.println(myAnnotation.value());
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

11111_zZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值