Java8新特性

一,简介

  1. Lambda 表达式

  2. 函数式接口

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

  4. Stream API

  5. 接口中的默认方法与静态方法

  6. 新时间日期API

  7. 其他新特性

新特性简介:

⚫ 速度更快

⚫ 代码更少(增加了新的语法 Lambda 表达式

⚫ 强大的 Stream API

⚫ 便于并行

⚫ 最大化减少空指针异常 Optional

其中最为核心的为 Lambda 表达式与Stream API

二. Lambda表达式

1.简介

为什么使用Lambda 表达式:

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

2.从匿名类到 Lambda 的转换

3.语法

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。它将 Lambda 分为两个部分:

**左侧:**指定了 Lambda 表达式需要的所有参数

**右侧:**指定了 Lambda 体,即 Lambda 表达式要执行的功能

语法格式一:无参,无返回值,Lambda体只需一条语句

语法格式二:Lambda需要一个参数

语法格式三:Lambda只需要一个参数时,参数的小括号可以省略

语法格式四:Lambda需要两个参数,并且有返回值

Comparator<Integer> comparator = (x , y)->{
    System.out.println("包含多条语句应有大括号");
    System.out.println("比较x,y的大小");
    return Integer.compare(x,y);
};

语法格式五:当Lambda体只有一条语句时,return与大括号可以省略

Comparator<Integer> comparator = (x,y)->Integer.compare(x,y);

语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“数据推断”

类型推断

上述 Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的 “类型推断“


三.函数式接口

1.定义

⚫ 只包含一个抽象方法的接口,称为函数式接口

⚫ 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda

表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方

法上进行声明)。

⚫ 我们可以在任意函数式接口上使用 @FunctionalInterface 注解,

这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包

含一条声明,说明这个接口是一个函数式接口。

2.自定义函数式接口

3.作为参数传递Lambda 表达式

作为参数传递 Lambda 表达式:为了将 Lambda 表达式作为参数传递,接 收Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型。

*练习:

MyFunction
package Test;

@FunctionalInterface
public interface MyFunction {
    public String getValue(String str);
}
Test2
package Test;

import org.testng.annotations.Test;
public class Test2 {

    @Test
    public void test2(){
        //先去掉首尾空格
        String strtrim  = strHandler("\t\t\t Java8",(str) -> str.trim());
        System.out.println(strtrim);
        //截取字符
        String newstr = strHandler("abcdefghijklmn",str -> str.substring(2,5));
        System.out.println(newstr);
        
}
    //用于处理字符串的方法
    public String strHandler(String str,MyFunction myFunction){
        return myFunction.getValue(str);
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4atDP0r0-1649521532194)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220406193939471.png)]

四.Java四大内置的函数接口

函数式接口参数类型返回类型用途
Consumer< T >消费型接口Tvoid对类型为T的对象应用操作:void accept(T t)
Supplier< T >供给型接口T返回类型为T的对象:T get()
Function<T, R>函数型接口TR对类型为T的对象应用操作,并返回结果为R类型的对象:R apply(T t)
Predicate 断言型接口Tboolean确定类型为T的对象是否满足某约束,并返回boolean值:boolean test(T t)

1.消费型接口

	@Test
    public void test01(){
        //Consumer
        Consumer<Integer> consumer = (x) -> System.out.println("消费型接口" + x);
        //test
        consumer.accept(100);
    }

2.供给型接口

@Test
public void test02(){
    List<Integer> list = new ArrayList<>();
    List<Integer> integers = Arrays.asList(1,2,3);
    list.addAll(integers);
    //Supplier<T>
    Supplier<Integer> supplier = () -> (int)(Math.random() * 10);
    list.add(supplier.get());
    System.out.println(supplier);
    for (Integer integer : list) {
        System.out.println(integer);
    }
}

3.函数型接口

@Test
public void test03(){
    //Function<T, R>
    String oldStr = "abc123456xyz";
    Function<String, String> function = (s) -> s.substring(1, s.length()-1);
    //test
    System.out.println(function.apply(oldStr));
}

4.断言型接口

@Test
public void test04(){
    //Predicate<T>
    Integer age = 35;
    Predicate<Integer> predicate = (i) -> i >= 35;
    if (predicate.test(age)){
        System.out.println("你该退休了");
    } else {
        System.out.println("我觉得还OK啦");
    }
}

其他接口

五.引用

1.方法引用

定义:

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

语法格式:

  • 对象 :: 实例方法
  • 类 :: 静态方法
  • 类 :: 实例方法

对象::实例方法

package study;
import org.testng.annotations.Test;
import java.io.PrintStream;
import java.util.function.Consumer;

public class Test3 {
    @Test
    public void test01(){
        PrintStream ps = System.out;
        Consumer<String> con1 = (s) -> ps.println(s);
        con1.accept("aaa");
        Consumer<String> con2 = ps::println;
        con2.accept("bbb");
    }
}

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

类::静态方法

package study;

import org.testng.annotations.Test;

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

public class Test3 {
    @Test
    public void test02(){
        Comparator<Integer> com1 = (x, y) -> Integerpare(x, y);
        System.out.println(com1pare(1, 2));
        Comparator<Integer> com2 = Integer::compare;
        System.out.println(com2pare(2, 1));

    }
}

类::实例方法

package study;
import org.testng.annotations.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;

public class Test3 {
    @Test
    public void test03(){
        BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);
        System.out.println(bp1.test("a","b"));

        BiPredicate<String, String> bp2 = String::equals;
        System.out.println(bp2.test("c","c"));
    }
}

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

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

2.构造器引用

格式:

ClassName :: new

@Test
    public void test04(){
        Supplier<List> sup1 = () -> new ArrayList();
        //构造器引用方式
        Supplier<List> sup2 = ArrayList::new;

    }

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

3.数组引用

@Test
    public void test05(){
        Function<Integer,String[]> fun1 = (x)->new String[x];
        String[] str1 = fun1.apply(10);
        System.out.println(str1.length);
        Function<Integer,String[]> fun2 = String[]::new;
        String[] str2 = fun2.apply(20);
        System.out.println(str2.length);

    }

六.Stream API

1.了解Stream

(1)简介

Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一

个则是 Stream API(java.util.stream.*)

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对

集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数

据库查询。也可以使用 Stream API 来并行执行操作。简而言之,

Stream API 提供了一种高效且易于使用的处理数据的方式。

(2)什么是Stream

流(Stream) 到底是什么呢?

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

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

注意:

①Stream 自己不会存储元素。

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

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


2.Stream的操作三个步骤

创建 Stream

一个数据源(如:集合、数组),获取一个流

中间操作

一个中间操作链,对数据源的数据进行处理

终止操作(终端操作)

一个终止操作,执行中间操作链,并产生结果


3.创建Stream

Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:

⚫ default Stream stream() : 返回一个顺序流

⚫ default Stream parallelStream() : 返回一个并行流

(1)由数组创建流

Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:

⚫ static Stream stream(T[] array): 返回一个流重载形式,能够处理对应基本类型的数组:

⚫ public static IntStream stream(int[] array)

⚫ public static LongStream stream(long[] array)

⚫ public static DoubleStream stream(double[] array)

(2)由值创建流

可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。

⚫ public static Stream of(T… values) : 返回一个流

(3)由函数创建流:创建无限流

可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流。

⚫ 迭代

public static Stream iterate(final T seed, final

UnaryOperator f)

⚫ 生成

public static Stream generate(Supplier s) :

代码举例:

@Test
    public void test06(){

        //1.可以通过Collection系列集合提供的stream()或parallelStream()
        //集合流:
        // - Collection.stream() 穿行流
        // - Collection.parallelStream() 并行流
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();
        
        //2.通过Arrays中的静态方法stream()获取数组连接
        //Arrays.stream(array)
        String[] strings = new String[10];
        Stream<String> stream2 = Arrays.stream(strings);

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

        //4.创建无限流
        //迭代
        Stream<Integer> stream4 = Stream.iterate(0, (i) -> i+2);
        stream4.limit(10).forEach(System.out::println);
        //生成
        Stream.generate(() -> Math.random())
                .limit(5)
                .forEach(System.out::println);
    }


4.Stream中间操作

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

(1)筛选与切片

  • 内部迭代:迭代操作由 Stream API 完成

  • 外部迭代:我们通过迭代器完成

(2)映射

  • map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
@Test
    public void test08(){
        List<String> list = Arrays.asList("a", "b", "c");
        list.stream()
                .map((str) -> str.toUpperCase())
                .forEach(System.out::println);
    }

  • flatMap:接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流
public class Tests {
    public Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for (char c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }
}
@Test
public void test09(){
    List<String> list = Arrays.asList("aaa", "bbb", "ccc");
    Tests tests = new Tests();
    list.stream()
            .flatMap(tests::filterCharacter)
            .forEach(System.out::println);
}

结果:

a
a
a
b
b
b
c
c
c

===============================================
Default Suite
Total tests run: 1, Passes: 1, Failures: 0, Skips: 0
===============================================

(3)排序

方法描述
sorted()产生一个新流,其中按自然顺序排序
sorted(Comparator comp)产生一个新流,其中按比较器顺序排序

**sorted()**自然排序

@Test
    public void test10(){
        List<String> list = Arrays.asList("c", "a", "b");
        list.stream()
                .sorted()
                .forEach(System.out::println);
    }

结果:

a
b
c

===============================================
Default Suite
Total tests run: 1, Passes: 1, Failures: 0, Skips: 0
===============================================

进程已结束,退出代码0

sorted(Comparator comp) 比较器顺序排序

@Test
    public void test05(){
        emps.stream()
                .sorted((e1, e2) -> { //compara()
                    if (e1.getAge().equals(e2.getAge())){
                        return e1.getName().compareTo(e2.getName());
                    } else {
                        return e1.getAge().compareTo(e2.getAge());
                    }
                })
                .forEach(System.out::println);
    }

5.Stream的终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。

(1)查找与匹配

方法描述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zpJIIb7C-1649521532199)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220407154558408.png)]

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

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

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

  • findFirst:返回第一个元素

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

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

  • max:返回流中最大值

  • min:返回流中最小值

@Test
public void test01(){
    List<Status> list = Arrays.asList(Status.FREE, Status.BUSY, Status.VOCATION);

    boolean flag1 = list.stream()
        .allMatch((s) -> s.equals(Status.BUSY));
    System.out.println(flag1);

    boolean flag2 = list.stream()
        .anyMatch((s) -> s.equals(Status.BUSY));
    System.out.println(flag2);

    boolean flag3 = list.stream()
        .noneMatch((s) -> s.equals(Status.BUSY));
    System.out.println(flag3);

    // 避免空指针异常
    Optional<Status> op1 = list.stream()
        .findFirst();
    // 如果Optional为空 找一个替代的对象
    Status s1 = op1.orElse(Status.BUSY);
    System.out.println(s1);

    Optional<Status> op2 = list.stream()
        .findAny();
    System.out.println(op2);

    long count = list.stream()
        .count();
    System.out.println(count);
}

(2)归约

备注:map 和 reduce 的连接通常称为map-reduce 模式,因 Google 用它来进行网络搜索而出名。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZE8zIeHc-1649521532200)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220407180925241.png)]

@Test
public void test01(){
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        Integer integer = list.stream()
                .reduce(0, (x, y) -> x + y);
        System.out.println(integer);
}

结果:

45

===============================================
Default Suite
Total tests run: 1, Passes: 1, Failures: 0, Skips: 0
===============================================


进程已结束,退出代码0

(3)收集

方法描述
collect(Collector c)将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

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


代码举例:


1.收集到List
public class Test5 {

    List<Employee> emps = Arrays.asList(
            new Employee(101, "Z3", 19, 9999.99),
            new Employee(102, "L4", 20, 7777.77),
            new Employee(103, "W5", 35, 6666.66),
            new Employee(104, "Tom", 44, 1111.11),
            new Employee(105, "Jerry", 60, 4444.44)
    );
    @Test
    public void test01(){
        List<String> list = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);
    }

2.收集到set
public class Test5 {

    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 9999.99),
            new Employee(102, "李四", 20, 7777.77),
            new Employee(103, "王五", 35, 6666.66),
            new Employee(104, "Jerry", 44, 1111.11),
            new Employee(105, "Jerry", 60, 4444.44)
    );

    @Test
    public void test02(){
        Set<String> set = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
        set.forEach(System.out::println);
    }
}

3.放入HashSet
public class Test5 {
    
    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 9999.99),
            new Employee(102, "李四", 20, 7777.77),
            new Employee(103, "王五", 35, 6666.66),
            new Employee(104, "Jerry", 44, 1111.11),
            new Employee(105, "Jerry", 60, 4444.44)
    );
    @Test
    public void tests03(){
        //放入LinkedHashSet
        LinkedHashSet<String> linkedHashSet = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        linkedHashSet.forEach(System.out::println);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DLUvx5bm-1649521532201)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220408202133459.png)]

4.总数
public class Test5 {

    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 9999.99),
            new Employee(102, "李四", 20, 7777.77),
            new Employee(103, "王五", 35, 6666.66),
            new Employee(104, "Tom", 44, 1111.11),
            new Employee(105, "Jerry", 60, 4444.44)

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

5.平均值
List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)

    );
    @Test
    public void test(){
        //平均值
        Double avg = emps.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(avg);
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lhLcc6zq-1649521532202)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220408202629418.png)]

6.总和
public class Test5 {

    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)

    );
    @Test
    public void test(){
        //总和
        Double sum = emps.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(sum);
	}
}

7.最大值
public class Test5 {
    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)
    );
    @Test
    public void test(){
        //最大值
        Optional<Employee> max = emps.stream()
                .collect(Collectors.maxBy((e1, e2) -> Doublepare(e1.getSalary(), e2.getSalary())));
        System.out.println(max.get());
        }
}

8.最小值
public class Test5 {

    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)

    );
    @Test
    public void test(){

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AcESZB3s-1649521532203)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220408203048076.png)]

9.分组
public class Test5 {
    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)
    );
    @Test
    public void tests(){
        //分组
        Map<Integer, List<Employee>> map = emps.stream()
                .collect(Collectors.groupingBy(Employee::getId));
        //输出Map
        System.out.println(map);
        System.out.println("------------------------------------------------------");
        //遍历Map
        map.values().forEach(System.out::println);
	}
}

10.多级分组
public class Test5 {
    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)

    );
    @Test
    public void tests(){
        //多级分组
        Map<Integer, Map<String, List<Employee>>> mapMap = emps.stream()
                .collect(Collectors.groupingBy(Employee::getId, Collectors.groupingBy((e) -> {
                    if (e.getAge() > 35) {
                        return "开除";
                    } else {
                        return "继续加班";
                    }
                })));
        System.out.println(mapMap);
        //遍历Map
        mapMap.values().forEach(System.out::println);
    }
}

11.分层
true/false
public class Test5 {

    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)

    );
    @Test
    public void tests(){
        //分区
        Map<Boolean, List<Employee>> listMap = emps.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() > 4321));
        System.out.println(listMap);

    }
}

结果:
{false=[], true=[Employee [id=101, name=张三, age=19, salary=10000.0], Employee [id=102, name=李四, age=20, salary=20000.0], Employee [id=103, name=王五, age=35, salary=30000.0], Employee [id=104, name=Tom, age=44, salary=40000.0], Employee [id=105, name=Jerry, age=60, salary=50000.0]]}

12.总结
public class Test5 {

    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)

    );

    @Test
    public void test05(){
        //总结
        DoubleSummaryStatistics dss = emps.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(dss.getMax());
        System.out.println(dss.getMin());
        System.out.println(dss.getSum());
        System.out.println(dss.getCount());
        System.out.println(dss.getAverage());
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cAzuAC2C-1649521532204)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220408205231325.png)]

13.连接
public class Test5 {

    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)

    );
    @Test
    public void test05(){
        //连接
        String str = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.joining("-")); //可传入分隔符
        System.out.println(str);
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nQqEQAUs-1649521532204)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220408205329113.png)]

6.案例

(1)给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?(如:给定【1,2,3,4,5】,返回【1,4,9,16,25】)

@Test
public void test01(){
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    list.stream()
        .map((x) -> x * x)
        .forEach(System.out::println);
}

(2)怎样使用 map 和 reduce 数一数流中有多少个 Employee 呢?

public class Test5 {
    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 19, 10000),
            new Employee(102, "李四", 20,20000),
            new Employee(103, "王五", 35, 30000),
            new Employee(104, "Tom", 44, 40000),
            new Employee(105, "Jerry", 60, 50000)

    );
    @Test
    public void test02(){
        Optional<Integer> result = emps.stream()
                .map((e) -> 1)
                .reduce(Integer::sum);
        System.out.println(result.get());
    }
}

七.并行流与串行流

1.简介

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。

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

2.了解 Fork/Join 框架

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

3.Fork/Join 框架与传统线程池的区别

采用 “工作窃取”模式(work-stealing):当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程的等待时间,提高了性能.

4.Fork/Join的实现

在实现前要继承一个类

RecursiveTask(有返回值)

或者

RecursiveAction(无返回值)

Recursive(英文翻译:递归)

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并行流/串行流

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

}

八.Optional

1.定义:

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

2.常用方法:

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

  2. Optional.empty(T t):创建一个空的 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):如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.empty()

  8. flatmap(Function mapper):与 map 相似,要求返回值必须是 Optional

(1)Optional.of

创建一个 Optional 实例

(此代码中未传递任何值)

在构造过程中Optional.of(null);会发生空指针异常

 @Test
    public void test01(){
        Optional<Employee> op = Optional.of(new Employee());
        Employee employee = op.get();
        System.out.println(employee);
    }

(2)Optional.empty

创建一个空的 Optional 实例

@Test
    public void test01(){
        Optional<Employee> op = Optional.empty();

        System.out.println(op.get());
    }

此代码会发生空指针异常

(3)Optional.ofNullable

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

@Test
    public void test01(){
        Optional<Employee> op = Optional.ofNullable(null);
        System.out.println(op.get());
    }
(4)isPresent

isPresent():判断是否包含某值

@Test
    public void test03(){
        Optional<Employee> op = Optional.ofNullable(new Employee());
        if (op.isPresent()) {
            System.out.println(op.get());
        }
        else {
            System.out.println("null");
        }
    }

public class Test5 {
    @Test
    public void test03(){
        Optional<Employee> op = Optional.ofNullable(null);
        if (op.isPresent()) {
            System.out.println(op.get());
        }else {
            System.out.println("null");
        }
    }
}

(5)orElse

orElse(T t):如果调用对象包含值,返回该值,否则返回 t

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

        Employee employee = op.orElse(new Employee(101, "张三", 19, 9999.99));
        System.out.println(employee);
    }
}

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

        Employee employee = op.orElse(new Employee(101, "张三", 19, 9999.99));
        System.out.println(employee);
    }
}

(6)orElseGet

orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回 s 获取的值

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

        Employee employee = op.orElseGet(()->new Employee());

        System.out.println(employee);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Gotdzf9-1649521532207)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220408224508823.png)]

(7)map

map(Function f):如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.empty()

public class Test5 {
    @Test
    public void test03(){
        Optional<Employee> op = Optional.ofNullable(new Employee(101, "张三", 19, 9999.99));

        Optional<String> str = op.map((e -> e.getName()));
        System.out.println(str);
    }
}

(8)flatmap

flatmap(Function mapper):与 map 相似,要求返回值必须是 Optional

public class Test5 {
    @Test
    public void test03(){
        Optional<Employee> op = Optional.ofNullable(new Employee(101, "张三", 19, 9999.99));

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q7CIqzZc-1649521532208)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220408225128991.png)]


九.接口

默认方法

public interface MyFun {

    default String getName(){
        return "libo";
    }

    default Integer getAge(){
        return 22;
    }
}

类优先原则:

静态方法

public interface MyFun {

    static void getAddr(){
        System.out.println("addr");
    }

    static String Hello(){
        return "Hello World";
    }
}

十.新时间日期API

1.与传统日期处理的转换

传统的日期格式化:

public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return DateFormatThreadLocal.convert("20161218");
            }
        };
        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> future : result) {

            System.out.println(future.get());

        }
    }

程序运行报错

解决方法:

上锁:

public class Test5 {

    public class DateFormatThreadLocal {
        private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){
            protected DateFormat initialValue(){
                return new SimpleDateFormat("yyyyMMdd");
            }
        };

        public static Date convert(String source) throws ParseException{
            return df.get().parse(source);
        }
    }
    
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return DateFormatThreadLocal.convert("20161218");
            }
        };
        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> future : result) {

            System.out.println(future.get());

        }
    }
}

Java8DataTimeFormatter:

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

        Callable<LocalDate> task = new Callable<LocalDate>() {

            @Override
            public LocalDate call()throws ExecutionException {
                return LocalDate.parse("20161218",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> future : result) {

            System.out.println(future.get());
        }
        pool.shutdown();
    }

2.使用LocalDate、LocalTime、LocalDateTime

LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信 息。也不包含与时区相关的信息。

注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法

(1)获取当前时间

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

结果:

2022-04-09T23:04:33.948455500

(2)时间加减运算

加:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5KRdtdB7-1649521532209)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220409230746965.png)]

@Test
    public void test1(){
        LocalDateTime dateTime = LocalDateTime.now();
        System.out.println(dateTime);
        LocalDateTime dateTime1 = dateTime.plusYears(2);
        System.out.println(dateTime1);
    }

减:

 @Test
    public void test1(){
        LocalDateTime dateTime = LocalDateTime.now();
        System.out.println(dateTime);
        LocalDateTime dateTime1 = dateTime.minusYears(2);
        System.out.println(dateTime1);
    }

(3)获取年 月 时 分 秒

@Test
    public void test1(){
        LocalDateTime dateTime = LocalDateTime.now();
        System.out.println(dateTime);
        //获取年
        System.out.println(dateTime.getYear());
        //获取月(英语)
        System.out.println(dateTime.getMonth());
        //获取今年的已过天数
        System.out.println(dateTime.getDayOfYear());
        //获取今天月份的值
        System.out.println(dateTime.getMonthValue());
        //获取小时
        System.out.println(dateTime.getHour());
        //获取分
        System.out.println(dateTime.getMinute());
        //获取秒
        System.out.println(dateTime.getSecond());
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LWA89GeP-1649521532211)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220409231718228.png)]

3.Instant时间戳

用于“时间戳”的运算。它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算

@Test
    public void test1(){
        Instant instant = Instant.now();//默认获取UTC时区
        System.out.println(instant);

        OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);

        System.out.println("时间戳:"+instant.toEpochMilli());
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8mDYYr3r-1649521532211)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220409235313519.png)]

4.Duration:用于计算两个“时间”间隔

public class Test5 {
    @Test
    public void test1()  {
        Instant instant = Instant.now();//默认获取UTC时区
        //系统等待1000毫秒
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {

        }

        Instant instant1 = Instant.now();

        Duration duration = Duration.between(instant,instant1);
        //精确到毫秒
        System.out.println(duration);
        //精确到天
        System.out.println(duration.toDays());


        LocalTime localTime = LocalTime.now();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        LocalTime localTime1 = LocalTime.now();

      System.out.println(Duration.between(localTime,localTime1).toMillis());
    }
}

5. Period:用于计算两个“日期”间隔

@Test
    public void test1()  {
       LocalDate localDate = LocalDate.of(2015,1,1);
       LocalDate localDate1 = LocalDate.now();
       Period period = Period.between(localDate,localDate1);
       System.out.println(period);
       System.out.println(period.getYears());
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gz4nwKDf-1649521532212)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220410000610842.png)]

6.日期的操纵

(1)时间校正器

TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。

TemporalAdjusters: 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现。

例如获取下个周日:

@Test
    public void test01(){
        //TemporalAdjusters:时间校正器
        LocalDateTime ldt1 = LocalDateTime.now();
        System.out.println(ldt1);

        //指定日期时间中的 年 月 日 ...
        LocalDateTime ldt2 = ldt1.withDayOfMonth(10);
        System.out.println(ldt2);

        //指定时间校正器
        LocalDateTime ldt3 = ldt1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        System.out.println(ldt3);

        //自定义时间校正器
        LocalDateTime ldt5 = ldt1.with((ta) -> {
            LocalDateTime ldt4 = (LocalDateTime) ta;
            DayOfWeek dow1 = ldt4.getDayOfWeek();
            if (dow1.equals(DayOfWeek.FRIDAY)) {
                return ldt4.plusDays(3);
            } else if (dow1.equals(DayOfWeek.SATURDAY)) {
                return ldt4.plusDays(2);
            } else {
                return ldt4.plusDays(1);
            }
        });
        System.out.println(ldt5);
    }

7.时间格式化

java.time.format.DateTimeFormatter类:该类提供了三种

格式化方法:

⚫ 预定义的标准格式

⚫ 语言环境相关的格式

⚫ 自定义的格式

@Test
    public void test01(){
        //默认格式化
        DateTimeFormatter dtf1 = DateTimeFormatter.ISO_DATE_TIME;
        LocalDateTime ldt1 = LocalDateTime.now();
        String str1 = ldt1.format(dtf1);
        System.out.println(str1);

        //自定义格式化 ofPattern
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime ldt2 = LocalDateTime.now();
        String str2 = ldt2.format(dtf2);
        System.out.println(str2);

        //解析
        LocalDateTime newDate = ldt1.parse(str1, dtf1);
        System.out.println(newDate);
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YmZqTqXf-1649521532213)(https://gitee/yan-chaochao/typora-library/raw/master/typora-library/image-20220410001413337.png)]

8.时区的处理

Java8 中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime其中每个时区都对应着 ID,地区ID都为 “{区域}/{城市}”的格式

例如 :Asia/Shanghai 等

ZoneId:该类中包含了所有的时区信息

getAvailableZoneIds() : 可以获取所有时区时区信息

of(id) : 用指定的时区信息获取ZoneId 对象

@Test
    public void test02(){
        //查看支持的时区
        Set<String> set = ZoneId.getAvailableZoneIds();
        set.forEach(System.out::println);

        //指定时区
        LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
        System.out.println(ldt1);

        //在已构建好的日期时间上指定时区
        LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
        ZonedDateTime zdt1 = ldt2.atZone(ZoneId.of("Europe/Tallinn"));
        System.out.println(zdt1);
    }

结果:

Asia/Aden
America/Cuiaba
Etc/GMT+9
Etc/GMT+8
Africa/Nairobi
America/Marigot
Asia/Aqtau
Pacific/Kwajalein
America/El_Salvador
Asia/Pontianak
Africa/Cairo
Pacific/Pago_Pago
Africa/Mbabane
Asia/Kuching
Pacific/Honolulu
Pacific/Rarotonga
America/Guatemala
Australia/Hobart
Europe/London
America/Belize
America/Panama
Asia/Chungking
America/Managua
America/Indiana/Petersburg
Asia/Yerevan
Europe/Brussels
GMT
Europe/Warsaw
America/Chicago
Asia/Kashgar
Chile/Continental
Pacific/Yap
CET
Etc/GMT-1
Etc/GMT-0
Europe/Jersey
America/Tegucigalpa
Etc/GMT-5
Europe/Istanbul
America/Eirunepe
Etc/GMT-4
America/Miquelon
Etc/GMT-3
Europe/Luxembourg
Etc/GMT-2
Etc/GMT-9
America/Argentina/Catamarca
Etc/GMT-8
Etc/GMT-7
Etc/GMT-6
Europe/Zaporozhye
Canada/Yukon
Canada/Atlantic
Atlantic/St_Helena
Australia/Tasmania
Libya
Europe/Guernsey
America/Grand_Turk
Asia/Samarkand
America/Argentina/Cordoba
Asia/Phnom_Penh
Africa/Kigali
Asia/Almaty
US/Alaska
Asia/Dubai
Europe/Isle_of_Man
America/Araguaina
Cuba
Asia/Novosibirsk
America/Argentina/Salta
Etc/GMT+3
Africa/Tunis
Etc/GMT+2
Etc/GMT+1
Pacific/Fakaofo
Africa/Tripoli
Etc/GMT+0
Israel
Africa/Banjul
Etc/GMT+7
Indian/Comoro
Etc/GMT+6
Etc/GMT+5
Etc/GMT+4
Pacific/Port_Moresby
US/Arizona
Antarctica/Syowa
Indian/Reunion
Pacific/Palau
Europe/Kaliningrad
America/Montevideo
Africa/Windhoek
Asia/Karachi
Africa/Mogadishu
Australia/Perth
Brazil/East
Etc/GMT
Asia/Chita
Pacific/Easter
Antarctica/Davis
Antarctica/McMurdo
Asia/Macao
America/Manaus
Africa/Freetown
Europe/Bucharest
Asia/Tomsk
America/Argentina/Mendoza
Asia/Macau
Europe/Malta
Mexico/BajaSur
Pacific/Tahiti
Africa/Asmera
Europe/Busingen
America/Argentina/Rio_Gallegos
Africa/Malabo
Europe/Skopje
America/Catamarca
America/Godthab
Europe/Sarajevo
Australia/ACT
GB-Eire
Africa/Lagos
America/Cordoba
Europe/Rome
Asia/Dacca
Indian/Mauritius
Pacific/Samoa
America/Regina
America/Fort_Wayne
America/Dawson_Creek
Africa/Algiers
Europe/Mariehamn
America/St_Johns
America/St_Thomas
Europe/Zurich
America/Anguilla
Asia/Dili
America/Denver
Africa/Bamako
Europe/Saratov
GB
Mexico/General
Pacific/Wallis
Europe/Gibraltar
Africa/Conakry
Africa/Lubumbashi
Asia/Istanbul
America/Havana
NZ-CHAT
Asia/Choibalsan
America/Porto_Acre
Asia/Omsk
Europe/Vaduz
US/Michigan
Asia/Dhaka
America/Barbados
Europe/Tiraspol
Atlantic/Cape_Verde
Asia/Yekaterinburg
America/Louisville
Pacific/Johnston
Pacific/Chatham
Europe/Ljubljana
America/Sao_Paulo
Asia/Jayapura
America/Curacao
Asia/Dushanbe
America/Guyana
America/Guayaquil
America/Martinique
Portugal
Europe/Berlin
Europe/Moscow
Europe/Chisinau
America/Puerto_Rico
America/Rankin_Inlet
Pacific/Ponape
Europe/Stockholm
Europe/Budapest
America/Argentina/Jujuy
Australia/Eucla
Asia/Shanghai
Universal
Europe/Zagreb
America/Port_of_Spain
Europe/Helsinki
Asia/Beirut
Asia/Tel_Aviv
Pacific/Bougainville
US/Central
Africa/Sao_Tome
Indian/Chagos
America/Cayenne
Asia/Yakutsk
Pacific/Galapagos
Australia/North
Europe/Paris
Africa/Ndjamena
Pacific/Fiji
America/Rainy_River
Indian/Maldives
Australia/Yancowinna
SystemV/AST4
Asia/Oral
America/Yellowknife
Pacific/Enderbury
America/Juneau
Australia/Victoria
America/Indiana/Vevay
Asia/Tashkent
Asia/Jakarta
Africa/Ceuta
Asia/Barnaul
America/Recife
America/Buenos_Aires
America/Noronha
America/Swift_Current
Australia/Adelaide
America/Metlakatla
Africa/Djibouti
America/Paramaribo
Asia/Qostanay
Europe/Simferopol
Europe/Sofia
Africa/Nouakchott
Europe/Prague
America/Indiana/Vincennes
Antarctica/Mawson
America/Kralendijk
Antarctica/Troll
Europe/Samara
Indian/Christmas
America/Antigua
Pacific/Gambier
America/Indianapolis
America/Inuvik
America/Iqaluit
Pacific/Funafuti
UTC
Antarctica/Macquarie
Canada/Pacific
America/Moncton
Africa/Gaborone
Pacific/Chuuk
Asia/Pyongyang
America/St_Vincent
Asia/Gaza
Etc/Universal
PST8PDT
Atlantic/Faeroe
Asia/Qyzylorda
Canada/Newfoundland
America/Kentucky/Louisville
America/Yakutat
Asia/Ho_Chi_Minh
Antarctica/Casey
Europe/Copenhagen
Africa/Asmara
Atlantic/Azores
Europe/Vienna
ROK
Pacific/Pitcairn
America/Mazatlan
Australia/Queensland
Pacific/Nauru
Europe/Tirane
Asia/Kolkata
SystemV/MST7
Australia/Canberra
MET
Australia/Broken_Hill
Europe/Riga
America/Dominica
Africa/Abidjan
America/Mendoza
America/Santarem
Kwajalein
America/Asuncion
Asia/Ulan_Bator
NZ
America/Boise
Australia/Currie
EST5EDT
Pacific/Guam
Pacific/Wake
Atlantic/Bermuda
America/Costa_Rica
America/Dawson
Asia/Chongqing
Eire
Europe/Amsterdam
America/Indiana/Knox
America/North_Dakota/Beulah
Africa/Accra
Atlantic/Faroe
Mexico/BajaNorte
America/Maceio
Etc/UCT
Pacific/Apia
GMT0
America/Atka
Pacific/Niue
Australia/Lord_Howe
Europe/Dublin
Pacific/Truk
MST7MDT
America/Monterrey
America/Nassau
America/Jamaica
Asia/Bishkek
America/Atikokan
Atlantic/Stanley
Australia/NSW
US/Hawaii
SystemV/CST6
Indian/Mahe
Asia/Aqtobe
America/Sitka
Asia/Vladivostok
Africa/Libreville
Africa/Maputo
Zulu
America/Kentucky/Monticello
Africa/El_Aaiun
Africa/Ouagadougou
America/Coral_Harbour
Pacific/Marquesas
Brazil/West
America/Aruba
America/North_Dakota/Center
America/Cayman
Asia/Ulaanbaatar
Asia/Baghdad
Europe/San_Marino
America/Indiana/Tell_City
America/Tijuana
Pacific/Saipan
SystemV/YST9
Africa/Douala
America/Chihuahua
America/Ojinaga
Asia/Hovd
America/Anchorage
Chile/EasterIsland
America/Halifax
Antarctica/Rothera
America/Indiana/Indianapolis
US/Mountain
Asia/Damascus
America/Argentina/San_Luis
America/Santiago
Asia/Baku
America/Argentina/Ushuaia
Atlantic/Reykjavik
Africa/Brazzaville
Africa/Porto-Novo
America/La_Paz
Antarctica/DumontDUrville
Asia/Taipei
Antarctica/South_Pole
Asia/Manila
Asia/Bangkok
Africa/Dar_es_Salaam
Poland
Atlantic/Madeira
Antarctica/Palmer
America/Thunder_Bay
Africa/Addis_Ababa
Asia/Yangon
Europe/Uzhgorod
Brazil/DeNoronha
Asia/Ashkhabad
Etc/Zulu
America/Indiana/Marengo
America/Creston
America/Punta_Arenas
America/Mexico_City
Antarctica/Vostok
Asia/Jerusalem
Europe/Andorra
US/Samoa
PRC
Asia/Vientiane
Pacific/Kiritimati
America/Matamoros
America/Blanc-Sablon
Asia/Riyadh
Iceland
Pacific/Pohnpei
Asia/Ujung_Pandang
Atlantic/South_Georgia
Europe/Lisbon
Asia/Harbin
Europe/Oslo
Asia/Novokuznetsk
CST6CDT
Atlantic/Canary
America/Knox_IN
Asia/Kuwait
SystemV/HST10
Pacific/Efate
Africa/Lome
America/Bogota
America/Menominee
America/Adak
Pacific/Norfolk
Europe/Kirov
America/Resolute
Pacific/Tarawa
Africa/Kampala
Asia/Krasnoyarsk
Greenwich
SystemV/EST5
America/Edmonton
Europe/Podgorica
Australia/South
Canada/Central
Africa/Bujumbura
America/Santo_Domingo
US/Eastern
Europe/Minsk
Pacific/Auckland
Africa/Casablanca
America/Glace_Bay
Canada/Eastern
Asia/Qatar
Europe/Kiev
Singapore
Asia/Magadan
SystemV/PST8
America/Port-au-Prince
Europe/Belfast
America/St_Barthelemy
Asia/Ashgabat
Africa/Luanda
America/Nipigon
Atlantic/Jan_Mayen
Brazil/Acre
Asia/Muscat
Asia/Bahrain
Europe/Vilnius
America/Fortaleza
Etc/GMT0
US/East-Indiana
America/Hermosillo
America/Cancun
Africa/Maseru
Pacific/Kosrae
Africa/Kinshasa
Asia/Kathmandu
Asia/Seoul
Australia/Sydney
America/Lima
Australia/LHI
America/St_Lucia
Europe/Madrid
America/Bahia_Banderas
America/Montserrat
Asia/Brunei
America/Santa_Isabel
Canada/Mountain
America/Cambridge_Bay
Asia/Colombo
Australia/West
Indian/Antananarivo
Australia/Brisbane
Indian/Mayotte
US/Indiana-Starke
Asia/Urumqi
US/Aleutian
Europe/Volgograd
America/Lower_Princes
America/Vancouver
Africa/Blantyre
America/Rio_Branco
America/Danmarkshavn
America/Detroit
America/Thule
Africa/Lusaka
Asia/Hong_Kong
Iran
America/Argentina/La_Rioja
Africa/Dakar
SystemV/CST6CDT
America/Tortola
America/Porto_Velho
Asia/Sakhalin
Etc/GMT+10
America/Scoresbysund
Asia/Kamchatka
Asia/Thimbu
Africa/Harare
Etc/GMT+12
Etc/GMT+11
Navajo
America/Nome
Europe/Tallinn
Turkey
Africa/Khartoum
Africa/Johannesburg
Africa/Bangui
Europe/Belgrade
Jamaica
Africa/Bissau
Asia/Tehran
WET
Europe/Astrakhan
Africa/Juba
America/Campo_Grande
America/Belem
Etc/Greenwich
Asia/Saigon
America/Ensenada
Pacific/Midway
America/Jujuy
Africa/Timbuktu
America/Bahia
America/Goose_Bay
America/Virgin
America/Pangnirtung
Asia/Katmandu
America/Phoenix
Africa/Niamey
America/Whitehorse
Pacific/Noumea
Asia/Tbilisi
America/Montreal
Asia/Makassar
America/Argentina/San_Juan
Hongkong
UCT
Asia/Nicosia
America/Indiana/Winamac
SystemV/MST7MDT
America/Argentina/ComodRivadavia
America/Boa_Vista
America/Grenada
Asia/Atyrau
Australia/Darwin
Asia/Khandyga
Asia/Kuala_Lumpur
Asia/Famagusta
Asia/Thimphu
Asia/Rangoon
Europe/Bratislava
Asia/Calcutta
America/Argentina/Tucuman
Asia/Kabul
Indian/Cocos
Japan
Pacific/Tongatapu
America/New_York
Etc/GMT-12
Etc/GMT-11
America/Nuuk
Etc/GMT-10
SystemV/YST9YDT
Europe/Ulyanovsk
Etc/GMT-14
Etc/GMT-13
W-SU
America/Merida
EET
America/Rosario
Canada/Saskatchewan
America/St_Kitts
Arctic/Longyearbyen
America/Fort_Nelson
America/Caracas
America/Guadeloupe
Asia/Hebron
Indian/Kerguelen
SystemV/PST8PDT
Africa/Monrovia
Asia/Ust-Nera
Egypt
Asia/Srednekolymsk
America/North_Dakota/New_Salem
Asia/Anadyr
Australia/Melbourne
Asia/Irkutsk
America/Shiprock
America/Winnipeg
Europe/Vatican
Asia/Amman
Etc/UTC
SystemV/AST4ADT
Asia/Tokyo
America/Toronto
Asia/Singapore
Australia/Lindeman
America/Los_Angeles
SystemV/EST5EDT
Pacific/Majuro
America/Argentina/Buenos_Aires
Europe/Nicosia
Pacific/Guadalcanal
Europe/Athens
US/Pacific
Europe/Monaco
2022-04-09T19:15:34.387271300
2022-04-09T19:15:34.388271900+03:00[Europe/Tallinn]

===============================================
Default Suite
Total tests run: 1, Passes: 1, Failures: 0, Skips: 0
===============================================


进程已结束,退出代码0

与传统日期处理的转换

@Test
    public void test03(){
        // Date 转 LocalDateTime 
        Date date = new Date();
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();

        // LocalDateTime 转 Date
        LocalDateTime localDateTime = LocalDateTime.now();
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        Date date = Date.from(zdt.toInstant());

        // 原则:利用 时间戳Instant
    }

十一.重复注解与类型注解

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

型的注解。

重复注解

定义注解:

@Repeatable(MyAnnotations.class) //指定容器类
@Target({ElementType.TYPE, ElementType.METHOD,  ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "Java 8";
}

定义容器:

@Target({ElementType.TYPE, ElementType.METHOD,  ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {

    MyAnnotation[] value();

}
  @Testpublic class Test01 {
    //重复注解
    @Test
    @MyAnnotation("Hello")
    @MyAnnotation("World")
    public void test01() throws NoSuchMethodException {
        Class<Test01> clazz = Test01.class;
        Method test01 = clazz.getMethod("test01");
        MyAnnotation[] mas = test01.getAnnotationsByType(MyAnnotation.class);
        for (MyAnnotation ma : mas) {
            System.out.println(ma.value());
        }
    }

类型注解

Java 8 新增注解:新增ElementType.TYPE_USE 和ElementType.TYPE_PARAMETER(在Target上)

更多推荐

Java 8的新特性(入门)