Java8新特性

Java8新特性

函数式接口

概念

  • 有且只有一个抽象方法的接口,称之为函数式接口
  • 接口中可以包含其他的方法(默认,静态,私有),但是只能有一个抽象方法。
  • @FunctionalInterface注解

    • 检测接口是否是一个函数式接口
      • 是;编译成功
      • 否;编译失败(接口中没有抽象方法或抽象方法的个数大于1)
    • 格式;
      1
      2
      3
      4
      @FunctionalInterface
      public interface 接口名{
      抽象方法
      }
  • 使用;一般可以作为方法的参数和返回值类型

函数式编程

Lambda的延迟执行

  • Lambda特点;延迟执行
  • 作用;提升性能

常用函数式接口

Supplier接口

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

Consumer接口

  • java.util.function.Consumer<T>;接口包含抽象方法void accept(T t),意为消费一个指定泛型数据
  • 消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据,至于具体怎么消费,需要定义计算
  • 默认方法;addThen
    • 需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费
    • 源码;
      1
      2
      3
      4
      default Consumer<T andThen(Consumer<? super T> after){
      Objects.requirNonNull(after);
      return (T t)->{accept(t);after.accept(t);};
      }

Predicate接口

  • java.util.function.Predicate<T>接口;对某种数据类型的数据进行判断,结果返回一个Boolean值
  • 抽象方法;boolean test(T t);用来对指定数据类型数据进行判断的方法
  • 默认方法;

    • add;与

      1
      2
      3
      4
      default Predicate<T> and(Predicate<? super T> other) {
      Objects.requireNonNull(other);
      return (t) ‐> test(t) && other.test(t);
      }
    • or;或

      1
      2
      3
      4
      default Predicate<T> or(Predicate<? super T> other) {
      Objects.requireNonNull(other);
      return (t) ‐> test(t) || other.test(t);
      }
    • negate;非

      1
      2
      3
      default Predicate<T> negate() {
      return (t) ‐> !test(t);
      }

Function接口

  • java.util.function.Function<T,R>;接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件
  • 抽象方法;R apply(T t);根据类型T的参数获取类型R的的结果(一般用于类型转换)
  • 默认方法;
    • andThen

Stream流式思想

  • JDK1.8之后
  • 关注做什么,不关注怎么做
  • “Stream流”其实是一个集合元素的函数模型,它并不是集合,也不是数据结构,其本身并不存储任何元素(或其地址值)
  • Stream(流)是一个来自数据源的元素队列
    • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
    • 数据源流的来源。 可以是集合,数组等。
  • Stream操作还有两个基础的特征:
    • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
    • 内部迭代: 以前对集合遍历都是通过Iterator或者增强for的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式,流可以直接调用遍历方法。
  • 使用步骤
    1. 获取数据源
    2. 数据转换
    3. 执行操作获取想要的结果
  • 注意;
    • Stream流属于管道流,只能被消费一次,第一个Stream流调用完毕,就会关闭。

      获取流

  • 两种方法
    1. 所有的Collection集合都可以通过stream默认方法获取流
    2. Stream接口的静态方法of可以获取数组对应的流

      java.util.stream.Stream<T>是Java8新加入的最常用的流接口

      根据COllection获取流

  • default Stream<E> stream()

根据Stream接口获取流

  • static <T> Stream<T> of(T...values);参数是一个可变参数,可以传递一个数组

常用方法

  • 延迟方法;返回值类型仍然是Stream接口自身类型的方法,因此支持链式调用。
  • 终结方法;返回值类型不再是Stream接口自身类型的方法,因此不再支持类似StringBuilder那样的链式调用
    逐一处理;foreach
  • void forEach(Consumer<? super T> action);该方法接收一个Consumer接口函数,会将每一个流元素交给该函数进行处理
  • forEach方法,用来遍历流中的数据,是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法
    过滤;filter
  • Stream<T> filter(Predicate<? super T> predicate);可以通过filter方法将一个流转换为另一个子集流
    映射;map
  • <R> Stream<R> map(Function<? super T, ? extends R> mapper);;将流中的元素映射到另一个流中,可以使用map方法
    统计个数;count
  • long count();用于统计Stream流中元素的个数
  • count方法是一个终结方法,返回值是一个long类型的整数,所有不能再继续调用Stream流中的其他方法
    取用前几个;limit
  • Stream<T> limit(long maxSize);;用于截取流中的元素
  • limit是一个延迟方法,只是对流中的元素进行截取,返回是一个新的流,所以可以继续调用Stream流中的其他方法
    跳过前几个;skip
  • Stream<T> skip(long n);;用于跳过元素
  • 如果流的当前长度大于n,则跳过前n个,否则会得到一个长度为0的空流
    组合;concat
  • static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b);将两个流合并为一个流
  • 这是一个静态方法,与String中的concat方法不同

方法引用

  • 方法引用符:双冒号::为引用运算符,而它所在的表达式被称为方法引用。如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者
  • 语义;
    • Lambda表达式写法: s -> System.out.println(s);拿到参数之后经Lambda之手,继而传递给 System.out.println 方法去处理。
    • 方法引用写法:System.out::println;直接让System.out 中的 println 方法来取代Lambda。两种写法的执行效果完全一样,而第二种方法引用的写法复用了已有方案,更加简洁。

      注:Lambda中传递的参数一定是方法引用中的那个方法可以接收的类型,否则会抛出异常

  • 通过对象名引用成员方法
    • 通过对象名引用成员方法,使用前提是对象名已经存在,成员方法也是已经存在的
  • 通过类名称引用静态方法
  • 通过super引用成员方法
  • 通过this引用成员方法、
  • 类的构造器引用
  • 数组的构造器引用
Knowledge is priceless, thanks for your support !