学静思语
Published on 2025-03-21 / 9 Visits
0
0

JDK8-新特性

JDK8-新特性

一、新特性目录

  • Lambda表达式
  • Stream API
  • 并行流与串行流
  • Optional容器
  • 接口默认方法与静态方法
  • 新时间与日期类
  • 重复注解与类型注解

二、Lambda表达式

1.基本语法

  • 左侧:Lambda表达式的参数列表
  • 中间:箭头头操作符,将参数列表和执行体分开
  • 右侧:Lambda表达式的执行体

2.语法格式

2.1 语法格式一

  • 基本语法格式:无参数,无返回值

    // 1.
    () -> {
      多行代码
    };
    // 2. 
    () -> 一行代码
    
  • 实例

    @Test
      public void test1(){
          // 如果执行体只有一行代码,则可以省略大括号{}
          MyFunction myFunction1 = () -> System.out.println("Hello Lambda~~~");
          // 如果执行体代码超过一行,则需要使用大括号括起来,否则只有一个代码会被包含到方法中
          MyFunction myFunction2 = () -> {
              System.out.println("ddddd");
              System.out.println("Hello Lambda~~~");
          };
    
          myFunction1.work();
    
      }
    

2.2 语法格式二

  • 基本语法格式:无参数,有返回值

    // 1.
    () -> {retuen new Employee();};
    // 2.
    () -> new Employee();
    // 3.
    () ->{
      多行代码
      return new Employee();
    }
    
  • 实例

    @Test
      public void test2(){
          // 如果使用return返回对象则需要使用大括号,括起来,否则会报错
          MyProduction<Employee> myProduction1 = () -> {return new Employee();};
    
          Employee product = myProduction1.product();
    
          // 可以省略return关键字
          MyProduction<Employee> myProduction2 = () -> new Employee("张三",20,8888.88);
    
          Employee employee = myProduction2.product();
    
          //如果执行体中有多行代码,则不能省略return关键字
          MyProduction<Employee> myProduction3 = () -> {
              System.out.println("Hello Production ~~~~");
              return new Employee("王五",23,9999.99);
          };
    
          Employee employee2 = myProduction3.product();
    
    
          System.out.println(product);
    
          System.out.println(employee);
    
          System.out.println(employee2);
      }
    

2.3 语法格式三

  • 基本语法格式:有参,无返回值

    // 1.
    (x,y) -> 一句语句
    // 2. 
    (x,y) -> {
      多条语句
    }
    // 3.
    (x) -> 一条语句
    x -> 一条语句     
    // 4. 
    (x) -> {
      多条语句
    } 
    x -> {
      多条语句
    }
    
  • 实例

    @Test
      public void test3(){
    
          // 如果参数是两个,则不能省略小括号,执行体只有一句的话可以省略大括号
          // 如果执行体有多条,则不能省略大括号
          MyShow<String,String> myComparison = (x,y) -> System.out.println(x+y);
    
          // 如果参数只有一个可以省略小括号(建议加上小括号),执行体只有一句的话可以省略大括号
          // 如果执行体有多条,则不能省略大括号
          MyConsumption<String> myConsumption = (x) -> System.out.println(x);
    
          myComparison.show("xixi","haha");
          myConsumption.consumption("你好");
    
      }
    

2.4 语法格式四

  • 基本语法格式:有参,有返回值

    // 1.
    (x) -> 一条语句;
    x  -> 一条语句;
    // 2.
    (x,y) -> 一条语句;
    // 3.
    (x) -> {
      多条语句
      return x.subString(2,x.length());
    };
    // 4.
    (x,y) -> {
      多条语句
      return Integer.compare(x,y);
    };
    
  • 实例:

      @Test
      public void test4(){
          // 如果只有一条语句,则return和大括号都可以省略不写
          // Lambda表达式的参数列表的数据类型可以省略不写i,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
          MyComparison<Integer,Integer,Integer> myComparison = (x,y) ->  Integer.compare(x,y);
    
          // 如果只有一个参数,则小括号可以省略,如果只有一条语句,也可以省略return和大括号
          MySetting<String,String> mySetting = x -> x.substring(2,x.length());
    
          // 如果执行体中有多条语句,则不能省略return和大括号
          MyComparison<Integer,Integer,Integer> myComparison2 = (x,y) -> {
              System.out.println("x = " +x + " y = "+ y);
              return Integer.compare(x,y);
          };
    
          // 如果执行体中有多条语句,则不能省略return和大括号
          MySetting<String,String> mySetting2 = (x) -> {
              System.out.println("x =" + x);
              return x.substring(2,x.length());
          };
    
    
          System.out.println(myComparison.compare(10,20));
          System.out.println(mySetting.generate("Hello Lambda"));
    
          System.out.println(myComparison2.compare(20,19));
          System.out.println(mySetting2.generate("llword"));
      }
    

3. Lambda表达式需要函数式接口的支持

  • 什么是函数式接口

  • 接口中只有一个抽象方法的接口,称之为函数式接口。可以使用注解@FunctionalInterface进行修饰,可以检查是否是函数式接口

  • 注意事项

  • 函数式接口是只允许有一个抽象方法的接口,而不是不允许有默认方法和静态方法。

    package com.leon.java8.lambda;
    
    /**
     * ClassName:MyFouncation
     * Package:com.leon.java8.lambda
     * Description:
     *
     * @Author: leon
     * @Version: 1.0
     */
    @FunctionalInterface
    public interface MyFunction {
    
        default void test(){
            System.out.println("Hello World");
        }
    
        public static void test2(){
            System.out.println("Hello World");
        }
    
        public void work();
    
    }
    

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

4.1 消费型接口

  • Consumer< T >

    void accept(T t);
    
  • 具体应用

    @Test
      public void test5(){
          //Consumer
          consumer(10000,(m) -> System.out.println("工资为"+m));
    
      }
    
      private void consumer(double money,Consumer<Double> consumer){
    
          consumer.accept(money);
    
      }
    

4.2 供给型接口

  • Supplier< T >

    T get();
    
  • 具体应用

    @Test
      public void test6(){
          //Supplier
          Employee jack = supplier(() -> new Employee("jack", 20, 8888.88));
    
          System.out.println(jack);
    
    
      }
    
      private Employee supplier(Supplier<Employee> supplier){
          return supplier.get();
      }
    

4.3 函数型接口

  • Function< T R >

    R apply(T t);
    
  • 具体应用

    @Test
      public void test7(){
          //Function
          String function = function("\t\t\t 哈哈哈哈 ", (s) -> s.trim());
    
          System.out.println(function);
    
      }
    
      private String function(String str,Function<String,String> function){
          return function.apply(str);
      }
    

4.4 断言型接口

  • Predicate< T >

    boolean test(T t);
    
  • 具体应用

    @Test
      public void test8(){
          //Predicate
          boolean predicate = predicate("hhhhh", (s) -> s.length() > 2);
    
          System.out.println(predicate);
    
      }
    
      private boolean predicate(String str,Predicate<String> predicate){
          return predicate.test(str);
      }
    

5. 方法引用和构造器引用

5.1 方法引用

  • 若Lambda体中的内容有方法已经实现了,我们可以使用”方法引用“(可以理解为方法引用Lambda表达式的另外一种表现形式)
5.1.1 对象 : : 实例方法名
 @Test
    public void test1() {

        Consumer<String> consumer1 = (x) -> System.out.println(x);

        consumer1.accept("hhh");

        //对象::实例方法名
        Consumer<String> consumer2 = System.out::println;

        consumer2.accept("Hello");
        //------------------------------

        Employee employee = new Employee("张三", 20, 8888.88);

        Supplier<String> supplier1 = () -> employee.getName();

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


        Supplier<String> supplier2 = employee::getName;

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

        //---------------------------------------

        System.out.println(employee);

        Consumer<Integer> consumer3 = (x) -> employee.setAge(x);

        consumer3.accept(30);

        System.out.println(employee);

        Consumer<Integer> consumer4 = employee::setAge;

        consumer4.accept(28);

        System.out.println(employee);

    }
5.1.2 类 : : 静态方法名
   @Test
    public void test2() {

        // 类::静态方法名
        Consumer<List<Employee>> consumer = (x) -> Collections.sort(x);

        consumer.accept(employees);

        employees.forEach(System.out::println);

        // --------------------------------

        Consumer<List<Employee>> consumer2  = Collections::sort;


        consumer2.accept(employees);

        employees.forEach(System.out::println);

        // ----------------------------------------

        BiConsumer<List<Employee>,Comparator<Employee>> biConsumer1 = (l,c) ->{
            Collections.sort(l,c);
        };

        biConsumer1.accept(employees,(x,y) -> x.getAge() - y.getAge() );

        employees.forEach(System.out::println);

        // -----------------------------------------

        BiConsumer<List<Employee>, Comparator<Employee>> biConsumer2 = Collections::sort;


        biConsumer2.accept(employees, (x, y) -> Integer.compare(x.getAge(), y.getAge()));

        employees.forEach(System.out::println);

    }
5.1.3 类 : : 实例方法名
  • 其适配的函数式接口的抽象方法,规则为:函数式接口参数 = 实例方法参数+1
  • 什么意思呢?
    • 如果函数式接口只有一个参数,那实例方法可以没有参数,但是得满足前提条件,函数式接口的第一个参数是方法的调用者,第二以及后面的参数为实例方法的参数。
 @Test
    public void test3() {

        BiPredicate<String,String> biPredicate1 = (x,y) -> x.equals(y);
        boolean test1 = biPredicate1.test("aa", "aa");

        System.out.println(test1);


        // 类::实例方法名
        // 若lambda表达式中的第一个参数是方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::实例方法
        BiPredicate<String, String> biPredicate2 = String::equals;

        boolean test = biPredicate2.test("hello", "hello");

        System.out.println(test);
    }

5.2 构造器引用

5.2.1 ClassName :: new
    @Test
    public void test4() {

        // ClassName :: new
        // 需要调用的构造器的参数列表要与函数式接口中的抽象方法的参数列表保持一致
        Supplier<Employee> supplier = () -> new Employee();

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

        Supplier<Employee> supplier2 = Employee::new;

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

        Function<Integer,Employee> function = Employee::new;

        System.out.println(function.apply(20));



    }

5.3 数组引用

5.3.1 Type[] :: new

  @Test
    public void test5() {

        // Type::new
        Function<Integer,String[]> function = (l) -> new String[l];

        System.out.println(function.apply(20).length);

        Function<Integer,String[]> function2 = String[]::new;

        System.out.println(function2.apply(2).length);

    }

5.4 注意事项

  • Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型保持一致
  • 用ClassName::实例方法
  • 函数式接口的第一个参数成为方法的调用者
  • 剩余参数(如果有)传递给实例方法
  • 参数数量关系: 函数接口参数数 = 实例方法参数数 + 1
  • 需要调用的构造器的参数列表要与函数式接口中的抽象方法的参数列表保持一致

三、Stream API

1. 创建Stream

 @Test
    public void test() {
        // 通过集合去创建Stream
        List<String> list = new ArrayList<>();

        Stream<String> stream1 = list.stream();

       // 通过Arrays静态方法创建Stream
        Employee[] employees = new Employee[10];

        Stream<Employee> stream2 = Arrays.stream(employees);

        // 通过Stream静态方法创建Stream
        Stream<String> stream3 = Stream.of("aa", "bb", "cc", "dd");

        // 创建无限流
        // 迭代
        Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2).limit(10);

        iterate.forEach(System.out::println);

        // 生成
        Stream<Double> generate = Stream.generate(Math::random).limit(2);

        generate.forEach(System.out::println);


    }

2. 中间操作

  • filer
  • 接收Lambda表达式,从流中排除某些元素
  • limit
  • 截断流,使其元素不超过给定数量
  • skip(n)
  • 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
  • distinct
  • 筛选,通过流所生成的hashCode()和equals()去除重复元素
@Test
    public void test2() {

        // filter
        employees.stream().filter((x) -> x.getAge() > 20).forEach(System.out::println);

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

        employees.stream().filter((x) -> x.getSalary() > 5000).forEach(System.out::println);

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

        // limit
        employees.stream().limit(3).forEach(System.out::println);

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

        // skip
        employees.stream().skip(3).forEach(System.out::println);

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

        // distinct
        employees.stream().distinct().forEach(System.out::println);

    }
  • map
  • 接收Lambda表达式,将元素转换成其他形式或提取信息,接收一个函数式接口作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。
  • flatMap
  • 接收一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有流接成一个流
  @Test
    public void test3() {

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


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

        Stream<Stream<Character>> streams = strings.stream().map(StreamApiTest::filterCharacter);
        streams.forEach((s) -> {
            Iterator<Character> iterator = s.iterator();

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

        });

        Stream<Character> characterStream = strings.stream().flatMap(StreamApiTest::filterCharacter);

        characterStream.forEach((c) -> System.out.print(c+" "));


    }

    private static Stream<Character> filterCharacter(String str) {

        List<Character> list = new ArrayList<>();

        for (Character c : str.toCharArray()) {
            list.add(c);
        }

        return list.stream();

    }
  • sorted()
  • 自然排序
  • sorted(Comparator com)
  • 定制排序
  @Test
    public void test4() {

        // sorted 自然
        Stream<Employee> sorted = employees.stream().sorted();

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

        // sorted 定制
        Stream<Employee> stream = employees.stream().sorted((x,y) -> - x.getAge() - y.getAge());

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

    }
  • allMatch
  • 检查是否匹配所有元素
  • anyMatch
  • 检查是否至少匹配一个元素
  • noneMatch
  • 检查是否没有匹配所有元素
  • findFirst
  • 返回第一个元素
  • findAny
  • 返回当前流中的任意元素
  • count
  • 返回流中元素的总个数
  • max
  • 返回流中最大值
  • min
  • 返回流中最小值
 @Test
    public void test5() {

        // allMatch
        boolean allMatch = employees.stream().allMatch((e) -> e.getStatus() == Employee.Status.BUSY);

        System.out.println(allMatch);

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

        // noneMatch
        boolean b1 = employees.stream().noneMatch((e) -> e.getStatus() == Employee.Status.FREE);

        System.out.println(b1);

        // findFirst
        Optional<Employee> first = employees.stream().findFirst();

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

        // findAny
        Optional<Employee> any = employees.stream().filter((e) -> e.getSalary() > 5000).findAny();
        System.out.println(any.get());

        // count
        long count = employees.stream().count();
        System.out.println(count);

        // max
        Optional<Employee> max = employees.stream().max((x,y)->Double.compare(x.getSalary(),y.getSalary()));

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

        // min
        Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compare);

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


    }

3. 终止操作(终端操作)

  • reduce(T indentity,BinaryOperator)
  • 可以将流中元素反复结合起来,得到一个值。
  • reduce(BinaryOperator)
  • 可以将流中元素反复结合起来,得到一个值。
 @Test
    public void test6(){
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

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

        System.out.println(sum);

        // reduce
        Optional<Integer> reduce = list.stream().reduce((x, y) -> x * y);

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


    }
  • collect
  • 将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
 @Test
    public void test7(){

        // collect
        List<Employee> collect = employees.stream().filter((e) -> e.getSalary() > 5000).collect(Collectors.toList());

        collect.forEach(System.out::println);

        // collect(Collectors.groupingBy(Employee::getStatus))
        Map<Employee.Status, List<Employee>> listMap = employees.stream().collect(Collectors.groupingBy(Employee::getStatus));

        listMap.forEach((k,v) -> System.out.println("key = " + k + " value = " + v));

        // collect(Collectors.groupingBy((e) -> e.getSalary() > 5000, Collectors.groupingBy(Employee::getStatus)));
        Map<Boolean, Map<Employee.Status, List<Employee>>> collect2 = employees.stream().collect(Collectors.groupingBy((e) -> e.getSalary() > 5000, Collectors.groupingBy(Employee::getStatus)));

        collect2.forEach((k,v) -> System.out.println("key = " + k + " value = " + v));

        // Collectors.toCollection(HashSet::new)
        Collection<String> collected = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
        collected.forEach(System.out::println);

        // collect(Collectors.counting());
        Long collect1 = employees.stream().collect(Collectors.counting());

        System.out.println(collect1);

        // collect(Collectors.averagingDouble(Employee::getSalary));
        Double aDouble = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));

        System.out.println(aDouble);

        // collect(Collectors.summingDouble(Employee::getSalary));
        Double aDouble1 = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));

        System.out.println(aDouble1);

        // collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
        Optional<Employee> collect4 = employees.stream().collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));

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

        // collect(Collectors.partitioningBy((x) -> x.getSalary() > 5000));
        Map<Boolean, List<Employee>> collect3 = employees.stream().collect(Collectors.partitioningBy((x) -> x.getSalary() > 5000));

        System.out.println(collect3);

        // collect(Collectors.summarizingDouble(Employee::getSalary));
        DoubleSummaryStatistics doubleSummaryStatistics = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));

        long count = doubleSummaryStatistics.getCount();

        double max = doubleSummaryStatistics.getMax();

        System.out.println(count);

        System.out.println(max);


    }

四、并行流与串行流

@Test
    public void test2(){

        // 并行流与顺序流切换
        // parallel 并行流
        // sequential 顺序流
        Instant start = Instant.now();

        long reduce = LongStream.rangeClosed(0L, 10000000000L).parallel().reduce(0, Long::sum);
        //long reduce = LongStream.rangeClosed(0L, 10000000000L).sequential().reduce(0, Long::sum);

        Instant end = Instant.now();
        System.out.println(reduce);
        System.out.println(Duration.between(start,end).toMillis()); //665
    }

五、Optional容器

1. 常用方法

  • of(T t)
  • 创建一个Optional实例
  • empty()
  • 创建一个空的Optional实例
  • ofNullable(T t)
  • 若t不为null,创建Optional实例,否则创建空实例
  • isPresent()
  • 判断是否包含值
  • orElse(T t)
  • 如果调用对象包含值,返回该值,否则返回t
  • orElseGet(Supplier s)
  • 如果调用对象包含值,返回该值,否则返回s获取的值
  • map(Function f)
  • 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
  • flatMap(Function mapper)
  • 与map类似,要求返回值必须是Optional
 @Test
    public void test1() {

        // of
        Optional<Employee> o = Optional.of(new Employee());

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

        // empty
        Optional<Object> empty = Optional.empty();

        //System.out.println(empty.get());

        /*
        * ofNullable
        *  public static <T> Optional<T> ofNullable(T value) {
                return value == null ? empty() : of(value);
           }
        * */
        //Optional<Object> o1 = Optional.ofNullable(null);
        Optional<Object> o1 = Optional.ofNullable(new Employee());
        System.out.println(o1.get());

        // orElse
        Object o2 = o1.orElse(new Employee("张三", 23, 10000));

        System.out.println(o2);

        // orElseGet
        Optional<String> employee = Optional.empty();

        Employee test = new Employee("李四", 23, 10000);

        String name = employee.orElseGet(test::getName);

        System.out.println(name);




    }

    @Test
    public void test2() {

        // map
        Optional<Employee> employee = Optional.of(new Employee("李四", 23, 6000));

        Optional<String> string = employee.map(Employee::getName);

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

        // flatMap
        Optional<Double> optional = employee.flatMap((e) -> Optional.of(e.getSalary()));

        System.out.println(optional.get());
        //System.out.println(optional.isPresent());

    }

六、接口默认方法与静态方法

1. 接口默认方法的类优先原则

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

/**
 * ClassName:MyTest
 * Package:com.leon.java8.interface8
 * Description:
 *
 * @Author: leon
 * @Version: 1.0
 */
public class MyTest /*extends MyClass */implements MyInterface,MyInterface2{
   @Override
   public String getName() {
      return "MyTest";
   }
}


package com.leon.java8.interface8;

/**
 * ClassName:MyInterface2
 * Package:com.leon.java8.interface8
 * Description:
 *
 * @Author: leon
 * @Version: 1.0
 */
public interface MyInterface2 {

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

    public static void show(){
        System.out.println("hello MyInterface2" );
    }
}


package com.leon.java8.interface8;

/**
 * ClassName:MyInterface
 * Package:com.leon.java8.interface8
 * Description:
 *
 * @Author: leon
 * @Version: 1.0
 */
public interface MyInterface {

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

    public static void show(){
        System.out.println("hello MyInterface" );
    }
}



package com.leon.java8.interface8;

/**
 * ClassName:MyClass
 * Package:com.leon.java8.interface8
 * Description:
 *
 * @Author: leon
 * @Version: 1.0
 */
public class MyClass {

    public String getName(){
        return "xxixi";
    }

}


package com.leon.java8.interface8;

/**
 * ClassName:InterfaceTest
 * Package:com.leon.java8.interface8
 * Description:
 *
 * @Author: leon
 * @Version: 1.0
 */
public class InterfaceTest {

   public static void main(String[] args) {

      MyTest myTest = new MyTest();

      String name = myTest.getName();

      System.out.println(name);

      MyInterface.show();
      MyInterface2.show();

   }

}

七、新时间与日期类

1. LocalDate

 @Test
    public void test1() {

        // LocalDate
        LocalDate now = LocalDate.now();

        // 当前时间
        System.out.println(now);
        // 当前年
        System.out.println(now.getYear());
        // 当前月
        System.out.println(now.getMonthValue());
        // 当前天
        System.out.println(now.getDayOfMonth());

    }

2.LocalTime

 @Test
    public void test2() {

        LocalTime now = LocalTime.now();

        // 获取当前时间
        System.out.println(now);
        // 获取小时
        System.out.println(now.getHour());
        // 获取分钟
        System.out.println(now.getMinute());
        // 获取秒
        System.out.println(now.getSecond());
        // 获取纳秒
        System.out.println(now.getNano());


    }

3.LocalDateTime

  @Test
    public void test3() {

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        LocalDateTime time = LocalDateTime.now();
        // 格式化时间
        //String format = time.format(formatter);
        // 格式化时间
        String format = formatter.format(time);

        System.out.println(time);

        System.out.println(format);
        // 获取年
        System.out.println(time.getYear());
        // 获取月份
        System.out.println(time.getMonthValue());
        // 获取天
        System.out.println(time.getDayOfMonth());
        // 获取小时
        System.out.println(time.getHour());
        // 获取分钟
        System.out.println(time.getMinute());
        // 获取秒
        System.out.println(time.getSecond());

        // 加一天
        LocalDateTime localDateTime = time.plusDays(2);
        System.out.println(localDateTime);


    }

4. Instant:时间戳(以Unix元年:1970年1月1日00:00:00到某个时间之间的毫秒值)

    @Test
    public void test4() {


        Instant now = Instant.now();

        OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));

        // 1970-1-1 00:00:00 加上六十秒
        Instant instant = Instant.ofEpochSecond(60);

        System.out.println(instant);

        // 获取当前时间
        System.out.println(now);
        // 偏移了8小时之后的时间
        System.out.println(offsetDateTime);
        // 获取毫秒值
        System.out.println(now.toEpochMilli());

    }

5. Duration:计算两个时间之间的间隔

    @Test
    public void test5() {

        LocalDateTime time = LocalDateTime.now();


        LocalDateTime localDateTime = LocalDateTime.of(2024, 10, 5, 15, 6);

        Duration between = Duration.between(localDateTime, time);

        System.out.println(between);

        // 获取天
        System.out.println(between.toDays());
        // 获取毫秒
        System.out.println(between.toMinutes());
        // 获取小时
        System.out.println(between.toHours());


    }

6.Period:计算两个日期之间的间隔

 @Test
    public void test6() {


        LocalDate now = LocalDate.now();

        LocalDate localDate = LocalDate.of(2024, 10, 5);

        Period between = Period.between(localDate, now);

        System.out.println(between);
        // 获取天数
        System.out.println(between.getDays());
        // 获取月数
        System.out.println(between.getMonths());

    }

7. TemporalAdjuster:时间校正器

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

    @Test
      public void test7() {
    
          LocalDateTime time = LocalDateTime.now();
    
          System.out.println(time);
    
          // 当前日期减去10天
          LocalDateTime localDateTime = time.withDayOfMonth(10);
    
          System.out.println(localDateTime);
    
          // 下一个周日的时间
          LocalDateTime with = time.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
    
          System.out.println(with);
    
          // 自定义工作日
          LocalDateTime date =  time.with((t) -> {
             LocalDateTime localDateTime1=  (LocalDateTime)t;
    
             if(localDateTime1.equals(DayOfWeek.FRIDAY)){
                return localDateTime1.plusDays(3);
             }else if(localDateTime1.equals(DayOfWeek.SATURDAY)){
                 return localDateTime1.plusDays(2);
             }else {
                 return localDateTime1.plusDays(1);
             }
          });
    
          System.out.println(date);
    
    
      }
    

8. DateTimeFormatter:日期格式化

 @Test
    public void test8() {

        // 格式化日期
        DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE_TIME;

        LocalDateTime time = LocalDateTime.now();

        String format = time.format(isoDateTime);

        System.out.println(format);

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");

        String format1 = time.format(dateTimeFormatter);

        System.out.println(format1);

    }

9. ZonedDate 、ZonedTime、 ZoneDateTime

    @Test
    public void test9(){

        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();

        availableZoneIds.stream().filter((s) -> s.contains("Asia")).forEach(System.out::println);

        LocalDateTime time = LocalDateTime.now(ZoneId.of("America/Guatemala"));

        System.out.println(time);

        ZonedDateTime zonedDateTime = time.atZone(ZoneId.of("Asia/Shanghai"));

        System.out.println(zonedDateTime);


    }

八、重复注解与类型注解

1.可重复的注解

package com.leon.java8.annotation;

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

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

/**
 * ClassName:MyAnnotations
 * Package:com.leon.java8.annotation
 * Description:
 *
 * @Author: leon
 * @Version: 1.0
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
    MyAnnotation[] value();
}

package com.leon.java8.annotation;

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

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

/**
 * ClassName:MyAnnotation
 * Package:com.leon.java8.annotation
 * Description:
 *    如果想要创建重复注解需要一个容器:
 *      @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
 *      @Retention(RetentionPolicy.RUNTIME)
 *      public @interface MyAnnotations {
 *          MyAnnotation[] value();
 *      }
 *    使用注解@Repeatable(MyAnnotations.class),来标注并指定容器注解
 *    设置 PARAMETER则可以在参数上进行标注
 * @Author: leon
 * @Version: 1.0
 */
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String value() default "重复注解";

}
package com.leon.java8.annotation;

import java.lang.reflect.Method;

/**
 * ClassName:MyClass
 * Package:com.leon.java8.annotation
 * Description:
 *
 * @Author: leon
 * @Version: 1.0
 */
public class MyClass {

    public static void main(String[] args) {

       Class<MyClass> claZZ = MyClass.class;

        try {
            Method show = claZZ.getMethod("show", String.class);

            MyAnnotation[] annotationsByType = show.getAnnotationsByType(MyAnnotation.class);

            for (MyAnnotation myAnnotation : annotationsByType) {

                System.out.println(myAnnotation.value());

            }

        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }


    }


    @MyAnnotation("hhh")
    @MyAnnotation("jjjj")
    public static void show(@MyAnnotation("p") String s){
        System.out.println("MyClass");
    }
}

2.类型注解

package com.leon.java8.annotation;

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

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

/**
 * ClassName:MyAnnotation
 * Package:com.leon.java8.annotation
 * Description:
 *    如果想要创建重复注解需要一个容器:
 *      @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
 *      @Retention(RetentionPolicy.RUNTIME)
 *      public @interface MyAnnotations {
 *          MyAnnotation[] value();
 *      }
 *    使用注解@Repeatable(MyAnnotations.class),来标注并指定容器注解
 *    设置PARAMETER则可以在参数上进行标注
 * @Author: leon
 * @Version: 1.0
 */
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String value() default "重复注解";

}
package com.leon.java8.annotation;

import java.lang.reflect.Method;

/**
 * ClassName:MyClass
 * Package:com.leon.java8.annotation
 * Description:
 *
 * @Author: leon
 * @Version: 1.0
 */
public class MyClass {

    public static void main(String[] args) {

       Class<MyClass> claZZ = MyClass.class;

        try {
            Method show = claZZ.getMethod("show", String.class);

            MyAnnotation[] annotationsByType = show.getAnnotationsByType(MyAnnotation.class);

            for (MyAnnotation myAnnotation : annotationsByType) {

                System.out.println(myAnnotation.value());

            }

        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }


    }


    @MyAnnotation("hhh")
    @MyAnnotation("jjjj")
    public static void show(@MyAnnotation("p") String s){
        System.out.println("MyClass");
    }
}

Comment