从Java 8到 Java 17–Java 8

/ 0评 / 0

想必绝大部分项目还在运行着Java8。接下来就开始梳理一下吧。

Java8 优势:速度快、代码更少(增加了新的语法 Lambda 表达式)、强大的 Stream API、便于并行、最大化减少空指针异常 Optional;

一、Lambda 表达式

Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以取代大部分的匿名内部类,可以写出更简洁、更灵活的代码。尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。作为一种更紧凑的代码风格,使 Java 的语言表达能力得到提升。JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。

1.lambda 表达式的语法格式如下:

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

  1. 左侧:指定了 Lambda 表达式需要的所有参数;
  2. 右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能;

lambda 表达式的语法格式如下:

(parameters) -> expression或(parameters) ->{statements; }

如下列demo:

// 1. 不需要参数,返回值为 5  
() -> 5  

// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  

// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  

// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  

// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

假设有一个玩家List ,程序员可以使用 for 语句 ("for 循环")来遍历,在Java SE 8中可以转换为另一种形式:

String[] atp = {"a","b","c"};
// 以前
List<String> list = Arrays.asList(atp);
for (String s : list) {
    System.out.println("s:"+s);
}

// 使用 lambda 表达式以及函数操作(functional operation)
list.forEach(s -> System.out.println("s:"+s));
// 在 Java 8 中使用双冒号操作符(double colon operator)
list.forEach(System.out::println);

2.从匿名类到 Lambda 的转换:

虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用 Lambda 表达式来实现。Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法。

        //匿名内部类
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World!");
            }
        };
        //Lambda表达式
        /**
         *1.简化参数类型,可以不写参数类型,但是必须所有参数都不写
         *2.简化参数小括号,如果只有一个参数则可以省略参数小括号
         *3.简化方法体大括号,如果方法条只有一条语句,则可以胜率方法体大括号(如下案例)
         *4.如果方法体只有一条语句,并且是 return 语句,则可以省略方法体大括号和rerun关键字:X x= a -> a+3;
         *Lambda 表达式展示:
         */
        Runnable runnable2 = () -> System.out.println("Lambda 表达式");

3.原来使用匿名内部类作为参数传递到 Lambda 表达式

//原来使用匿名内部类作为参数传递
TreeSet ts = new TreeSet<>(new Comparator<String>() {

    @Override
    public int compare(String o1, String o2) {
        return Integer.compare(o1.length(),o2.length());
    }
});

//Lambda 表达式作为参数传递
TreeSet<String> ts2 = new TreeSet<>((o1,o2)-> Integer.compare(o1.length(),o2.length()));

二、函数式接口

函数式接口(FunctionalInterface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

函数式接口可以被隐式转换为lambda表达式。

函数式接口可以现有的函数友好地支持 lambda。

JDK 1.8之前已有的函数式接口:

java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener

JDK 1.8 新增加的函数接口:

java.util.function

java.util.function 它包含了很多类,用来支持 Java的函数式编程,该包中的函数式接口有:

BiConsumer<T,U>
//代表了一个接受两个输入参数的操作,并且不返回任何结果

BiFunction<T,U,R>
//代表了一个接受两个输入参数的方法,并且返回一个结果

BinaryOperator<T>
//代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果

BiPredicate<T,U>
//代表了一个两个参数的boolean值方法

BooleanSupplier
//代表了boolean值结果的提供方

Consumer<T>
//代表了接受一个输入参数并且无返回的操作

DoubleBinaryOperator
//代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。

DoubleConsumer
//代表一个接受double值参数的操作,并且不返回结果。

DoubleFunction<R>
//代表接受一个double值参数的方法,并且返回结果

DoublePredicate
//代表一个拥有double值参数的boolean值方法

DoubleSupplier
//代表一个double值结构的提供方

DoubleToIntFunction
//接受一个double类型输入,返回一个int类型结果。

DoubleToLongFunction
//接受一个double类型输入,返回一个long类型结果

DoubleUnaryOperator
//接受一个参数同为类型double,返回值类型也为double。

Function<T,R>
//接受一个输入参数,返回一个结果。

IntBinaryOperator
//接受两个参数同为类型int,返回值类型也为int 。

IntConsumer
//接受一个int类型的输入参数,无返回值。

IntFunction<R>
//接受一个int类型输入参数,返回一个结果。

IntPredicate
//接受一个int输入参数,返回一个布尔值的结果。

IntSupplier
//无参数,返回一个int类型结果。

IntToDoubleFunction
//接受一个int类型输入,返回一个double类型结果。

IntToLongFunction
//接受一个int类型输入,返回一个long类型结果。

IntUnaryOperator
//接受一个参数同为类型int,返回值类型也为int 。

LongBinaryOperator
//接受两个参数同为类型long,返回值类型也为long。

LongConsumer
//接受一个long类型的输入参数,无返回值。

LongFunction<R>
//接受一个long类型输入参数,返回一个结果。

LongPredicate
//接受一个long输入参数,返回一个布尔值类型结果。

LongSupplier
//无参数,返回一个结果long类型的值。

LongToDoubleFunction
//接受一个long类型输入,返回一个double类型结果。

LongToIntFunction
//接受一个long类型输入,返回一个int类型结果。

LongUnaryOperator
//接受一个参数同为类型long,返回值类型也为long。

ObjDoubleConsumer<T>
//接受一个object类型和一个double类型的输入参数,无返回值。

ObjIntConsumer<T>
//接受一个object类型和一个int类型的输入参数,无返回值。

ObjLongConsumer<T>
//接受一个object类型和一个long类型的输入参数,无返回值。

Predicate<T>
//接受一个输入参数,返回一个布尔值结果。

Supplier<T>
//无参数,返回一个结果。

ToDoubleBiFunction<T,U>
//接受两个输入参数,返回一个double类型结果

ToDoubleFunction<T>
//接受一个输入参数,返回一个double类型结果

ToIntBiFunction<T,U>
//接受两个输入参数,返回一个int类型结果。

ToIntFunction<T>
//接受一个输入参数,返回一个int类型结果。

ToLongBiFunction<T,U>
//接受两个输入参数,返回一个long类型结果。

ToLongFunction<T>
//接受一个输入参数,返回一个long类型结果。

UnaryOperator<T>
//接受一个参数为类型T,返回值类型也为T。

函数式接口实例:

Predicate 接口是一个函数式接口,它接受一个输入参数 T,返回一个布尔值结果。

public static void eval(List<Integer> list, Predicate<Integer> predicate) {
        for(Integer n: list) {
            if(predicate.test(n)) {
                System.out.println(n + " ");
            }
        }
    }

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        System.out.println("输出所有数据:");
        eval(list, n->true);

        System.out.println("输出所有偶数:");
        eval(list, n-> n%2 == 0 );

        System.out.println("输出大于 3 的所有数字:");
        eval(list, n-> n>3);
    }

三、默认方法

Java 8 新增了接口的默认方法。

简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。

我们只需在方法名前面加个default关键字即可实现默认方法。

语法格式如下:

public interface MyFunc {
    default void print(){
        System.out.println("Hello Java8!");
    }
}

多个默认方法:

若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时。
1.选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
2.接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法
是否是默认方法),那么必须覆盖该方法来解决冲突 。

1. 接口默认方法的”类优先”原则(使用 super 来调用指定接口的默认方法)

public class MyClass implements MyFunc,TInt{
    @Override
    public void print() {
        MyFunc.super.print();
    }
}

2.创建自己的默认方法,来覆盖重写接口的默认方法:

public class MyClass implements MyFunc,TInt{
    @Override
    public void print() {
        System.out.println("666");
    }
}

接口中的静态方法

Java8 中,接口中允许添加静态方法;

public interface MyFunc {
    static void Hi(){
        System.out.println("Hello!");
    }
    default void print(){
        System.out.println("Hello Java8!");
    }
}

四、方法引用

方法引用通过方法的名字来指向一个方法。

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用使用一对冒号:: 。如:

(x) -> System.out.println(x);
//等同于
System.out::println

compare((x,y) -> x.equals(y),"abcd","abcd");
//等同于
compare(String::equals,"abc","abc");

五、 Stream

什么是 Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

和以前的Collection操作不同, Stream操作还有两个基础的特征:

filter():对元素进行过滤
map():将流的元素映射成另一个类型
distinct():去除流中重复的元素
sorted():对元素进行排序
forEach :对流中的每个元素执行某个操作
peek():与forEach()方法效果类似,不同的是,该方法会返回一个新的流,而forEach()无返回
limit():截取流中前面几个元素
skip():跳过流中前面几个元素
toArray():将流转换为数组
reduce():对流中的元素归约操作,将每个元素合起来形成一个新的值
collect():对流的汇总操作,比如输出成List集合
anyMatch():匹配流中的元素,类似的操作还有allMatch()和noneMatch()方法
findFirst():查找第一个元素,类似的还有findAny()方法
max():求最大值
min():求最小值
count():求总数

流的操作类型

流的操作类型主要分为两种

在 Java 8 中, 集合接口有两个方法来生成流:

串行(stream)程序

List<String> lists = Arrays.asList("1", "2", "3", "");
lists.stream()//转成串行流
    .filter(list -> !list.isEmpty())//进行过滤
    .collect(Collectors.toList())//转成List
    .forEach(s -> System.out.println("s:"+s));//遍历输出

并行(parallel)程序

parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.parallelStream().filter(s -> s.isEmpty()).count();
System.out.println("count:"+count);

中间操作

forEach

Stream 提供了新的方法 'forEach' 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:

Random random = new Random();
// random.ints().limit(10).forEach(num -> System.out.println("num:"+num));
random.ints().limit(10).forEach(System.out::println);

Collectors

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);

map

所谓流映射就是将接受的元素映射成另外一个元素

map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
    .map(i -> i*i)
    .distinct()
    .collect(Collectors.toList())
    .forEach(System.out::println);

filter筛选

filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:

List<String> strings = Arrays.asList("1", "", "2", "aa");
long count = strings.stream().filter(s -> s.isEmpty()).count();

通过使用filter方法进行条件筛选,filter的方法参数为一个条件:

List<Integer> integers = Arrays.asList(1, 1, 2, 3, 4, 5);
integers.stream()
    .filter(i -> i>3)
    .collect(Collectors.toList())
    .forEach(System.out::println);
List<String> stringList = Arrays.asList("Java 8", "Lambdas",  "In", "Action");
stringList.stream()
        .map(String::length)
        .collect(Collectors.toList())
        .forEach(System.out::println);

通过map方法可以完成映射,该例子完成中String -> Integer的映射,之前上面的例子通过map方法完成了Dish->String的映射

flatMap流转换

将一个流中的每个值都转换为另一个流

List<String> wordList = Arrays.asList("Hello", "World");
wordList.stream()
    .map(w -> w.split(" "))
    .flatMap(Arrays::stream)
    .distinct()
    .collect(Collectors.toList()).forEach(System.out::println);

distinct去除重复元素

通过distinct方法快速去除重复的元素

List<Integer> integers = Arrays.asList(1, 1, 2, 3, 4, 5);
integers.stream()
    .distinct()
    .collect(Collectors.toList())
    .forEach(System.out::println);

limit返回指定流个数

limit方法指定返回流的个数,limit的参数值必须>=0,否则将会抛出异常

limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据:

Random random = new Random();
// random.ints().limit(10).forEach(num -> System.out.println("num:"+num));
random.ints().limit(10).forEach(System.out::println);
List<Integer> integers = Arrays.asList(1, 1, 2, 3, 4, 5);
integers.stream()
    .limit(3)
    .collect(Collectors.toList())
    .forEach(System.out::println);

skip跳过流中的元素

List<Integer> integers = Arrays.asList(1, 1, 2, 3, 4, 5);
integers.stream()
    .skip(2)
    .collect(Collectors.toList())
    .forEach(System.out::println);

通过skip方法跳过流中的元素,上述例子跳过前两个元素,所以打印结果为2,3,4,5skip的参数值必须>=0,否则将会抛出异常

sorted

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

元素匹配

提供了三种匹配方式

通过allMatch方法实现

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().allMatch(i -> i > 3)) {
    System.out.println("值都大于3");
}
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().anyMatch(i -> i > 3)) {
    System.out.println("存在大于3的值");
}

等价于

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
for (Integer integer : integerList) {
    if (integer>3){
        System.out.println("存在大于3的值");
        break;
    }
}

存在大于3的值则打印,java8中通过anyMatch方法实现这个功能

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().noneMatch(i -> i>6)) {
    System.out.println("值都小于6");
}

通过noneMatch方法实现

终端操作

统计流中元素个数

通过使用count方法统计出流中元素个数

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
long count = integerList.stream().count();
System.out.println("count:"+count);

等价于通过counting

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Long counting = integerList.stream().collect(Collectors.counting());
System.out.println("counting:"+counting);

查找

提供了两种查找方式

通过findFirst方法查找到第一个大于三的元素并打印

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> first = integerList.stream().filter(i -> i > 3).findFirst();
System.out.println("first:"+first.get());
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> any = integerList.stream().filter(i -> i > 3).findAny();
System.out.println("any:"+any.get());

通过findAny方法查找到其中一个大于三的元素并打印,因为内部进行优化的原因,当找到第一个满足大于三的元素时就结束,该方法结果和findFirst方法结果一样。提供findAny方法是为了更好的利用并行流,findFirst方法在并行上限制更多

reduce将流中的元素组合起来

假设我们对一个集合中的值进行求和

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;
for (Integer integer : integerList) {
    sum += integer;
}
System.out.println("sum:"+sum);
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
int sum = integerList.stream().reduce(0,(a,b) -> a+b);
System.out.println("sum:"+sum);

一行就可以完成,还可以使用方法引用简写成:

int sum = integerList.stream().reduce(0, Integer::sum);

reduce接受两个参数,一个初始值这里是0,一个BinaryOperator<T> accumulator 来将两个元素结合起来产生一个新值, 另外reduce方法还有一个没有初始化值的重载方法

获取流中最小最大值

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5,-1,-100);
integerList.stream().min((e1,e2) -> e1.compareTo(e2)).ifPresent(i -> System.out.println("i:"+i));

同理max是:

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5,-1,-100);
integerList.stream().max((e1,e2) -> e1.compareTo(e2)).ifPresent(i -> System.out.println("i:"+i));

六、Optional 类

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional 类的引入很好的解决空指针异常。

6.1 类声明

以下是一个 java.util.Optional 类的声明:

public final class Optional<T> extendsObject

方法:

static <T> Optional<T> empty()
返回空的 Optional 实例。

boolean equals(Object obj)
判断其他对象是否等于 Optional。

Optional<T> filter(Predicate<? super <T> predicate)
如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Option Optional。

<U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)
如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional

T get()
如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException

int hashCode()
返回存在值的哈希码,如果值不存在返回 0。

void ifPresent(Consumer<? super T> consumer)
如果值存在则使用该值调用 consumer , 否则不做任何事情。

boolean isPresent()
如果值存在则方法会返回true,否则返回 false。

<U>Optional<U> map(Function<? super T,? extends U> mapper)
如果存在该值,提供的映射方法,如果返回非null,返回一个Optional描述结果。

static <T> Optional<T> of(T value)
返回一个指定非null值的Optional。

static <T> Optional<T> ofNullable(T value)
如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。

T orElse(T other)
如果存在该值,返回值,否则返回 other。

T orElseGet(Supplier<? extends T> other)
如果存在该值,返回值,否则触发 other,并返回 other 调用的结果。

<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
String toString()
返回一个Optional的非空字符串,用来调试

Optional 实例:

    public static void main(String[] args) {
        Integer i = null;
        Integer i2 = new Integer(10);

        // Optional.ofNullable - 允许传递为 null 参数
        Optional <Integer> a = Optional.ofNullable(i);

        // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
        Optional<Integer> b = Optional.of(i2);

        T1 t1 = new T1();
        System.out.println("t1.sum(a,b):"+t1.sum(a,b));

    }

    public Integer sum(Optional<Integer> a, Optional<Integer> b) {
        // Optional.isPresent - 判断值是否存在
        System.out.println("第一个参数值存在: " + a.isPresent());
        System.out.println("第二个参数值存在: " + b.isPresent());
        // Optional.orElse - 如果值存在,返回它,否则返回默认值
        Integer value1 = a.orElse(new Integer(0));
        //Optional.get - 获取值,值需要存在
        Integer value2 = b.get();
        return value1 + value2;
    }

七、新时间日期 API

LocalDate、LocalTime、LocalDateTime:

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

方法 描述 示例
now() 静态方法,根据当前时间创建对象 LocalDate localDate = LocalDate.now();LocalTime localTime = LocalTime.now();LocalDateTime localDateTime = LocalDateTime.now()
of() 静态方法,根据指定日期/时间创建对象 LocalDate localDate = LocalDate.of(2016, 10, 26); LocalTime localTime = LocalTime.of(02, 22, 56); LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55);
plusDays,plusWeeks, plusMonths, plusYears 向当前LocalDate 对象添加几天、几周、几个月、几年
minusDays, minusWeeks,minusMonths, minusYears 从当前 LocalDate 对象减去几天、几周、几个月、几年
plus, minus 添加或减少一个 Duration 或 Period
withDayOfMonth, withDayOfYear, withMonth,withYear 将月份天数、年份天数、月份、年份修改为指定的值并返 回新的LocalDate 对象
getDayOfMonth 获得月份天数(1-31)
getDayOfYear getDayOfYear 获得年份天数(1-366)
getDayOfWeek 获得星期几(返回一个 DayOfWeek 枚举值)
getMonth 获得月份, 返回一个 Month 枚举值
getMonthValue 获得月份(1-12)
getYear 获得年份
until 获得两个日期之间的 Period 对象,或者指定 ChronoUnits 的数字
isBefore, isAfter 比较两个 LocalDate
isLeapYear 判断是否是闰年

Instant 时间戳

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

Instant instant_1 = Instant.now();

Duration 和 Period:

Duration:用于计算两个“时间”间隔;Period:用于计算两个“日期”间隔;

//时间间隔
        Instant instant_1 = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Instant instant_2 = Instant.now();

        Duration duration = Duration.between(instant_1, instant_2);
        System.out.println(duration.toMillis());
        //1014

        LocalTime localTime_1 = LocalTime.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LocalTime localTime_2 = LocalTime.now();

        System.out.println(Duration.between(localTime_1, localTime_2).toMillis());
        // 运行结果:1000

        //日期间隔
        LocalDate localDate_1 = LocalDate.of(2021, 10,1);
        LocalDate localDate_2 = LocalDate.now();
        Period period = Period.between(localDate_1, localDate_2);
        System.out.println(period.getYears());
        System.out.println(period.getMonths());
        System.out.println(period.getDays());

日期的操纵:

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

TemporalAdjusters:该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现。例如获取下个周日:

        LocalDate nextSunday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY));//获取下个周日
        System.out.println(nextSunday);
        LocalDateTime localDateTime1 = LocalDateTime.now();
        System.out.println(localDateTime1);

        // 获取这个第一天的日期
        System.out.println(localDateTime1.with(TemporalAdjusters.firstDayOfMonth()));
        // 获取下个周末的日期
        System.out.println(localDateTime1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)));

解析与格式化:

java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:
预定义的标准格式;
语言环境相关的格式;
自定义的格式;

        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ISO_DATE;
        LocalDateTime localDateTime = LocalDateTime.now();
        String strDate1 = localDateTime.format(dateTimeFormatter1);
        System.out.println(strDate1);

        // Date -> String
        DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String strDate2 = dateTimeFormatter2.format(localDateTime);
        System.out.println(strDate2);

        // String -> Date
        LocalDateTime localDateTime1 = localDateTime.parse(strDate2, dateTimeFormatter2);
        System.out.println(localDateTime1);

时区的处理:

Java8 中加入了对时区的支持,带时区的时间为分别为:

ZonedDate、ZonedTime、ZonedDateTime

其中每个时区都对应着 ID,地区ID都为 “{区域}/{城市}”的格式;例如 :Asia/Shanghai 等;
● ZoneId:该类中包含了所有的时区信息;
● getAvailableZoneIds():可以获取所有时区时区信息;
● of(id):用指定的时区信息获取 ZoneId 对象;

与传统日期处理的转换

To 遗留类 From 遗留类
java.time.Instant java.util.Date Date.from(instant) date.toInstant()
java.time.Instant java.sql.Timestamp Timestamp.from(instant) timestamp.toInstant()
java.time.ZonedDateTime java.util.GregorianCalendar GregorianCalendar.from(zonedDateTime) cal.toZonedDateTime()
java.time.LocalDate java.sql.Time Date.valueOf(localDate) date.toLocalDate()
java.time.LocalTime java.sql.Time Date.valueOf(localDate) date.toLocalTime()
java.time.LocalDateTime java.sql.Timestamp Timestamp.valueOf(localDateTime) timestamp.toLocalDateTime()
java.time.ZoneId java.util.TimeZone Timezone.getTimeZone(id) timeZone.toZoneId()
java.time.format.DateTimeFormatter java.text.DateFormat formatter.toFormat()

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注