Java8新特性

本文详细介绍了Java 8的新特性,包括Lambda表达式、函数式接口、接口的默认和静态方法、方法引用、Optional、Stream API以及新的日期/时间API。Lambda允许将函数作为方法参数,函数式接口如Supplier、Function等简化了代码。接口引入了默认方法和静态方法。方法引用用于简化代码,Optional提供了一种处理null的优雅方式。Stream API提供了高效的数据处理,支持串行和并行操作。Date/Time API改进了日期时间处理。此外,还涵盖了其他特性,如重复注解、类型推测机制等。
摘要由CSDN通过智能技术生成

文章目录

 

前言

提示:介绍Java8的新特性,包括Lambda表达式、函数式接口、方法引用、Optional、Stream流、日期类、其他

参考:https://www.runoob.com/java/java8-new-features.html

           https://www.cnblogs.com/woyaobianfei/p/9187127.html  

1、Lambda表达式

Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。

在JDK8之前,一个方法能接受的参数都是变量,例如: object.method(Object o)
那么,如果需要传入一个动作呢?比如回调。
那么你可能会想到匿名内部类。
例如:
匿名内部类是需要依赖接口的,所以需要先定义个接口

public interface PersonCallBack {
    void callBack(Person person);
}

Person类

public class Person {
 
    private int id;
 
    private String name;
 
    public Person (int id, String name) {
        this.id = id;
        this.name = name;
    }
 
    /**
     * 创建一个Person后进行回调
     * @param id
     * @param name
     * @param personCallBack
     */
    public static void create(Integer id, String name, PersonCallBack personCallBack) {
        Person person = new Person(id, name);
        personCallBack.callBack(person);
    }
 
}

调用方法:

        //  调用方法,传入回调类,传统方式,使用匿名内部类
        Person.create(1, "zhangsan", new PersonCallBack() {
            @Override
            public void callBack(Person person) {
                System.out.println("callback -- " +person.getName());
            }
        });

上面的PersonCallback其实就是一种动作,但是我们真正关心的只有callback方法里的内容而已,我们用Lambda
表示,可以将上面的代码就可以优化成:

 // 使用lambda表达式实现
 Person.create(2, "lisi", (person) -> {System.out.println("lambda callback -- " +person.getName());});
 // 进一步简化
 // 这归功于Java8的类型推导机制。因为现在接口里只有一个方法,那么现在这个Lambda表达式肯定是对应实现了这个方法,
 // 既然是唯一的对应关系,那么入参肯定是Person类,所以可以简写,
 // 并且方法体只有唯一的一条语句,所以也可以简写,以达到表达式简洁的效果。
 Person.create(2, "lisi", person -> System.out.println("lambda callback -- " +person.getName()));

Lambda允许把函数作为一个方法的参数,一个lambda由用逗号分隔的参数列表、–>符号、函数体三部分表示。

一个Lambda表达式实现了接口里的有且仅有的唯一一个抽象方法。那么对于这种接口就叫做函数式接口

Lambda表达式其实完成了实现接口并且实现接口里的方法这一功能,也可以认为Lambda表达式代表一种动作

我们可以直接把这种特殊的动作进行传递。

2、函数式接口

函数式接口是新增的一种接口定义。
@FunctionalInterface修饰的接口叫做函数式接口,或者,函数式接口就是一个只具有一个抽象方法的普通接口,@FunctionalInterface可以起到校验的作用。

@FunctionalInterface
public interface MyFunctionInterface {
 
    /**
     * 函数式接口的唯一抽象方法
     */
    void method();
 
}
 

在JDK7中其实就已经有一些函数式接口了,比如Runnable、Callable、FileFilter等等。
在JDK8中也增加了很多函数式接口,比如java.util.function包。
比如这四个常用的接口:

一个Lambda表达式其实也可以理解为一个函数式接口的实现者,但是作为表达式,它的写法
其实是多种多样的,比如

  • () -> {return 0;},没有传入参数,有返回值
  • (int i) -> {return 0;},传入一个参数,有返回值
  • (int i) -> {System.out.println(i)},传入一个int类型的参数,但是没有返回值
  • (int i, int j) -> {System.out.println(i)},传入两个int类型的参数,但是没有返回值
  • (int i, int j) -> {return i+j;},传入两个int类型的参数,返回一个int值
  • (int i, int j) -> {return i>j;},传入两个int类型的参数,返回一个boolean值

那么这每种表达式的写法其实都应该是某个函数式接口的实现类,需要特定函数式接口进行对应,比如上面的四种情况就分别对应:Supplier<T> , Function<T,R> , Consumer<T> , BiConsumer<T, U> , BiFunction<T, U, R> , BiPredicate<T, U> 。
Java8中提供给我们这么多函数式接口就是为了让我们写Lambda表达式更加方便,当然遇到特殊情况,你还是需要定义你自己的函数式接口然后才能写对应的Lambda表达式。
总的来说,如果没有函数式接口,就不能写Lambda表达式。

3、接口的默认方法和静态方法

在接口中用default修饰的方法称为默认方法

接口中的默认方法一定要有默认实现(方法体),接口实现者可以继承它,也可以覆盖它。

    /**
     * 接口的默认方法
     * @param s
     * @return
     */
    default String methodDefault(String s) {
        System.out.println(s);
        return "res--" + s;
    }

在接口中用static修饰的方法称为静态方法

    /**
     * 接口的静态方法
     * @param a
     * @param b
     * @return
     */
    static String methodStatic(String a, String b) {
        return a + b;
    }

4、方法引用

4.1、引用方法

  • 实例对象::实例方法名
  • 类名::静态方法名
  • 类名::实例方法名
        // 引用方法1   实例对象::实例方法名
        // System.out代表的就是PrintStream类型的一个实例,println是这个实例的一个方法
//        Consumer<String> consumer1 = s -> System.out.println(s);
        Consumer<String> consumer2 = System.out::println;
        consumer2.accept("呵呵");
 
        // 引用方法2   类名::静态方法名
        // Function中的唯一抽象方法apply方法参数列表与abs方法的参数列表相同,都是接收一个Long类型参数。
//        Function<Long, Long> f = x -> Math.abs(x);
        Function<Long, Long> f = Math::abs;
        Long result = f.apply(-3L);
 
        // 引用方法3  类名::实例方法名
        // 若Lambda表达式的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,就可以使用这种方法
//        BiPredicate<String, String> b = (x,y) -> x.equals(y);
        BiPredicate<String, String> b = String::equals;
        b.test("a", "b");

4.2、引用构造方法

        // 引用构造方法
        // 在引用构造方法的时候,构造方法参数列表要与接口中抽象方法的参数列表一致,格式为 类名::new
//        Function<Integer, StringBuffer> fun = n -> new StringBuffer(n);
        Function<Integer, StringBuffer> fun = StringBuffer::new;
        StringBuffer buffer = fun.apply(10);

4.3、引用数组

        // 引用数组
        // 引用数组和引用构造器很像,格式为 类型[]::new,其中类型可以为基本类型也可以是类
//        Function<Integer, int[]> fun = n -> new int[n];
        Function<Integer, int[]> fun1 = int[]::new;
        int[] arr = fun1.apply(10);
        Function<Integer, Integer[]> fun2 = Integer[]::new;
        Integer[] arr2 = fun2.apply(10);

5、Optional

Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

创建Optional对象的几个方法:

  1. Optional.of(T value), 返回一个Optional对象,value不能为空,否则会出空指针异常
  2. Optional.ofNullable(T value), 返回一个Optional对象,value可以为空
  3. Optional.empty(),代表空

其他API:

  1.  optional.isPresent(),是否存在值(不为空)
  2.  optional.ifPresent(Consumer<? super T> consumer), 如果存在值则执行consumer
  3.  optional.get(),获取value
  4.  optional.orElse(T other),如果没值则返回other
  5.  optional.orElseGet(Supplier<? extends T> other),如果没值则执行other并返回
  6.  optional.orElseThrow(Supplier<? extends X> exceptionSupplier),如果没值则执行exceptionSupplier,并抛出异常

高级API:

  1.  optional.map(Function<? super T, ? extends U> mapper),映射,映射规则由function指定,返回映射值的Optional,所以可以继续使用Optional的API。
  2.  optional.flatMap(Function<? super T, Optional< U > > mapper),同map类似,区别在于map中获取的返回值自动被Optional包装,flatMap中返回值保持不变,但入参必须是Optional类型。
  3.  optional.filter(Pre
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值