Java8特性

904 阅读6分钟

特性

  • **Lambda表达式   **允许把函数作为一个方法的参数传递到方法中

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

  • **默认方法    **接口可以有实现方法,而且不需要实现类去实现其方法。

  • **方法引用    **可以直接引用已有Java类或对象(实例)的方法或构造器

  • StreamApI对集合(Collection)对象功能的增强

  • **Date Time API   **加强对日期与时间的处理

  • Optional类   解决空指针异常。

Lambda表达式

Lambda 表达式,也可称为闭包。允许把函数作为方法的参数传递到方法中。lambda由逗号分隔的参数列表、->符号、函数体三部分组成。

语法:(parameters) -> expression 或 (parameters) ->{ statements; }

public interface PersonCallBack {    void callback();     } // 定义接口
public void test(String name, PersonCallBack callBack) {    
    System.out.println(name);    
    callBack.callback();   
}
public static void main(String[] args) {    
    new Person().test("张三", () -> {        
        System.out.println("18");    
    });
}

需要声明PersonCallBack接口为函数式接口。即接口中有且仅有唯一的一个抽象方法。lambda表达式其实就实现接口并且实现了接口中的唯一的方法。

  • **可选类型声明:**不需要声明参数类型,编译器可以统一识别参数值。
  • **可选的参数圆括号:**一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • **可选的大括号:**如果主体包含了一个语句,就不需要使用大括号。
  • **可选的返回关键字:**如果主体只有一个表达式返回值则编译器会自动返回值,使用大括号需要指定表达式返回了一个数值。

注意:lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

函数式接口

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

在java8中新增了很多  函数式接口  。在java.util.function包下。使我们使用lambda接口更加方便。下面列举常用接口。

默认方法和静态方法

接口中使用default修饰的方法为默认方法。用static修饰的方法为静态方法。

默认方法和静态方法就是接口可以有实现方法,而且不需要实现类去实现其方法。实现类也可以实现方法进行重写。

为什么要有这个特性?

首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题。

方法引用

方法引用通过方法的名字来指向一个方法,方法引用使用一对冒号 :: 。

方法的参数列表必须与函数式接口的抽象方法的参数列表保持一致,返回值不作要求。 

  • 引用方法

  • 实例对象::实例方法名 instance::method

    Consumer<String> consumer = System.out::println; 
    consumer.accept("ޮ张三");
    
  • **类名::静态方法名  **Class::static_method

    Function<Long, Long> f = Math::abs; 
    Long result = f.apply(-3L);
    
  • 类名::实例方法名  Class::method

    BiPredicate<String, String> b = String::equals; 
    b.test("a", "b");
    
  • 引用构造方法 Class::new

    Supplier<Person> supplier = Person::new;   
    Person person = supplier.get();
    
  • 引用数组

    Function<Integer, int[]> fun = int[]::new; 
    int[] arr = fun.apply(10);
    

Optional 类 

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

创建Optional对象的几个方法: 

  1. Optional.of(T value), 返回一个Optional对象,value不能为空,否则会出空指针异常 

  2. Optional.ofNullable(T value), 返回一个Optional对象,value可以为空

  3. Optional.empty(),代表空 

其他API

  • optional.isPresent(),是否存在值(不为空)

  • optional.ifPresent(Consumer<? super T> consumer), 如果存在值则执行consumer 

  • optional.get(),获取value

  • optional.orElse(T other),如果没值则返回other

  • optional.orElseGet(Supplier<? extends T> other),如果没值则执行other并返回

  • optional.orElseThrow(Supplier<? extends X> exceptionSupplier),如果没值则执行exceptionSupplier, 并抛出异常 

注意:

使用 Optional 时尽量不直接调用 Optional.get() , Optional.isPresent() 方法。 应依赖于 其他像 Optional.orElse(), Optional.orElseGet()等这样的方法.

Stream API

juejin.cn/post/688105…

Date Time API

Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。

java8之前

  • 非线程安全 java.util.Date 是非线程安全的,所有的日期类都是可变的

  • **设计很差       **日期/时间类的定义不一致,在java.util和java.sql的包中都有日期类。

  • **时区处理麻烦  **日期类并不提供国际化,没有时区支持

新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。

LocalDate类

LocalDate只持有ISO-8601格式且无时区信息的日期部分

LocalDate now = LocalDate.now(); // 2020-10-08
now = now.plusDays(2);  // 2020-10-10
now = now.plusMonths(1); // 2020-11-10
now = now.minusMonths(1); // 2020-10-10
now = now.minusDays(2); // 2020-10-08
LocalDate date3 = LocalDate.of(2020, Month.DECEMBER, 12); // 2020-12-12

获取当前日期,对其进行修改

LocalTime类

LocalTime只持有ISO-8601格式且无时区信息的时间部分

LocalTime now = LocalTime.now(); // 22:10:54.613
now = now.plusMinutes(12); // 22:22:54.613
now = now.minusHours(2); // 20:22:54.613
System.out.println(now.format(DateTimeFormatter.ofPattern("HH:mm:ss"))); // 20:22:54
LocalTime date4 = LocalTime.of(22, 15, 30); // 20:15:30
LocalTime date5 = LocalTime.parse("20:15:30"); // 20:15:30

获取当前时间,对其进行修改

LocalDateTime类

LocaleDateTim把LocaleDat与LocalTime的功能合并起来

ZonedDateTime类

从指定时区的系统时钟中获取当前日期时间。

ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/Los_Angeles"));
System.out.println(now); // 2020-10-08T07:13:54.754-07:00[America/Los_Angeles]

获取当前时区

ZoneId currentZone = ZoneId.systemDefault();
System.out.println("当期时区: " + currentZone); // 当期时区: Asia/Shanghai

Clock类

它通过指定一个时区,然后就可以获取到当前的时刻,日期与时间

Clock shanghai = Clock.system(ZoneId.of("Asia/Shanghai"));
System.out.println(LocalDateTime.now(shanghai)); // 2020-10-08T22:15:39.999

Duration类

Duration计算两个日期差

LocalDateTime start = LocalDateTime.parse("2020-01-01 22:10:10", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
LocalDateTime end = LocalDateTime.parse("2020-02-01 22:15:10", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Duration duration = Duration.between(start, end);
System.out.println(duration.toDays()); // 31
System.out.println(duration.toHours()); // 744