JDK1.8 新特性

JDK1.8 新特性

  • 是java语言开发的一个很重要的版本,Oracle 公司于 2014 年3月18日发布的。

  • 支持

    • Lambda 表达式

    • 函数式接口 ***

    • 新的Stream API ***

    • 新的日期时间 API

1. Lambda表达式

  • 特殊的匿名内部类,语法更加的简洁

  • 基本语法:

    • 函数式接口 变量名 = (参数列表)->{}

    • Runnable

    • Compartor

  • 注意问题

    • 形参列表的数据类型可以自动推断。

    • 形参为空,保留小括号。

    • 形参只有一个,可以省略小括号。

    • 如果执行语句只有一句,且没有返回值,可以省略大括号。

    • 如果执行语句只有一句,且有返回值,如果省略大括号,那么必须return 语句一起省略。

    • Lambda 不会生成一个单独的内部类文件。

  • package com.qf.lambda;

    import java.util.Comparator;
    import java.util.TreeSet;

    /**
    * Lambda 表达式 1:是一些特殊的接口的匿名子类对象的特殊的表达方式。
    * 特殊的接口:接口只能有一个抽象的方法没有实现。
    * 可以让代码变得很简洁。
    *
    * Lambda 的语法:
    * 父接口类型 父接口引用 = (形参列表)->{方法体}
    *
    * 特殊的语法:
    * 1:如果形参列表只有一个参数,那么小括号可以省略。形参的类型也可以省略。
    * 2: 如果方法体只有一句代码,也可以省略大括号。
    * 有返回值:如果省略大括号,return 也得省略。
    * 无返回值:直接省略大括号即可。
    * 3:形参列表为空,必须有小括号。
    *
    *
    */
    public class TestLambda {

    public static void main(String[] args) {
    // 匿名内部类。
    Runnable runnable = new Runnable() {
    @Override
    public void run() {
    System.out.println("run");
    }
    };
    new Thread(runnable).start();

    // Lambda
    Runnable run = () -> {
    System.out.println("run1");
    };
    new Thread(run).start();

    new Thread(() -> {
    System.out.println("run2");
    }).start();

    // 形参列表只有一个的情况
    Comparable<Integer> com = o -> 1;//有返回值的写法。
    MyInterface interface1 = o->System.out.println(o);//无返回值的写法。


    Comparator<Integer> com1 = new Comparator<Integer>() {
    public int compare(Integer o1, Integer o2) {
    return o1-o2;
    };
    };
    TreeSet<Integer> set = new TreeSet<>(com1);

    Comparator<Integer> com2 = (o1,o2)->o1-o2;

    TreeSet<Integer> set1 = new TreeSet<>(com2);

    TreeSet<Integer> set2 = new TreeSet<>((o1,o2)->o1-o2);

    }
    }

    interface MyInterface{
    void test(Object o);
    }
  •  

2. 函数式接口 ***

  • 有且仅有一个抽象方法的接口,称为函数式接口。只有函数式接口才能使用 Lambda 表达式。

  • JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在 java.util.function 包中被提供。

  • @FunctionalInterface 注解用于检测接口是否符合函数式接口

  • 常见的函数式接口

    • Supplier 生产型接口

      • java.util.function.Supplier 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对象数据。Supplier接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据。

      • 无参,有返回

    • Consumer 消费型接口

      • java.util.function.Consumer 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据(至于具体怎么消费(使用), 需要自定义(输出,计算…) 其数据类型由泛型决定。Consumer 接口中包含抽象方法 void accept(T t) ,意为消费一个指定泛型的数据。

      • 有参,无返回

    • Predicate 断言接口

      • 有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用 java.util.function.Predicate 接口。Predicate 接口中包含一个抽象方法: boolean test(T t) 。

      • 有参,返回boolean

    • Function 函数型接口

      • java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。Function 接口中最主要的抽象方法为: R apply(T t) ,根据类型T的参数获取类型R的结果。

      • 有参,有返回

  • 案例:

    • Supplier 生产随机的钱,Consumer 负责不同钱的消费。

    • Predicate 人名过滤功能。

    • Function 大小写的转换。

    • package com.qf.lambda;

      import java.util.ArrayList;
      import java.util.Arrays;
      import java.util.List;
      import java.util.function.Consumer;
      import java.util.function.Function;
      import java.util.function.Predicate;
      import java.util.function.Supplier;

      /**
      * 函数式接口:
      * 特点:如果一个接口中只有一个抽象方法,那么该接口就称为函数式接口。
      * 只有函数式接口才能使用 Lambda 表达式。
      *
      * JDK 提供的函数式接口: java.util.function 都在这个包下。
      * @FunctionalInterface 注解用来检查 接口是否满足 函数式接口。
      * 1:供给型接口:Supplier
      * 方法:无参有返回。
      * T get();
      * 通过该接口可以获取 T 类型的数据。
      * 2:消费型接口:Consumer
      * 方法:有参无返回。
      * void accept(T t);
      * 可以消费 T 类型的数据。
      * 3:断言型接口:Predicate
      * 方法:内容过滤,有参,有返回boolean。
      * boolean test(T t);
      * 判断 T 类型的 数据是否满足你的的要求。
      * 4:函数型接口:Function
      * 方法:做某些功能的实现,有参,有返回。
      * R apply(T t);
      * 对 T 类型的数据,进行加工,返回 R 类型的数据。
      */
      public class TestFunctionInterface {

      public static void main(String[] args) {
      // 1:供给型接口:Supplier
      int[] array = getArray(new Supplier<Integer>() {
      public Integer get() {
      return (int)(Math.random() * 100);
      }
      }, 10);

      System.out.println(Arrays.toString(array));
      // Lambda
      array = getArray(()->(int)(Math.random() * 100), 10);
      System.out.println(Arrays.toString(array));

      // 2:消费型接口:Consumer
      happy(new Consumer<Integer>() {
      @Override
      public void accept(Integer t) {
      System.out.println("佳欣花费了:"+ t +"元去看了一段让自己上火的舞蹈!");
      }
      }, 1000);

      happy(t->System.out.println("佳欣花费了:"+ t +"元去看了一段让自己上火的舞蹈!"), 1000);


      // 3:断言型接口:Predicate
      List<Integer> list = filterNums(new Predicate<Integer>() {
      public boolean test(Integer t) {
      return t%2==0;
      }
      }, array);
      System.out.println(list);

      List<Integer> list1 = filterNums(t->t%2==0, array);
      System.out.println(list1);

      // 函数型接口:Function
      String case1 = toUpperCase(new Function<String, String>() {
      @Override
      public String apply(String t) {
      return t.toUpperCase();
      }
      }, "abc");

      System.out.println(case1);

      String case2 = toUpperCase(t->t.toUpperCase(), "2134fjlerjoJLFJDLKdlkjfd");

      System.out.println(case2);

      }

      // 通过 Supplier 接口,获取若干个(count)整数,组成一个数组。
      public static int[] getArray(Supplier<Integer> supplier,int count){
      int[] arr = new int[count];

      for (int i = 0; i < count; i++) {
      arr[i] = supplier.get();
      }
      return arr;
      }

      // 消费钱去happy
      static void happy(Consumer<Integer> consumer,int money){
      consumer.accept(money);
      }

      // 将一个数组中的内容的偶数部分以List 形式返回。
      static List<Integer> filterNums(Predicate<Integer> predicate,int[] arr){
      List<Integer> list = new ArrayList<Integer>();

      for (int i = 0; i < arr.length; i++) {
      // 元素满足要求,添加到List 中。
      if(predicate.test(arr[i])){
      list.add(arr[i]);
      }
      }
      return list;
      }

      // 将任意的字符串转换为大写。
      static String toUpperCase(Function<String, String> fun,String str){
      return fun.apply(str);
      }
      }
    •  

3. 方法引用(了解)

  • 方法引用:Lambda表达式的简写形式。

  • 如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。

  • 常用形式:

    • 对象::实例方法

    • 类::静态方法

    • 类::实例方法

    • 类::new

package com.qf.day28;

import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
* 方法引用:Lambda表达式的简写形式。
* 如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
*/
public class MethodRef {
   public static void main(String[] args) {
       //形式1: 对象::实例方法
       Consumer<String> consumer1=s-> System.out.println(s);
       //(1)Lambda表达式只能包含一个方法调用 (2) 调用的方法的参数和返回值和接口中方法一致。
       Consumer<String> consumer2=System.out::println;
       consumer1.accept("hello");
       consumer2.accept("world");
       //形式2:类::静态方法
       //(1)Lambda表达式只能包含一个方法调用 (2)调用的方法的参数和返回值和接口中方法一致。
       Comparator<Integer> com1=(o1,o2)->Integer.compare(o1, o2);
       Comparator<Integer> com2=Integer::compare;
       //形式3:类::实例方法
       //(1)Lambda表达式只能包含一个方法调用 (2)一个参数作为调用者,其他作为参数
       Comparator<Integer> com3=(o1,o2)->o1.compareTo(o2);
       Comparator<Integer> com4=Integer::compareTo;
       //形式4:类::new
       //(1)Lambda表达式只能包含一个构造方法调用 (2)调用的构造方法的参数和接口中方法参数一致。
       Supplier<Student> sup1=()->new Student();
       Supplier<Student> sup2=Student::new;
       Student s1 = sup1.get();
       Student s2 = sup2.get();

       MySupplier<Student> sup3=(name,age)->new Student(name,age);
       MySupplier<Student> sup4=Student::new;

       Student s3 = sup3.get("张三", 20);
       Student s4 = sup4.get("李四", 22);
       //形式5:元素类型[]::new
       //(1)Lambda表达式只能包含一个数组的创建。(2)参数作为数组的长度
       Function<Integer,Student[]> fun1=n->new Student[n];
       Function<Integer,Student[]> fun2=Student[]::new;
       Student[] students = fun2.apply(5);
       System.out.println(students.length);
  }
}

4. Stream ***(Lambda应用)

  • Stream 与集合类似,但集合中保存的是数据,而Stream中保存的是对集合或者数组的数据的操作。所以 Stream是对数据集操作的集合

  • Stream 特点

    • 不会存储元素。

    • 不会改变源对象,它只会返回一个持有结果的新的Stream。

    • 操作的是延迟执行的,等需要结果的时候才会执行。

  • Stream 体系

    • BaseStream 接口

      • 四个子接口 DoubleStream、IntStream、LongStream、Stream

  • Stream的使用步骤

    • 创建流:新建一个流。

    • 中间操作:在一个或者多个步骤,将初始的Stream转换到另外一个Stream。

    • 终止操作:使用一个终止操作来产生一个结果,该操作会强制之前的延迟操作立即执行,然后Stream就不能使用了。

  • Stream的创建方式:

    • 使用Collection接口中stream()或parallelStream()。

    • 通过Arrays类的stream()方法。

    • 通过Stream接口的of()、iterate()、generate()方法。

      • Stream.iterate:迭代流 limit() 限制次数

    • 通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。

      • 范围控制

  • Stream 的中间操作

    • filter、limit、skip、distinct、sort

    • map

    • parallel

  • Stream 的终止操作

    • forEach、min、max、count

    • reduce 统计工资

    • collect 收集人名

5. 新的时间API

  • 之前的时间api存在的问题:

    • 线程非安全

      • 多个线程同时将一个日期字符串格式化成一个日期对象存在线程安全问题。

    • 时间可变

      • 可以对日期对象修改它的属性值。

  • java.time.LocalDateTime

    • 本地日期时间,不可变的

    • 创建对象:

      • LocalDateTime.now()

      • LocalDateTime.of(......)

    • 实例方法:

      • minus...

      • plus....

      • get.....

      • with....

  • Instant:时间戳

    • Instant类在Java日期与时间功能中,表示了时间线上一个确切的点,定义为距离初始时间的时间差(初始时间为GMT 1970年1月1日00:00)

    • 创建对象:

      • Instant.now() 格林尼治时间

      • Instant.ofEpochMilli(milliSeconds)

    • toEpochMilli()

    • minusMillis

    • plusMillis

  • ZoneId 时区

    • ZoneId.getAvailableZoneIds()

    • ZoneId.systemDefault()

  • Date--Instant--LocalTime (将原来的Date转换为LocalTime)

    Date date = new Date();
    Instant instant = date.toInstant();
    LocalDateTime time = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
  • LocalTime--Instant--Date

    LocalDateTime time = LocalDateTime.now();
    Instant instant = time.atZone(ZoneId.systemDefault()).toInstant();
    Date date = Date.from(instant);
  • DateTimeFormatter

    • 日期和字符串之间的相互转换

    LocalDateTime time = LocalDateTime.now();

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String result = dtf.format(time);

    String str = "2022-04-16 18:31:43";
    LocalDateTime time2 = LocalDateTime.parse(str,dtf);

     

  •  
posted @   ITboy搬砖人  阅读(119)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示