Java8 新特性

Java8新特性

推荐阅读:

  • lambda表达式、方法引用、构造器引用、数组引用
  • Stream流
  • optional
  • 时间日期API [线程安全]
  • 重复注解与类型注解
  • ForkJoin框架
  • 接口的默认方法和静态方法

1. Lambda表达式

Java8中引入了一个新的操作符 “->” 该操作符称位箭头操作符

  • 定义一个接口(函数式接口)
@FunctionalInterface
public interface MyFunction {

    Integer getValue(Integer num);
}
  • 使用lambda表达式
public class LambdaTest2 {

    public Integer operation(Integer num, MyFunction mf) {
        return mf.getValue(num);
    }

    @Test
    public void test1() {
        Integer num = operation(100, (x) -> x * x);
        System.out.println(num);

        Integer num2 = operation(100, (x) -> x + 200);
        System.out.println(num2);
    }

}

1.1 内置四大核心函数式接口

接口名称接口类型方法方法参数方法返回值类型
Consumer消费型void accept(T t)×
Supplier供给型T get()×
Function<T,R>函数型R apply (T t)
Predicate断言型boolean test(T t)
消费型接口
   /**
     * Consumer<T>: 消费型接口
     * 需求:
     */
    public void happy(double money, Consumer<Double> con) {
        con.accept(money);
    }

    @Test
    public void happyTest() {
        happy(10000, m -> System.out.println("今天吃饭花了" + m));
    }
供给型接口
   /**
     * Supplier<T>:供给型接口
     * 需求:随机存储10个数字存入集合
     */
    public List<Integer> getNumList(int num, Supplier<Integer> sup) {
        List<Integer> list = new ArrayList<>();

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

    @Test
    public void supTest() {
        getNumList(10, () -> (int) (Math.random() * 100));
    }
函数型接口
   /**
     * Function<T,R>: 函数型接口
     */
    public String strHandler(String str, Function<String, String> fun) {
        return fun.apply(str);
    }

  
    @Test
    public void funTest() {
        String s = strHandler("\t\t\t 你是谁啊! \t\t\t", (str) -> str.trim());
        System.out.println(s);
    }
断言型接口
/**
     * Predicate<T>: 断言型接口
     * 需求:将满足条件的字符串放入集合
     */
    public static List<String> filterStr(List<String> strList, Predicate<String> pre) {
        List<String> list = new ArrayList<>();
        for (String str : strList) {
            if (pre.test(str)) {
                list.add(str);
            }
        }
        return list;
    }

    @Test
    public void preHandler(){
        List<String> stringList = Arrays.asList("Hello", "Friends", "Lambda", "www", "ok");
        List<String> strings = filterStr(stringList, (str) -> str.length() > 3);
        System.out.println(strings);
    }

1.2 方法引用

若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”(可理解为是lambda表达式的另外一种表现形式)

有三种语法形式
  • 对象::实例方法名
  • 类名::静态方法名
  • 类名::实例方法名
注意
  1. Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!

  2. 若Lambda参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可使用 ClassName::methodName

对象::实例方法名
/**
     * 对象::实例方法名
     */
    @Test
    public void test1() {
        PrintStream ps = System.out;
        // 方法引用
        Consumer<String> con = ps::println;
        con.accept("aqwsdasagas");
    }
类名::静态方法名
/**
     * 类::静态方法名
     */
    @Test
    public void test2() {
        // lambda
        Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
        // 方法引用
        Comparator<Integer> com1 = Integer::compare;
    }
类::实例方法名
/**
     * 类::实例方法名
     */
    @Test
    public void test3() {
        BiPredicate<String, String> bp = (x, y) -> x.equals(y);
        BiPredicate<String, String> bp1 = String::equals;
    }

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

1.3 构造器引用

注意:需要调用的构造函数的参数列表要与函数式接口中抽象方法的参数列表保持一致!

前提定义Employee和枚举类

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

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

    public Employee(int id) {
        this.id = id;
    }
}
  • 构造器引用案例
   /**
     * 构造器引用: 获得了一个无参构造
     */
    @Test
    public void test4() {
        // lambda
        Supplier<Employee> sup = () -> new Employee();
        // 构造器引用
        Supplier<Employee> sup2 = Employee::new;
        // 应该获得了一个无参构造,因为get方法就是无参有返回值
        Employee employee = sup2.get();
        System.out.println(employee);
    }

    /**
     * 构造器引用:获取参数为int id的构造方法
     */
    @Test
    public void test5() {
        Function<Integer, Employee> fun = (x) -> new Employee(x);
        Employee apply = fun.apply(2);
        Function<Integer, Employee> fun2 = Employee::new;
        // 根据apply的参数个数去调用对应的构造方法(一个参数,int类型)
        Employee apply2 = fun.apply(3);
        System.out.println(apply);
        System.out.println(apply2);
    }

1.4 数组引用

Type::new

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

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

1.5 情景处理

某公司员工定制排序
package cn.luis.lambda.practise;

import cn.luis.lambda.method.Employee;
import org.junit.jupiter.api.Test;

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

public class Compony {

    /**
     * 某公司员工基本信息
     */
    List<Employee> emps = Arrays.asList(
            new Employee(1,"zhanagsan", 18, 1111.11),
            new Employee(2,"lisi", 49, 2222.22),
            new Employee(3,"zhaoliu", 49, 3333.33),
            new Employee(4,"tianqi", 35, 4444.44)
    );


    /**
     * 定制排序:先按年龄比,年龄相同按姓名比
     */
    @Test
    public void test1() {
        Collections.sort(emps, (e1, e2) -> {
            if (e1.getAge() == e2.getAge()) {
                return e1.getName().compareTo(e2.getName());
            } else {
                return Integer.compare(e1.getAge(),e2.getAge());
            }
        });

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

        for (Employee emp : emps) {
            System.out.println(emp);
        }

    }

}

字符串处理
package cn.luis.lambda.practise;

import org.junit.jupiter.api.Test;

public class StringTest {
    /**
     * 函数式接口
     */
    interface StringFun {
        String getValue(String str);
    }

    /**
     * 用于处理字符串
     */
    public String strHandler(String str, StringFun sf) {
        return sf.getValue(str);
    }


    /**
     * 字符串处理
     */
    @Test
    public void test1() {
        String s1 = strHandler("\t\t\t hello , may i have a dog \t\t\t", str -> str.trim());
        System.out.println(s1);
        String s2 = strHandler("asdfghjkl", str -> str.toUpperCase());
        System.out.println(s2);
        String s3 = strHandler("asdfghjkl", str -> str.substring(0, 3));
        System.out.println(s3);
    }

}

long型数字处理
   package cn.luis.lambda.practise;

import org.junit.jupiter.api.Test;

public class LongTest {

    /**
     * 函数式接口
     */
    public interface MyFunction<T, R> {

        R getValue(T t1, T t2);

    }

    /**
     * 对于两个long型数据进行处理
     * MyFunction<Integer,Integer>: 传入参数类型、返回值类型
     */
    public void operacte(Integer x, Integer y, MyFunction<Integer, Integer> mf) {
        System.out.println(mf.getValue(x, y));
    }

    @Test
    public void test1() {
        operacte(100, 100, (x, y) -> x + y);
    }
}

2. Stream流

Stream的三个操作步骤

  • 创建Stream
  • 中间操作
  • 终止操作(终端操作)

2.1 创建Stream

创建stream的四种方式

  • 通过Collection系列集合提供的stream()方法或parallelStream()
		List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();
		Stream<String> stream2 = list.parallelStream();
  • 通过静态方法获取一个数组流
		Employee[] employees = new Employee[10];
        Stream<Employee> stream2 = Arrays.stream(employees);
  • 通过Stream类静态类中的of方法
		Stream<String> stream3 = Stream.of("aa","bb","cc","dd");
  • 创建无限流:两种(迭代和生成)
		// 4.1迭代 : 传一个起始值和一个一元运算
        Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
        /// 中间操作  终止操作
        stream4.limit(10).forEach(System.out::println);

        // 4.2生成(无限生成随机数)
        Stream.generate(()->Math.random()).forEach(System.out::println);

2.2 中间操作

中间操作:不会执行任何操作,终止操作:一次性执行全部内容,即“惰性求值”

2.2.1 筛选与切片
方法描述
filter接收Lambda,从流中排除某些元素
limit截断流,使其元素不超过给定数量
skip(n)跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
distinct筛选,通过流所生成元素的hashCode() 和 equals() 去除重复元素

例子:

  • filter
	List<Employee> employees = Arrays.asList(
            new Employee(1, "张三", 18, 1111.11),
            new Employee(2, "李四", 49, 2222.22),
            new Employee(3, "赵六", 57, 3333.33),
            new Employee(4, "田七", 35, 4444.44),
            new Employee(4, "田七", 35, 4444.44)
    );	

    /**
     * 中间操作:不会执行任何操作,终止操作:一次性执行全部内容,即“惰性求值”
     * 1.筛选与切片:filter
     */
	@Test
    public void test1() {
        // 内部迭代:迭代操作由Stream API完成
        employees.stream()
                .filter(e -> e.getAge() > 35)
                .forEach(System.out::println);

        // 外部迭代
        Iterator<Employee> it = employees.iterator();

        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
  • limit
package cn.luis.stream.intermediate;

import cn.luis.stream.Employee;
import org.junit.jupiter.api.Test;

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

public class LimitTest {

    List<Employee> employees = Arrays.asList(
            new Employee(1, "张三", 18, 1111.11),
            new Employee(3, "赵六", 57, 3333.33),
            new Employee(4, "田七", 35, 4444.44),
            new Employee(2, "李四", 49, 2222.22),
            new Employee(5, "田七", 35, 4444.44)
    );

    /**
     * 中间操作:不会执行任何操作,终止操作:一次性执行全部内容,即“惰性求值”
     * 2.筛选与切片:limit
     */
    @Test
    public void test2() {
        // limit;短路,找到两个符合的就终止了
        employees.stream()
                .filter(e -> {
                    //System.out.println("不符合条件的或者直接抛弃了!" + e);
                    return e.getAge() > 20;
                })
                .limit(2)
                .forEach(System.out::println);
    }

}
  • skip
	/**
     * 中间操作:不会执行任何操作,终止操作:一次性执行全部内容,即“惰性求值”
     * 1.筛选与切片:skip
     */
    @Test
    public void test3() {
        // limit;跳过前两个
        employees.stream()
                .filter(e -> {
                    System.out.println("呦!");
                    return e.getAge() > 25;
                })
                .skip(2)
                .forEach(System.out::println);
    }
  • distinct
	/**
     * 中间操作:不会执行任何操作,终止操作:一次性执行全部内容,即“惰性求值”
     * 1.筛选与切片:distinct
     */
    @Test
    public void test4() {
        // distinct;去重 【employees要重写hashcode和equals】
        employees.stream()
                .filter(e -> {
                    System.out.println("呦!");
                    return e.getAge() > 25;
                })
                .distinct()
                .forEach(System.out::println);
    }
2.2.2 映射

map里传入Function函数型接口,传入一个参数返回一个值

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

例子:

public class StreamApi3 {

    List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");

    @Test
    public void test1() {
        list.stream()
                .map(s -> s.toUpperCase())
                .forEach(System.out::println);

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


        // 这种套娃式可以用flatMap替代 (见test2)
        Stream<Stream<Character>> stream = list.stream().map(StreamApi3::filterCharacter);
        stream.forEach(sm->{
            sm.forEach(System.out::println);
        });
    }


    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }

    @Test
    public void test2() {
        // 扁平化maop:原来把流放入map流,现在是直接将流中的元素放入flatmap流中
        // 把{a,a,a},{b,b,b} ... 转换成了 {a,a,a,b,b,b,c,c,c}
        Stream<Character> characterStream = list.stream()
            .flatMap(StreamApi3::filterCharacter);
        
        characterStream.forEach(System.out::println);
    }
}
2.2.3 排序
方法描述
sorted()自然排序(Comparable)
sorted(Comparator com)定制排序(Comparator)

例子:

	/**
     * 中间操作:不会执行任何操作,终止操作:一次性执行全部内容,即“惰性求值”
     * 3. 排序
     * sorted() -- 自然排序(Comparable)
     * sorted(Comparator com) -- 定制排序(Comparator)
     */
    @Test
    public void test1() {

        // 自然排序
        Stream<Employee> sorted = employees.stream().sorted();
        // 按年龄排序,年龄相同按名字排序
        employees.stream()
                .sorted((e1, e2) -> {
                    if (e1.getAge() == e2.getAge()) {
                        return e1.getName().compareTo(e2.getName());
                    } else {
                        Integer x = e1.getAge();
                        return x.compareTo(e2.getAge());
                    }
                }).forEach(System.out::println);
    }

2.3 终止操作

2.3.1 查找与匹配
方法描述
allMatch检查是否匹配所有元素
anyMatch检查是否至少匹配一个元素
noneMatch检查是否没有匹配所有元素
findFirst返回第一个元素
findAny返回当前流中的任意元素
count返回流中元素的总个数
max返回流中的最大值
min返回流中的最小值

例子:

  • 查找的对象
List<Employee> employees = Arrays.asList(
            new Employee(1, "张三", 18, 1111.11, Status.BUSY),
            new Employee(2, "李四", 49, 2222.22, Status.FREE),
            new Employee(3, "赵六", 57, 3333.33, Status.BUSY),
            new Employee(4, "田七", 35, 4444.44, Status.VOCATION),
            new Employee(2, "李十四", 49, 2222.22, Status.FREE),
            new Employee(2, "李十四", 49, 2222.22, Status.FREE),
            new Employee(2, "李十四", 49, 2222.22, Status.FREE)
    );
  • 查找与匹配
@Test
    public void test1() {
        boolean b = employees.stream()
                .allMatch(e -> e.getStatus().equals(Status.BUSY));
        System.out.println(b);

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

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

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

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

        // 并行
        Optional<Employee> anye2 = employees.parallelStream()
                .filter(e -> e.getStatus().equals(Status.FREE))
                .findAny();
        System.out.println(anye2.get());
    }
  • 查找与匹配
	@Test
    public void test2() {
        long count = employees.stream()
                .count();
        System.out.println(count);

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

        Optional<Double> min = employees.stream()
                .map(Employee::getSalary)
                .min(Double::compare);
        System.out.println(min.get());
    }
2.3.2 规约
方法描述
reduce可以将流中的元素反复结合起来,得到一个值

例子:

/**
     * reduce(起始值,二元运算): 规约
     */
    @Test
    public void test3() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        // 先把起始值0作为x,再从list取数放入y
        Integer sum = list.stream()
                .reduce(0, (x, y) -> x + y);
        System.out.println(sum);

        System.out.println("----------计算公司总工资---------");
        Double reduce = employees.stream()
                .map(e -> e.getSalary())
                .reduce(0.0, (x, y) -> x + y);
        // 优化写法(map-reduce模式)
        Optional<Double> reduce1 = employees.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println(reduce1.get());
    }
2.3.3 收集

包括集合、计算、分组、分区

方法描述
collect将流转换为其他形式,接收一个Collectot接口的实现,用于给Stream中的元素汇总的方法
  • 集合
	@Test
    public void test4() {
        List<String> nameList = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        nameList.forEach(System.out::println);
        System.out.println("-----------过滤重复数据--------------");
        Set<String> nameSet = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
        nameSet.forEach(System.out::println);
        System.out.println("-----------放到其他类型集合--------------");
        HashSet<String> nameHashSet = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
        nameHashSet.forEach(System.out::println);
    }
  • 计算
	/**
     * collect 之 计算
     */
    @Test
    public void test5() {
        // 总数
        Long collect = employees.stream()
                .collect(Collectors.counting());
        System.out.println(collect);

        // 平均值
        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> maxo = employees.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(maxo.get());

        // 最小值
        Optional<Double> mino = employees.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(mino.get());
    }
  • 分组
	/**
     * collect 之 分组
     */
    @Test
    public void test6() {
        // 分组
        Map<Status, List<Employee>> statusListMap = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        /*statusListMap.keySet().forEach(System.out::println);
        statusListMap.entrySet().forEach(System.out::println);
        System.out.println(statusListMap);*/

        // 多级分组
        /*employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus), Collectors.groupingBy((Employee e) -> {
                    if (e.getAge() <= 35) {
                        return "青年";
                    }else if (e.getAge() > 20) {
                        return "老年";
                    } else {
                        return "少年";
                    }
                }));*/

        // 分区: 满足条件的分一个区,不满足的分一个区
        Map<Boolean, List<Employee>> collect = employees.stream()
                .collect(Collectors.partitioningBy(e -> e.getSalary() > 2000.0));
        System.out.println(collect);

        // Double:强大计算
        DoubleSummaryStatistics aDouble = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(aDouble.getAverage());
        System.out.println(aDouble.getMax());
        System.out.println(aDouble.getCount());

        // 字符串拼接
        String str = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(","));
        System.out.println(str);
    }

2.4 应用

  • 交易员类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Trander {

    private String name;
    private String city;

}
  • 交易类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Transaction {

    private Trander trander;
    private int year;
    private int value;
}
  • 练习
package cn.luis.stream.practise;

import org.junit.Before;
import org.junit.Test;

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

/**
 * @author Luis
 * @version 1.0
 * @description TODO
 * @date 2020/12/8 9:25
 */
public class TransactionTest {

    List<Transaction> transactions;

    @Before
    public void before() {
        Trander raoul = new Trander("Raoul", "Cambridge");
        Trander mario = new Trander("Mario", "Milan");
        Trander alan = new Trander("Raoul", "Cambridge");
        Trander brian = new Trander("Brian", "Cambridge");

        transactions = Arrays.asList(
                new Transaction(brian, 2011, 300),
                new Transaction(raoul, 2012, 1000),
                new Transaction(raoul, 2011, 400),
                new Transaction(mario, 2012, 710),
                new Transaction(mario, 2012, 700),
                new Transaction(alan, 2012, 950)
        );
    }

    /**
     * 找到2011年发生的所有交易,并按交易额排序(从低到高)
     * [有条件先筛选,排序记得写规则]
     */
    @Test
    public void test1() {
        transactions.stream()
                .filter(t -> t.getYear() == 2011)
                .sorted((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()))
                .forEach(System.out::println);
    }

    /**
     * 交易员都在哪些不同的城市工作过
     * [记得去重]
     */
    @Test
    public void test2() {
        transactions.stream()
                .map(t -> t.getTrander().getCity())
                .distinct()
                .forEach(System.out::println);
    }

    /**
     * 查找所有来自剑桥的交易员,并按姓名排序
     */
    @Test
    public void test3() {
        transactions.stream()
                .map(t -> t.getTrander())
                .distinct()
                .filter(trander -> "Cambridge".equals(trander.getCity()))
                .sorted((t1, t2) -> t1.getName().compareTo(t2.getName()))
                .forEach(System.out::println);

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

        transactions.stream()
                .map(t -> t.getTrander().getName())
                .sorted()
                .forEach(System.out::println);

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

        String reduceStr = transactions.stream()
                .map(t -> t.getTrander().getName())
                .sorted()
                .reduce("", String::concat);
        System.out.println(reduceStr);

        System.out.println("---------------------------------");
    // 将所有姓名组成字符串,然后按照子母排排序
        transactions.stream()
                .map(t->t.getTrander().getName())
                .flatMap(TransactionTest::filterCharacter)
                .sorted()
                .forEach(System.out::print);
    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }

    /**
     * 返回所有交易员的姓名字符串,按字母顺序排序
     */
    @Test
    public void test4() {
        String collect = transactions.stream()
                .map(Transaction::getTrander)
                .map(Trander::getName)
                .sorted(String::compareToIgnoreCase)
                .collect(Collectors.joining(","));
        System.out.println(collect);
    }

    /**
     * 有没有交易员是在米兰工作的
     */
    @Test
    public void test5() {
        boolean b = transactions.stream()
                .map(Transaction::getTrander)
                .map(Trander::getCity)
                .noneMatch(c -> "Milan".equals(c));

        System.out.println(!b);

    }

    /**
     * 打印生活在剑桥的交易员的所有交易额
     */
    @Test
    public void test6() {
        Optional<Integer> reduce = transactions.stream()
                .filter(t -> "Cambridge".equals(t.getTrander().getCity()))
                .map(Transaction::getValue)
                .reduce(Integer::sum);
        System.out.println(reduce.isPresent());
        System.out.println(reduce.get());
    }

    /**
     * 所有交易中,最高的交易额
     */
    @Test
    public void test7() {
        Optional<Integer> max = transactions.stream()
                .map(Transaction::getValue)
                .max(Double::compare);
        System.out.println(max.get());

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

        Optional<Integer> collect = transactions.stream()
                .map(Transaction::getValue)
                .collect(Collectors.maxBy((v1, v2) -> v1.compareTo(v2)));
        System.out.println(collect.get());
    }
}

3. DateAPI

3.1 人读的时间

api描述
LocalDate日期年月日
LocalTime时间时分秒
LocalDateTime时间和日期年月日+时分秒

例子:

@Test
    public void test1() {
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        LocalDateTime ldt2 = LocalDateTime.of(2020, 12, 9, 12, 56);
        System.out.println(ldt2);

        LocalDateTime ldt3 = ldt.plusYears(2);
        System.out.println(ldt3);

        LocalDateTime ldt4 = ldt.minusMonths(2);
        System.out.println(ldt4);

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

        int year = ldt.getYear();
        int monthValue = ldt.getMonthValue();
        int dayOfMonth = ldt.getDayOfMonth();
        int hour = ldt.getHour();
        int minute = ldt.getMinute();
        int second = ldt.getSecond();
        System.out.println(year);
        System.out.println(monthValue);
        System.out.println(dayOfMonth);
        System.out.println(hour);
        System.out.println(minute);
        System.out.println(second);

    }

结果:

2020-12-10T17:05:55.025
2020-12-09T12:56
2022-12-10T17:05:55.025
2020-10-10T17:05:55.025
----------------------------
2020
12
10
17
5
55

3.2 机器读的时间

方法描述
Instant时间戳(以unix元年:1970年1月1日00:00:00到某个时间之间的毫秒值)
Duration计算两个“时间”之间的间隔
Period计算两个“日期”之间的间隔

例子:

	@Test
    public void test2() {
        // 默认获取UTC时区(格林威治)的时间
        Instant in1 = Instant.now();
        System.out.println(in1);

        // 加8小时
        OffsetDateTime odt = in1.atOffset(ZoneOffset.ofHours(8));
        System.out.println(odt);

        // 毫秒值
        long haomiao = in1.toEpochMilli();
        System.out.println(haomiao);

        Instant instant = Instant.ofEpochSecond(1000);
        
    }	
  • 计算时间间隔
	/**
     * Duration:计算;两个“时间”之间的间隔
     */
    @Test
    public void test3() throws InterruptedException {
        Instant in1 = Instant.now();
        Thread.sleep(3000);
        Instant in2 = Instant.now();
        Duration duration = Duration.between(in1, in2);
        // 获取秒和纳秒用get~(),获取毫秒用to~()
        System.out.println(duration.toMillis()); // 3001

        LocalTime lt = LocalTime.now();
        Thread.sleep(2000);
        LocalTime lt2 = LocalTime.now();
        System.out.println(Duration.between(lt, lt2).toMillis()); // 2001
        System.out.println(Duration.between(lt2, lt).toMillis()); // -2001

    }
  • 计算日期间隔
	/**
     * Period:计算;两个“日期”之间的间隔
     */
    @Test
    public void test4() throws InterruptedException {
        LocalDate ld1 = LocalDate.now();
        LocalDate ld2 = LocalDate.of(2015, 1, 1);
        Period period = Period.between(ld2, ld1);
        System.out.println(period);
        System.out.println(period.getYears());
        System.out.println(period.getMonths());
        System.out.println(period.getDays());
        
        /**
            P5Y11M9D
            5
            11
            9
        */

    }

3.3 时间校正器

api描述
TemporalAdjuster时间校正器
TemporalAdjusters时间校正器工具类

例子:

@Test
    public void test5() {
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        // 将月中的天指定为10
        LocalDateTime ldt2 = ldt.withDayOfMonth(10);
        System.out.println(ldt2);

        // 下一个周日
        LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        System.out.println(ldt3);

        // 自定义:下一个工作日是什么时候
        LocalDateTime gzr = ldt.with(l -> {
            LocalDateTime ldt4 = (LocalDateTime) l;
            DayOfWeek dayOfWeek = ldt4.getDayOfWeek();
            if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
                return ldt4.plusDays(4);
            } else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
                return ldt4.plusDays(2);
            } else {
                return ldt4.plusDays(1);
            }
        });
        System.out.println(gzr);
        System.out.println("工作日: " + gzr.getMonthValue() + "月" + gzr.getDayOfMonth() + "日");
    }

3.4 格式化时间、日期

api

api描述
DateTimeFormatter时间格式化

方法

api描述举例
.ofPattern()定义日期转换格式DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”);

例子:

	@Test
    public void test6() {

        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        // DateTimeFormatter、LocalDateTime 都有format方法
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // String strDate1 = dtf2.format(ldt);
        String strDate2 = ldt.format(dtf2);
        System.out.println(strDate2);
        LocalDateTime ldt2 = LocalDateTime.parse(strDate2, dtf2);
        System.out.println(ldt2);

    }

3.5 时区的处理

api描述
ZoneId时区
ZonedDate时间
ZonedTime日期
ZonedDateTime日期和时间

例子:

	/**
     * 时区的处理:ZonedDate、ZonedTime、ZonedDateTime
     */
    @Test
    public void test7() {
        Set<String> zoneIds = ZoneId.getAvailableZoneIds();
        //zoneIds.forEach(System.out::println);
        //System.out.println(zoneIds.stream().count()); // 599个时区

        // 指定时区
        LocalDateTime now1 = LocalDateTime.now();
        // 两种指定时区方法
        LocalDateTime now2 = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        // 两种指定时区方法
        ZonedDateTime zdt = now1.atZone(ZoneId.of("Asia/Shanghai"));
        System.out.println(now1);
        System.out.println(now2);
        System.out.println(zdt);
    }

3.6 Instant、LocalDateTime、Date间的转换

3.6.1 Date to LocalDateTime
   /**
     * Date to LocalDateTime
     */
    @Test
    public void test9() {
        Date todayDate = new Date();
        System.out.println("todayDate = " + todayDate);

        LocalDateTime todayLocalDateTime = todayDate.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();

        System.out.println("todayLocalDateTime = " + todayLocalDateTime);
    }

结果:

todayDate = Fri Dec 11 10:26:00 CST 2020
todayLocalDateTime = 2020-12-11T10:26:00.115
3.6.2 LocalDateTime to Date
   /**
     * LocalDateTime to Date
     */
    @Test
    public void test10() {
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println("localDateTime = " + localDateTime);

        Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

        System.out.println("date = " + date);
    }

结果:

localDateTime = 2020-12-11T10:29:17.403
date = Fri Dec 11 10:29:17 CST 2020
3.6.3 综合

通过:ZonedDateTime

   /**
     * Instant、LocalDateTime、Date转换
     */
    @Test
    public void test8() {
        ZoneId zoneId = ZoneId.of("Asia/Shanghai");

        Instant instant = Instant.now();
        ZonedDateTime zonedDateTime = instant.atZone(zoneId);

        System.out.println("instant=== " + instant);
        System.out.println("zonedDateTime=== " + zonedDateTime);

        LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
        System.out.println("localDateTime=== " + localDateTime);

        Date date = Date.from(instant);
        System.out.println("date=== " + date);
    }

结果:

instant=== 2020-12-11T02:21:52.939Z
zonedDateTime=== 2020-12-11T10:21:52.939+08:00[Asia/Shanghai]
localDateTime=== 2020-12-11T10:21:52.939
date=== Fri Dec 11 10:21:52 CST 2020
3.6.4 DateUtil
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
 
public class Dateutili {
 
    public static Date asDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }
 
    public static Date asDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
 
    public static LocalDate asLocalDate(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
    }
 
    public static LocalDateTime asLocalDateTime(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }
}

4. Optional

4.1 API

apiOptional
位置java.util.Optional
描述是一个容器类,是一个可以为null的容器对象

4.2 方法

4.2.1 创建Optional类对象的方法
方法描述
Optional.of(T t)创建一个Optional实例
Optional.empty()创建一个空的Optional实例
Optional.ofNullable(T t)若t不为null,创建Optional实例,否则创建空实例

例子:

Optional.of(T t) 创建一个Optional实例

/**
     * Optional.of(T t) 创建一个Optional实例
     */
    @Test
    public void test1() {
        Girl girl = new Girl();
        girl = null;
        // of(T t): 保证t是非空的
        Optional<Girl> girl1 = Optional.of(girl);
        System.out.println(girl1);
    }

Optional.ofNullable(T t) 若t不为null,创建Optional实例,否则创建空实例

@Test
    public void test2() {
        Girl girl = new Girl();
        girl = null;
        // ofNullable(T t): t可以为null
        Optional<Girl> girl1 = Optional.ofNullable(girl);
        System.out.println(girl1);
    }
4.2.2 判断Optional容器中是否包含对象
方法描述
isPresent()判断是否包含对象
void idPresent(Consumer<? super ?> consumer)如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它
4.2.3 获取Optional容器的对象
方法描述
T get()如果调用对象包含值,返回该值,否则抛异常
orElse(T other)如果调用对象包含值,返回该值,否则返回 other对象
orElseGet(Supplier<? extends ?> s)果调用对象包含值,返回该值,否则返回 s 获取的值
T orElseThrow(Supplier<? extends X> exceptionSupplier)如果有值将其返回,否则抛出由Supplier接口实现提供的异常
map(Function f)如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
flatMap(Function mapper)与map类似,要求返回值必须是Optional

4.3 情景应用

定义一个boy类、girl类

  • boy
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Boy {

    private Girl girl;
}
  • girl
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Girl {

    private String name;
}
测试类

如果boy为null,则空指针会在本类抛出,若name为空,则在getGirlName方法抛出

原始写法
package cn.luis.lambda.atguigu.optional;

import org.junit.Test;

import java.util.Optional;

public class OptionalTest {

    public String getGirlName(Boy boy) {
        return boy.getGirl().getName();
    }

    /**
     * 练习
     * 如果boy为null,则空指针会在本类抛出,若name为空,则在getGirlName方法抛出
     */
    @Test
    public void test3() {
        Boy boy = new Boy();
        //boy = null;
        String girlName = getGirlName(boy);
        System.out.println(girlName);
    }
}
普通优化
package cn.luis.lambda.atguigu.optional;

import org.junit.Test;

import java.util.Optional;

public class OptionalTest {

    /**
     * 普通优化
     */
    public String getGirlName1(Boy boy) {
        if (boy != null) {
            Girl girl = boy.getGirl();
            if (girl != null) {
                return boy.getGirl().getName();

            }
        }
        return null;
    }

    /**
     * 普通优化
     * 如果boy为null,则空指针会在本类抛出,若name为空,则在getGirlName方法抛出
     */
    @Test
    public void test33() {
        Boy boy = new Boy();
        //boy = null;
        String girlName = getGirlName1(boy);
        System.out.println(girlName);
    }
}
使用Optional优化
package cn.luis.lambda.atguigu.optional;

import org.junit.Test;

import java.util.Optional;

public class OptionalTest {

    /**
     * Optional优化
     */
    public String getGirlName2(Boy boy) {
        Girl girl = boy.getGirl();
        Optional<Girl> girlOptional = Optional.ofNullable(girl);
        Girl girl1 = girlOptional.orElse(new Girl("Mary"));
        System.out.println(girl1.getName());
        return null;
    }

    /**
     * Optional优化
     */
    @Test
    public void test333() {
        //Boy boy = new Boy();
        Boy boy = new Boy(new Girl("LiLy"));
        Optional<Boy> boyOptional = Optional.ofNullable(boy);
        Boy boy1 = boyOptional.orElse(new Boy());
        String girlName = getGirlName1(boy1);
        System.out.println(girlName);
    }
}

5. 可重复注解、类型注解

5.1 可重复注解

重复注解:1. 定义注解,2.定义注解容器,3在注解上添加@Repeatable(容器注解.class)

  • 自定义注解
@Repeatable(MyAnns.class)
@Target({TYPE, METHOD,FIELD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnn {

    String value() default "luis";
}
  • 定义一个注解容器
@Target({TYPE, METHOD,FIELD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnns {

    MyAnn[] value();
}
  • 测试类
public class AnnotationTest {

     /**
     * 重复注解:1. 定义注解,2.定义注解容器,3在注解上添加@Repeatable(容器注解.class)
     */
    @MyAnn("hello")
    @MyAnn("world")
    public void show() {
    }

    /**
     * 利用反射获取注解的值
     */
    @Test
    public void test1(){
        Class<AnnotationTest> clazz = AnnotationTest.class;
        try {
            Method showMethod = clazz.getMethod("show");

            MyAnn[] ann = showMethod.getAnnotationsByType(MyAnn.class);
            for (MyAnn myAnn : ann) {
                System.out.println(myAnn.value());
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

5.2 类型注解

java8需要搭配框架或者自己定义注解才可

public class AnnotationTest {

    /**
     * 类型注解,java8需要搭配框架或者自己定义注解才可
     * @Target({ElementType.TYPE, METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.LOCAL_VARIABLE})
     */
    // 提供编译时检查,不允许为null
    public /*@NonNull*/ Object obj = null;
}

6. ForkJoin框架

[了解]:对并发优化!

package cn.luis.lambda.atguigu.fork_join;

import java.util.concurrent.RecursiveTask;

/**
 * @author Luis
 * @version 1.0
 * @description TODO  RecursiveAction:无返回值
 * @date 2020/12/9 9:51
 */
public class FoekJoinCalculate extends RecursiveTask<Long> {

    private static final long serialVersionUID = 134656970987L;

    private long start;
    private long end;
    // 临界值
    private static final long THRESHOLD = 10000;

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

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

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

            for (long i = start; i <= end; i++) {
                sum += 1;
            }
            return sum;
        } else {
            long middle = (start + end) / 2;
            FoekJoinCalculate left = new FoekJoinCalculate(start, middle);
            // 拆分子任务,同时压入线程队列
            left.fork();

            FoekJoinCalculate right = new FoekJoinCalculate(middle + 1, end);
            // 拆分子任务,同时压入线程队列
            right.fork();

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

  • 测试类
package cn.luis.lambda.atguigu.fork_join;

import org.junit.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 Luis
 * @version 1.0
 * @description TODO
 * @date 2020/12/9 10:20
 */
public class ForkTest {

    /**
     * ForkJoin框架 (和普通for对比,要数据特大才有效果,因为拆分也需要时间)
     */
    @Test
    public void test1() {
        // 计算时间戳
        Instant start = Instant.now();

        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask<Long> task = new FoekJoinCalculate(0, 10000000000L); //1876
        Long sum = pool.invoke(task);

        System.out.println(sum);

        Instant end = Instant.now();

        System.out.println("耗费时间:" + Duration.between(start, end).toMillis()); //34
    }

    /**
     * 普通for
     */
    @Test
    public void test2() {
        // 计算时间戳
        Instant start = Instant.now();
        long sum = 0L;
        for (long i = 0; i <= 10000000000L; i++) {
            sum += i;
        }
        System.out.println(sum);
        Instant end = Instant.now();

        System.out.println("耗费时间:" + Duration.between(start, end).toMillis()); //4324
    }

    /**
     * java8并行流
     */
    @Test
    public void test3(){
        // 生成long型随机数

        // 串行流
        long reduce = LongStream.rangeClosed(0, 10000000000L)
                .reduce(0, Long::sum);
        System.out.println(reduce);

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

        // 串行流
        long reduce2 = LongStream.rangeClosed(0, 10000000000L)
                .parallel()
                .reduce(0, Long::sum);
        System.out.println(reduce2);


    }

}

本文总结自B站-尚硅谷

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本微信小程序医院挂号预约系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此微信小程序医院挂号预约系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。微信小程序医院挂号预约系统有管理员,用户两个角色。管理员功能有个人中心,用户管理,医生信息管理,医院信息管理,科室信息管理,预约信息管理,预约取消管理,留言板,系统管理。微信小程序用户可以注册登录,查看医院信息,查看医生信息,查看公告资讯,在科室信息里面进行预约,也可以取消预约。微信小程序医院挂号预约系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值