当前位置: 首页 > news >正文

技术分享——Java8新特性

技术分享——Java8新特性

  • 1.背景
  • 2. 新特性主要内容
  • 3. Lambda表达式
  • 4. 四大内置核心函数式接口
    • 4.1 Consumer<T>消费型接口
    • 4.2 Supplier<T>供给型接口
    • 4.3 Function<T,R>函数型接口
    • 4.4 Predicate<T> 断定型接口
  • 5. Stream流操作
    • 5.1 什么是流以及流的类型
    • 5.2 流操作
      • 5.2.1 创建Stream
      • 5.2.2 Stram流 筛选与切片
      • 5.2.3 映射
      • 5.2.4 排序
      • 5.2.5 匹配与查找
      • 5.2.6 规约与收集
  • 6. 并行流 parallelStream
  • 7. Optional 类
  • 8. 新的时间API
    • 8.1 java.time 主要类
    • 8.2 应用对比
      • 8.2.1 格式化对比
      • 8.2.2 字符串转日期格式
      • 8.2.3 日期计算
      • 8.2.4 获取指定日期

1.背景

目前企业级开发语言主要是Java,Java 8 是目前最常用的 JDK 版本,相比 Java 7 增加了很多功能,比如 Lambda表达式、Stream 流操作、并行流(ParallelStream)、Optional 可空类型、新时间API等。

新特性给我们带来的好处

  • 代码量更少(lambda表达式)
  • 强大的Stream API(提供了一种新的处理集合数据的方式,允许以声明性的方式处理数据)
  • 便于并行(ParallelStream)
  • 最大化减少NPE(Optional)

2. 新特性主要内容

Lambda表达式
四大内置核心函数式接口
Stream流操作 
ParallelStrean并行流
Optional类
新的时间API

3. Lambda表达式

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

  1. 语法格式
左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需执行的功能,既Lambda体 

语法格式一:无参数,无返回值
Runnable r1 = ()-> System.out.println("Hello World");
 
语法格式二:有一个参数,并无返回值
Consumer<String> con = (x)-> System.out.println(x);

语法格式三:若只有一个参数,参数的()可以不写
Consumer<String> con = x-> System.out.println(x);
 
语法格式四:有两个以上参数,有返回值,并且Lambda体中有多条语句
Comparator<Integer> com = (x, y) -> {
   System.out.println("Hello World");
   return Integer.compare(x, y);
};
 
语法格式五:若Lambda体中只有一条语句,return{}都可以不写
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

这里注意Lambda表达式需要"函数式接口"的支持。
函数式接口:接口中只有一个抽象方法,称为函数式接口(@FunctionalInterface 注解声明该接口是一个函数式接口)。
在这里插入图片描述
2. 举个🌰

匿名内部类的格式
new 父类或接口(){
        //进行方法重写
};

// 用匿名内部类的方式来创建线程
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("The runable now is using!");
    }
}).start();

------------------------------------------------------------------------
// 使用Lambda来创建线程,返回的是Runnable对象实例
new Thread(() -> System.out.println("The runable now is using!")).start();

4. 四大内置核心函数式接口

在这里插入图片描述

4.1 Consumer消费型接口

接受一个参数,无返回值,常用于对参数进行处理、修改等操作。
举个🌰

public static void main(String[] args) {
    Consumer<Integer> consumer = i -> {
        System.out.println("Consumer 接收 参数 i 开始处理");
        int step = 1;
        System.out.printf("Consumer 输入%d, 输出%d%n", i, i + step);
    };

    List<Integer> list = Arrays.asList(4, 2, 6);
    list.forEach(consumer);
}
result:
    Consumer 接收 参数 i 开始处理
    Consumer 输入4, 输出5
    Consumer 接收 参数 i 开始处理
    Consumer 输入2, 输出3
    Consumer 接收 参数 i 开始处理
    Consumer 输入6, 输出7

4.2 Supplier供给型接口

不接受参数,返回一个结果,常用于生成某些对象。
举个🌰

// 获取长度为10的整数集合
public static 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);
   }

   return list;
}

getNumList(10, () -> (int) (Math.random() * 100));

4.3 Function<T,R>函数型接口

接受一个参数,返回一个结果,常用于对参数进行处理、转换等操作。
这里举个🌰
有User、UserEntity两个实体类定义如下

@Data
@AllArgsConstructor
public class User {
    private Integer age;
    private String name;
}    
@Data
@AllArgsConstructor
public class UserEntity{
    private Integer age;
    private String name;
    private Integer type;
}

将一组User转换成一组UserEntity, 根据User的年龄来定义用户级别(普通用户,vip,svip),其中用户级别是User Entity的一个字段,所以输入参数是List,返回结果是List 。
构造数据

List<User> users = new ArrayList<>();
users.add(new User(10, "张三"));
users.add(new User(15, "李四"));
users.add(new User(16, "王五"));
users.add(new User(20, "赵六"));
users.add(new User(25, "田七"));
private static Function<List<User>, List<UserEntity>> multiUsersToEntities(List<User> users) {
   Function<List<User>, List<UserEntity>> function = t -> {
      List<UserEntity> userEntityList = new ArrayList<>();
      for (User user : t) {
         UserEntity userEntity = new UserEntity(user.getAge(), user.getName(), "普通用户");
         Integer age = user.getAge();
         if (age > 15 && age <= 20) {
            userEntity.setType("vip");
         }
         if (age > 20) {
            userEntity.setType("svip");
         }
         userEntityList.add(userEntity);
      }
      return userEntityList;
   };
   return function;
}

List<UserEntity> uEntities = multiUsersToEntities(users).apply(users);

4.4 Predicate 断定型接口

接受一个参数,返回一个布尔值,常用于条件判断、筛选等操作。

Predicate<String> predicate = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(predicate);

总结:
这四个接口的作用在于提供常用的函数式编程中常用的基础操作,提高了代码的复用性和简洁性。它们可以被Java8中的Lamba表达式直接调用,从而实现更加简洁而清晰的代码。
如果你需要进行一些简单的操作,这些接口可以让你无需自己编写函数或者创建单独的类,而使用Java8提供的函数式编程工具来解决问题。

除了四大核心函数接口外,Java8还提供了一些其他的函数式接口。
在这里插入图片描述

5. Stream流操作

5.1 什么是流以及流的类型

流是Java API的新成员,它允许通过声明的方式处理数据集合。我们可以把他看成遍历数据集的高级迭代器。它的源数据可以是 Collection、Array 等。由于它的方法参数都是函数式接口类型,所以一般和 Lambda 配合使用。
流的类型有stream 串行流和parallelStream 并行流,parallelStream可多线程执行。

特点:

  1. Stream不会自己存储元素
  2. Stream不会改变源对象,相反他们会返回一个持有新结果的新Strream。
  3. Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

5.2 流操作

Stram的操作三个步骤

  • 创建Stream
    一个数据源(如:集合、数组),获取一个流。
  • 中间操作
    一个中间操作,对数据源的数据进行处理。中间操作可以连成一条流水线。
  • 终端操作
    一个终端操作,执行中间操作链,并产生结果。终端操作的作用是关闭流水线。

在这里插入图片描述

5.2.1 创建Stream

  1. Collection系列集合提供的stream()方法或者parallelStream()创建Stream
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
  1. Arrays类中的静态方法stream()
Employee[] emps = new Employee[10];
Stream<Employee> stream = Arrays.stream(emps);
  1. 通过Stream类中的静态方法of
Stream<String> stream = Stream.of("aa", "bb", "cc");

5.2.2 Stram流 筛选与切片

  1. filter——接收Lambda, 从流中排除某些元素
    在这里插入图片描述
Stream<T> filter(Predicate<? super T> predicate); 断言型接口
List<String> s = Arrays.asList("a","b","c",null);

List<String> s2 = s.stream()
      .filter(e -> e != null)
      .collect(Collectors.toList());
System.out.println(s2);  
// result:[a, b, c] 
  1. limit ——截断流,使其不超过给定的数量
List<String> s = Arrays.asList("a","b","c");

List<String> s2 = s.stream()
      .limit(2L)
      .collect(Collectors.toList());
System.out.println(s2); 
// result:[a, b]
  1. skip(n)—— 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流
List<String> s = Arrays.asList("a","b","c");

List<String> resultList = demoList.stream()
      .skip(2)
      .collect(Collectors.toList());
System.out.println(resultList); 
// result: [c]
  1. distinct——筛选,通过流所生成元素的hashCode()和equals()去除重复元素
List<String> s = Arrays.asList("a","a","b","c");

List<String> resultList = s.stream()
        .distinct()
        .collect(Collectors.toList());
System.out.println(resultList); 
// result: [a,b,c]

5.2.3 映射

  1. map——支持Lambda语法,将元素转换成其他形式提取信息。接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
List<String> demoList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");

List<String> result = demoList.stream()
      .map(str -> str.toUpperCase())
      .collect(Collectors.toList());
System.out.println(result); 
// result: [AAA, BBB, CCC, DDD, EEE]
  1. flatMap——将流中的每个值都替换成另一个流,然后把所有的流连接成一个流。
    在这里插入图片描述
    举个🌰
    给定的单词集合[hello,world],返回集合[h,e,l,l,o, w,o,r,l,d]
List<String> stringList = Arrays.asList("hello", "world");
List<String[]> collect = stringList.stream()
      .map(str -> str.split(""))
      .collect(Collectors.toList());
collect.forEach(col -> System.out.println(Arrays.toString(col)));
    
/* result:
    [h, e, l, l, o]
    [w, o, r, l, d]
*/

大家可以看到返回结果是两个数组,并没有达到我们的要求。map的操作只是将元素放入map中的函数中使其返回另一个Stream<String[]>类型的,但我们真正想要的是一个Stream类型的,所以我们需要扁平化处理,将多个数组放入一个数组中。

List<String> stringList = Arrays.asList("hello", "world");
List<String> collect = stringList.stream()
         .map(str -> str.split(""))
         .flatMap(item -> {
            return Arrays.stream(item);
         })
         .collect(Collectors.toList());
 System.out.println(collect);
 
 // result:[h, e, l, l, o, w, o, r, l, d]

5.2.4 排序

  1. sorted()——自然排序(实现Comparable的compareTo方法)
List<String> list = Arrays.asList("ccc", "aaa", "bbb", "ddd", "eee");
list.stream()
      .sorted()
      .forEach(System.out::println);
      
/* result: 
            aaa
            bbb
            ccc
            ddd
            eee
*/
  1. sorted(Comparator com)——定制排序
    Stream<T> sorted(Comparator<? super T> comparator);
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(new Employee(15, "18801171255", "张三", 8000));
employeeList.add(new Employee(18, "18801171256", "李四", 9000));
employeeList.add(new Employee(20, "18801171257", "王五", 1000));
employeeList.add(new Employee(20, "18801171258", "赵六", 1000));

employeeList.stream()
      .sorted((e1,e2)->{
         if(e1.getAge().equals(e2.getAge())){
            return e1.getName().compareTo(e2.getName());
         }else{
            return e1.getAge().compareTo(e2.getAge());
         }
      })
      .collect(Collectors.toList());

System.out.println(employeeList);
/*
    retult:
    [Employee{age=15, mobile='18801171255', name='张三', salary=8000}, 
    Employee{age=18, mobile='18801171256', name='李四', salary=9000}, 
    Employee{age=20, mobile='18801171257', name='王五', salary=1000}, 
    Employee{age=20, mobile='18801171258', name='赵六', salary=1000}]
*/

5.2.5 匹配与查找

  1. allMatch——检查是否匹配所有元素
    判断数据列表中全部元素都符合设置的predicate条件,如果是就返回true,否则返回false,流为空时总是返回true。
    boolean allMatch(Predicate<? super T> predicate);
List<String> typeList1 = Arrays.asList("1", "2");
List<String> typeList2 = Arrays.asList("1", "2", "3", "4");
// 集合列表中全部元素必须在allMatch里面的那些字符串,只要全部元素中有任意一个不同的元素在AllMatch中就返回false
boolean isMatch1 = typeList1.stream()
                    .allMatch(a -> a.equals("1") || a.equals("2") || a.equals("3"));
boolean isMatch2 = typeList2.stream()
                    .allMatch(a -> a.equals("1") || a.equals("2") || a.equals("3"));
System.out.println(isMatch1);   // result:true
System.out.println(isMatch2);   // fresult:false
  1. anyMatch——检查是否至少匹配一个元素(只要有一个满足条件就返回true)
List<Integer> list = Arrays.asList(10, 12, 14, 16);
boolean flag = list.stream().anyMatch(item -> item > 13);
System.out.println(flag);  // result:true
  1. noneMath——检查是否没有匹配所有元素
    判断数据列表中全部元素都不符合设置的predicate条件,如果是就返回true,否则返回false,流为空时总是返回true。
List<String> list = Arrays.asList("dddd", "ee", "qqq", "bcfff");
boolean isMatch = list.stream().noneMatch(str -> str.startsWith("a"));
System.out.println(isMatch);  // result:true
  1. findFirst——返回第一个元素
    Optional<T> findFirst();
List<String> list = Arrays.asList("dddd", "ee", "qqq", "bcfff");
Optional<String> result = list.stream().findFirst();
System.out.println(result.get()); // result:dddd
  1. findAny——返回当前流中的任意元素。返回的元素是不确定的,对于同一个列表多次调用findAny()有可能会返回不同的值。
  2. count——返回流中元素的总个数
  3. max——返回流中最大值、min——返回流中最小值
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(new Employee(15, "18801171255", "张三", 8000));
employeeList.add(new Employee(18, "18801171256", "李四", 9000));
employeeList.add(new Employee(20, "18801171257", "王五", 1000));
employeeList.add(new Employee(30, "18801171258", "赵六", 1000));

Employee maxAgeemployee = employeeList.stream()
      .max((e1, e2) -> Integer.compare(e1.age, e2.getAge()))
      .get();
System.out.println(maxAgeemployee);
// result:Employee{age=30, mobile='18801171258', name='赵六', salary=1000}

Employee minAgeemployee = employeeList.stream()
      .min((e1, e2) -> Integer.compare(e1.age, e2.getAge()))
      .get();
System.out.println(minAgeemployee);
// result:Employee{age=15, mobile='18801171255', name='张三', salary=8000}

5.2.6 规约与收集

  1. Reduce——它将所有元素组合成单个结果。Reduce的目的是提供一种累积元素的方法,将所有元素组合为同一结果,可以使用reduce进行sum,min,max,count等操作
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream()
      .reduce(0, (x, y) -> x + y);
System.out.println(sum);  // result: 55
  1. 收集 collect——将流转化为其他形式。接收一个Collector接口的实现。Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常见的收集器实例。
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(new Employee(15, "18801171255", "张三", 8000));
employeeList.add(new Employee(18, "18801171256", "李四", 9000));
employeeList.add(new Employee(20, "18801171257", "王五", 1000));
employeeList.add(new Employee(30, "18801171258", "赵六", 1000));

// 把名字收集成List集合
List<String> nameList = employeeList.stream()
      .map(Employee::getName)
      .collect(Collectors.toList());

// 把年龄收集成set集合
Set<Integer> ageList = employeeList.stream()
      .map(Employee::getAge)
      .collect(Collectors.toSet());

// 收集成Map key:age value:mobile
Map<Integer, String> ageAndMobileMap = employeeList.stream()
      .collect(Collectors.toMap(Employee::getAge, Employee::getMobile));

6. 并行流 parallelStream

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
Java8中将并行流进行了优化,我们可以很容易的对数据进行并行操作,Stream API 可以声明性地通过parallel()与sequential()在并行流与顺序流之间进行切换。

这里举个🌰

Integer sum = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8).parallelStream().reduce(0, Integer::sum);

在这里插入图片描述
注意:

  1. 顺序问题
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

list.parallelStream().forEach(System.out::print);
// 65148723

list.stream().forEach(System.out::print);
// 12345678

list.parallelStream()
        .forEachOrdered(System.out::print);
// 12345678
  1. 线程安全问题
public static void main(String[] args) {
   printFun();
}
public static void printFun() {
   List<Integer> integersList = new ArrayList<>();
   for (int i = 0; i < 100; i++) {
      integersList.add(i);
   }
   //普通集合 存储
   List<Integer> parallelStorage = new ArrayList<>();
   //同步集合 存储
   List<Integer> parallelStorage2 = Collections.synchronizedList(new ArrayList<>());
   //通过并行流存入普通集合parallelStorage中
   integersList.parallelStream()
         .filter(i -> i % 2 == 0)
         .forEach(i -> parallelStorage.add(i));
   System.out.println("开始打印普通集合parallelStorage");
   parallelStorage.stream()
         .forEach(e -> System.out.print(e + " "));
   System.out.println();
   System.out.print("------------------------------------");
   System.out.println();
   //通过并行流存入同步集合parallelStorage2中
   integersList
         .parallelStream()
         .filter(i -> i % 2 == 0)
         .forEach(i -> parallelStorage2.add(i));
   System.out.println("开始打印同步集合parallelStorage");
   parallelStorage2
         .stream()
         .forEach(e -> System.out.print(e + " "));
}

在这里插入图片描述

List<String> resultList = new CopyOnWriteArrayList<>();
List<String> resultList = Collections.synchronizedList(new ArrayList<>());

7. Optional 类

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

常用方法:

  1. Optional.of(T t):创建一个Optional实例
Optional<Person> op = Optional.of(new Employee());
op.get();
  1. Optional.empty():创建一个空的Optional实例
Optional op = Optional.empty();
op.get();
// NoSuchElementException

在这里插入图片描述

  1. Optional.ofNullable(T t):若t不为null,创建Optional实例否则创建空实例
Optional<Person> op = Optional.ofNullable(new Employee());
System.out.println(op.get());
// result: Employee{age=null, mobile='null', name='null', salary=null}
  1. orElse(T t):如果调用对象包含值,返回该值,否则返回t
Optional<Employee> op = Optional.ofNullable(null);
Employee employee = op.orElse(new Employee(15, "18801171255", "张三", 8000));
System.out.println(employee);
// result: Employee{age=15, mobile='18801171255', name='张三', salary=8000}
  1. orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取到的值
Optional<Employee> op = Optional.ofNullable(null);
Employee employee = op.orElseGet(() -> new Employee(15, "18801171255", "张三", 8000));
System.out.println(employee);
// result: Employee{age=15, mobile='18801171255', name='张三', salary=8000}
  1. map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
Optional<Employee> op = Optional.ofNullable(new Employee(15, "18801171255", "张三", 8000)));
Optional<String> opStr = op.map(e -> e.getName());
System.out.println(opStr.get());
// result:张三
  1. flatMap(Function mapper):与map类似,要求返回值必须是Optional
Optional<Employee> op = Optional.ofNullable(new Employee(15, "18801171255", "张三", 8000));
Optional<String> opStr = op.flatMap(e -> Optional.of(e.getName()));
System.out.println(opStr.get());
// result:张三

8. 新的时间API

在这里插入图片描述
在这里插入图片描述

8.1 java.time 主要类

LocalDateTime.class //日期+时间 format: yyyy-MM-ddTHH:mm:ss.SSS
LocalDate.class //日期 format: yyyy-MM-dd
LocalTime.class //时间 format: HH:mm:ss

8.2 应用对比

8.2.1 格式化对比

Java 8 之前:

import java.text.SimpleDateFormat;
import java.util.Date;

public void oldFormat(){
    Date now = new Date();
    //format yyyy-MM-dd HH:mm:ss
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    String date  = sdf.format(now);
    System.out.println(String.format("date format : %s", date));
    
    result: date format : 2023-03-14
------------------------------------------------------------------
    //format HH:mm:ss
    SimpleDateFormat sdft = new SimpleDateFormat("HH:mm:ss");
    String time = sdft.format(now);
    System.out.println(String.format("time format : %s", time));

    result: time format : 15:45:32
------------------------------------------------------------------
    //format yyyy-MM-dd HH:mm:ss
    SimpleDateFormat sdfdt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String datetime = sdfdt.format(now);
    System.out.println(String.format("dateTime format : %s", datetime));
    
    dateTime format : 2023-03-14 15:45:32
}

Java 8 之后:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public void newFormat(){
    //format yyyy-MM-dd
    LocalDate date = LocalDate.now();
    System.out.println(String.format("date format : %s", date));

    result:date format : 2023-03-14
------------------------------------------------------------------
    //format HH:mm:ss
    LocalTime time = LocalTime.now().withNano(0);
    System.out.println(String.format("time format : %s", time));
    
    result:time format : 15:49:16
------------------------------------------------------------------
    //format yyyy-MM-dd HH:mm:ss
    LocalDateTime dateTime = LocalDateTime.now();
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String dateTimeStr = dateTime.format(dateTimeFormatter);
    System.out.println(String.format("dateTime format : %s", dateTimeStr));
    
    result:dateTime format : 2023-03-14 15:49:16
}

8.2.2 字符串转日期格式

Java 8 之前:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = sdf.parse("2022-09-20");

Java 8 之后:

public static LocalDate parse(CharSequence text) {
    return parse(text, DateTimeFormatter.ISO_LOCAL_DATE);
}
LocalDate.parse("2022-07-06");

LocalDateTime.parse("2021-01-26 12:12:22");

LocalTime.parse("12:12:22");

8.2.3 日期计算

Java 8 之前:

SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
Calendar ca = Calendar.getInstance();
ca.add(Calendar.DATE, 7);
Date d = ca.getTime();
String after = formatDate.format(d);
System.out.println("一周后日期:" + after);

result:一周后日期:2023-03-21
-----------------------------------------------------------------------

//算两个日期间隔多少天,计算间隔多少年,多少月方法类似
String dates1 = "2023-12-23";
String dates2 = "2023-02-26";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = format.parse(dates1);
Date date2 = format.parse(dates2);
int day = (int) ((date1.getTime() - date2.getTime()) / (1000 * 3600 * 24));
System.out.println(dates2 + "和" + dates2 + "相差" + day + "天");

result:2023-02-262023-02-26相差300

Java 8 之后:

public void pushWeek(){
     //一周后的日期
     LocalDate localDate = LocalDate.now();
     //方法1
     LocalDate after = localDate.plus(1, ChronoUnit.WEEKS);
     //方法2
     LocalDate after2 = localDate.plusWeeks(1);
     System.out.println("一周后日期:" + after);
     
     result:一周后日期:2023-03-21
-----------------------------------------------------------------------

     //算两个日期间隔多少天,计算间隔多少年,多少月
     LocalDate date1 = LocalDate.parse("2021-02-26");
     LocalDate date2 = LocalDate.parse("2021-12-23");
     Period period = Period.between(date1, date2);
     System.out.println("date1 到 date2 相隔:"
                + period.getYears() + "年"
                + period.getMonths() + "月"
                + period.getDays() + "天");
                
     result:date1 到 date2 相隔:0927-------------------------------------------------------------------------     
     //这里period.getDays()得到的天是抛去年月以外的天数,并不是总天数
     //如果要获取纯粹的总天数应该用下面的方法
     long day = date2.toEpochDay() - date1.toEpochDay();
     System.out.println(date2 + "和" + date2 + "相差" + day + "天");
     
     result:2023-12-232023-12-23相差300}

8.2.4 获取指定日期

Java 8 之前:

public void getDay() {
   SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
   //获取当前月第一天:
   Calendar c = Calendar.getInstance();
   c.set(Calendar.DAY_OF_MONTH, 1);
   String first = format.format(c.getTime());
   System.out.println("first day:" + first);

   //获取当前月最后一天
   Calendar ca = Calendar.getInstance();
   ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
   String last = format.format(ca.getTime());
   System.out.println("last day:" + last);

   //当年最后一天
   Calendar currCal = Calendar.getInstance();
   Calendar calendar = Calendar.getInstance();
   calendar.clear();
   calendar.set(Calendar.YEAR, currCal.get(Calendar.YEAR));
   calendar.roll(Calendar.DAY_OF_YEAR, -1);
   Date time = calendar.getTime();
   System.out.println("last day:" + format.format(time));
}

Java 8 之后:

public void getDayNew() {
   LocalDate today = LocalDate.now();
   //获取当前月第一天:
   LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
   // 取本月最后一天
   LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
   //取下一天:
   LocalDate nextDay = lastDayOfThisMonth.plusDays(1);
   //当年最后一天
   LocalDate lastday = today.with(TemporalAdjusters.lastDayOfYear());
   //2023年最后一个周日,如果用Calendar是不得烦死。
   LocalDate lastMondayOf2023 = LocalDate.parse("2023-12-31")
                               .with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
}

相关文章:

  • JavaScript获取img的原始尺寸
  • extjs动态修改grid列表中的行数据
  • [数据结构]二叉树OJ(leetcode)
  • Java容器类详解(Collection与Map,含多线程性能对比)
  • 项目文件的组织方式
  • 系统集成路由器OSPF动态、综合路由配置
  • windows搭建ftp服务器、抓取虚拟机数据包、局域网流量监听
  • 数值分析——求积公式
  • php模拟文件上传使用curl向远程服务器上传文件,php将图片转成二进制文件进行请求接口上传
  • 【大数据之Hadoop】三、HDFS概述及组成框架
  • MapReduce数据倾斜产生的原因及其解决方案
  • docker开启的Mysql修改时区
  • 完成首选项
  • 【C语言进阶】自定义类型之结构体,枚举和联合
  • springboot校友社交系统
  • 【Python算法】简单深搜练习
  • ASO优化之应用商店中的A/B测试——改良版
  • Github隐藏功能显示自己的README,个人化你的Github主页
  • 什么是 SSL 证书管理
  • java中如何实现全文搜索
  • 电加热油锅炉工作原理_电加热导油
  • 大型电蒸汽锅炉_工业电阻炉
  • 燃气蒸汽锅炉的分类_大连生物质蒸汽锅炉
  • 天津市维修锅炉_锅炉汽化处理方法
  • 蒸汽汽锅炉厂家_延安锅炉厂家
  • 山西热水锅炉厂家_酒店热水 锅炉
  • 蒸汽锅炉生产厂家_燃油蒸汽发生器
  • 燃煤锅炉烧热水_张家口 淘汰取缔燃煤锅炉
  • 生物质锅炉_炉
  • 锅炉天然气_天燃气热风炉