Java 8

108 阅读5分钟

Java 8

Java8 (⼜称 JKD1.8) 是 Java 语⾔开发的⼀个主要版本。Oracle公司于2014年3⽉18⽇发布Java8 。

Lambda 表达式

  • Lambda表达式是特殊的匿名内部类,语法更简洁。
  • Lambda表达式允许把函数作为⼀个⽅法的参数(函数作为⽅法参数传递),将代码像数据⼀样传递。

注意事项:

  • 形参列表的数据类型会⾃动推断。
  • 如果形参列表为空,只需保留() 。
  • 如果形参只有1个,()可以省略,只需要参数的名称即可。
  • 如果执⾏语句只有⼀句,且⽆返回值,{}可以省略,若有返回值,则若想省去{},则必须同时省略return,且执⾏语句也保证只有⼀句。
  • Lambda不会⽣成⼀个单独的内部类⽂件。

函数式接口

  • 如果⼀个接⼝只有⼀个抽象⽅法,则该接⼝称之为函数式接⼝。
  • 函数式接⼝可以使⽤Lambda表达式,Lambda表达式会被匹配到这个抽象⽅法上 。
  • @FunctionalInterface 注解检测接⼝是否符合函数式接⼝规范。

常见的函数式接口

接⼝参数类型返回类型说明
Consumer< T > 消费型接⼝Tvoidvoid accept(T t);对类型为T的对象应⽤操作
Supplier< T > 供给型接⼝TT get(); 返回类型为T的对象
Function< T,R > 函数型接⼝TRR apply(T t);对类型为T的对象应⽤操作,并返回类型为R类型的对象。
Predicate< T > 断⾔型接⼝Tbooleanboolean test(T t);确定类型为T的对象是否满⾜条件,并返回 boolean类型。
public static void main(String[] args) {
    // 使用消费型接口
    happy(money -> System.out.println("聚餐花了" + money + "块钱"), 1000.0);
    // 使用供给型接口 -> 给别人提供需要的东西
    int[] nums = getNums(() -> new Random().nextInt(100), 10);
    System.out.println(Arrays.toString(nums));
    // 使用函数型接口 x -> y
    String hello = handler(String::toUpperCase, "hello");
    System.out.println(hello);

    ArrayList<String> list = new ArrayList<>();
    list.add("zhangsan");
    list.add("lisi");
    list.add("wangwu");
    list.add("zhang");
    // 使用断言型接口
    List<String> zhang = filter(a -> a.startsWith("zhang"), list);
    System.out.println(zhang);
}

// 消费型接口
public static void happy(Consumer<Double> consumer, Double money) {
    consumer.accept(money);
}
// 供给型接口
public static int[] getNums(Supplier<Integer> supplier, int count) {
    int[] nums = new int[count];
    for (int i = 0; i < count; i++) {
        nums[i] = supplier.get();
    }
    return nums;
}
// 函数型接口
public static String handler(Function<String, String> function, String s) {
    return function.apply(s);
}
// 断言型接口
public static List<String> filter(Predicate<String> predicate, List<String> list) {
    ArrayList<String> newArray = new ArrayList<>();
    for (String string : list) {
        if (predicate.test(string)) {
            newArray.add(string);
        }
    }
    return newArray;
}

方法引用

  • ⽅法引⽤是Lambda表达式的⼀种简写形式。
  • 如果Lambda表达式⽅法体中只是调⽤⼀个特定的已经存在⽅法,则可以使⽤⽅法引⽤。

常见形式

  • 对象::实例⽅法
  • 类::静态⽅法
  • 类::实例⽅法
  • 类::new

Stream

流(Stream)与集合类似,但集合中保存的是数据,⽽Stream中保存对集合或数组数据的操作。

Stream特点

  • Stream ⾃⼰不会存储元素。
  • Stream 不会改变源对象。相反,他们会返回⼀个持有结果的新Stream。
  • Stream 操作是延迟执⾏的,会等到需要结果的时候才执⾏。

使用步骤

创建

  • 新建⼀个流。 中间操作
  • 在⼀个或多个步骤中,将初始Stream转化到另⼀个Stream的中间操作。 终⽌操作
  • 使⽤⼀个终⽌操作来产⽣⼀个结果。该操作会强制之前的延迟操作⽴即执⾏,在此之后,该Stream就不能使⽤了。

创建Stream

  • 通过Collection对象的stream()或parallelStream()⽅法。
  • 通过Arrays类的stream()⽅法。
  • 通过Stream接⼝的of()、iterate()、generate()⽅法。
  • 通过IntStream、LongStream、DoubleStream接⼝中的of、range、rangeClosed⽅法。
public static void main(String[] args) {
    ArrayList<String> arrayList = new ArrayList<>();
    arrayList.add("zhangsan");
    arrayList.add("wangwu");
    arrayList.add("lisi");
    arrayList.add("zhang");
    Stream<String> stream = arrayList.stream();
    stream.filter(t -> t.startsWith("zhang")).forEach(System.out::println);

    // Arrays.stream()
    System.out.println(Arrays.stream(new int[]{2, 7, 3, 6, 5, 8, 9, 1}).count());

    // Stream().of | .iterate() | .generate()
    Stream.of(1, 2, 3, 4).filter(t -> t > 2).forEach(System.out::print);

    Stream.iterate(0, x -> x + 2).limit(5).forEach(System.out::print);

    Stream.generate(() -> new Random().nextInt(100)).limit(10).forEach(System.out::print);

    // range()
    IntStream.range(0, 20)/*.filter(t -> t > 4 && t < 15 )*/.forEach(System.out::println);
    System.out.println("----");
    IntStream.rangeClosed(0, 20)/*.filter(t -> t > 4 && t < 15 )*/.forEach(System.out::println);

}

中间操作

常见的中间操作

  • filter、limit、skip、distinct、sorted
  • map
  • parallel
public static void main(String[] args) {
    ArrayList<Student> arrayList = new ArrayList<>();
    arrayList.add(new Student("john", 18));
    arrayList.add(new Student("jack", 19));
    arrayList.add(new Student("rose", 18));
    arrayList.add(new Student("rose", 18));

    // filter 过滤
    Stream<Student> stream = arrayList.stream();
    stream.filter(s -> s.getAge() <= 18).forEach(System.out::println);
    System.out.println("===================limit====================");
    // limit 限制
    arrayList.stream().limit(2).forEach(System.out::println);
    System.out.println("=====================skip==================");
    // skip 跳过
    arrayList.stream().skip(2).forEach(System.out::println);
    System.out.println("====================distinct===================");
    // distinct 去重 -> 重写 equals 和 hasCode
    arrayList.stream().distinct().forEach(System.out::println);
    System.out.println("====================sort===================");
    // sort 排序
    arrayList.stream().sorted((Comparator.comparingInt(Student::getAge))).forEach(System.out::println);
    System.out.println("=====================map==================");
    // map 映射
    arrayList.stream().map(Student::getAge).forEach(System.out::println);
    System.out.println("=====================parallel==================");
    // parallel
    arrayList.stream().parallel().forEach(System.out::println);

}
  • 串⾏流和并⾏流:
    • 串⾏流使⽤单线程。
    • 并⾏流使⽤多线程,效率更⾼。

终止操作

常见的终止操作

  • forEach、min、max、count
  • reduce、collect
public static void main(String[] args) {
    ArrayList<Student> students = new ArrayList<>();
    students.add(new Student("john", 18));
    students.add(new Student("jack", 19));
    students.add(new Student("rose", 18));
    students.add(new Student("rose", 18));

    System.out.println("=====================min====================");
    // Optional 防止空指针异常的类
    Optional<Student> min = students.stream().min((Comparator.comparingInt(Student::getAge)));
    Student student = min.get();
    System.out.println(student);
    System.out.println("=====================max====================");
    System.out.println(students.stream().max(Comparator.comparingInt(Student::getAge)).get());
    System.out.println("=====================reduce====================");
    System.out.println(students.stream().map(Student::getAge).reduce(Integer::sum).get());
    System.out.println("=====================collect====================");
    List<Integer> collect = students.stream().map(Student::getAge).collect(Collectors.toList());
    for (Integer i : collect) {
        System.out.println(i);
    }
}

新时间API

本地化日期时间API

  • LocalDate
  • LocalTime
  • LocalDateTime
LocalDate localDate = LocalDate.now();
System.out.println(localDate);
LocalTime localTime = LocalTime.now();
System.out.println(localTime);
LocalDateTime dateTime = LocalDateTime.now();
System.out.println(dateTime);
System.out.println(dateTime.getYear());
System.out.println(dateTime.getMonth());
System.out.println(dateTime.getHour());
System.out.println(dateTime.getMinute());
System.out.println(dateTime.getSecond());

System.out.println(dateTime.getDayOfYear());
System.out.println(dateTime.getDayOfMonth());
System.out.println(dateTime.getDayOfWeek());

System.out.println(dateTime.minusDays(1));
System.out.println(dateTime.plusDays(1));

Instant

Instant:时间戳

Instant instant = Instant.now();

System.out.println(instant); // 2024-08-09T01:33:53.332525800Z
System.out.println(instant.getEpochSecond()); // 1723167233
System.out.println(instant.toEpochMilli()); // 1723167233332

Instant instant1 = instant.minusMillis(24 * 60 * 60 * 1000);
System.out.println(instant1); // 2024-08-08T01:34:56.871878300Z

Instant instant2 = instant.plusMillis(24 * 60 * 60 * 1000);
System.out.println(instant2); // 2024-08-10T01:35:22.490775Z

Instant now = Instant.now();
Thread.sleep(5000);
Instant now2 = Instant.now();
// 计算时间差 Duration.between()
long millis = Duration.between(now, now2).toMillis();
System.out.println(millis / 1000);

ZoneId

ZoneId:时区

Set<String> zoneIds = ZoneId.getAvailableZoneIds();
for (String zoneId : zoneIds) {
    System.out.println(zoneId);
}
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId);

Date、Instant、LocalDateTime

Date、Instant、LocalDateTime的转换

Date date = new Date();
System.out.println(date);
// date -> Instant
Instant instant = date.toInstant();
System.out.println(instant);
// Instant -> LocalDateTime
LocalDateTime localDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(localDateTime);
// LocalDateTime -> Instant
Instant instant1 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
System.out.println(instant1);
// Instant -> Date
Date from = Date.from(instant1);
System.out.println(from);

DateTimeFormatter

DateTimeFormatter:格式化类

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

LocalDateTime dateTime = LocalDateTime.now();
String format = dateTime.format(dateTimeFormatter);
System.out.println(format); // 2024-08-09 10:13:48

String date = "2024-08-09 10:13:48";
LocalDateTime time = LocalDateTime.parse(date, dateTimeFormatter);
System.out.println(time);