JDK8新特性

  • JDK8新特性
    • Lambda表达式
    • 函数式(Functional)接口
    • 方法引用与构造器引用
      • 方法引用
      • 构造器引用
    • 强大的 StreamAPI
      • 创建Stream方式
      • Stream 的中间操作
      • Stream 的终止操作
    • Optional 类

Java 8 (又称为jdk 1.8)是Java语言开发的一一个主要版本。
Java 8是oracle公司于2014年3月发布,可以看成是自Java5以来最具革命性的版本。Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性。

特点

  • 速度更快

  • 代码更少(增加了新的语法: Lambda 表达式)

  • 强大的Stream API

  • 便于并行最大化减少空指针异常: Optional

  • Nashorn引擎,允许在JVM.上运行JS应用

Lambda表达式

Lambda初体验

-> : Lambda 操作符、箭头操作符

左边:Lambda形参列表(就是抽象方法里的形参)

右边:Lambda 方法体(就是重写抽象方法的方法体)

   @Testpublic void test1() {// 普通写法Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("普通写法");}};r1.run();System.out.println("*********************************");// Lambda方式Runnable r2 = () -> System.out.println("Lambda写法");r2.run();}// 普通方式@Testpublic void test2() {}@Testpublic void test3() {Comparator<Integer> c1 = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return Integer.compare(o1, o2);}};System.out.println(c1.compare(10, 21));System.out.println("*********************");Comparator<Integer> c2 = (o1, o2) -> {return Integer.compare(o1, o2);};System.out.println(c2.compare(21, 2));}

Lambda 表达式的使用

  1. 形参可以省略参数类型,编译器自动进行 “类型推断”
  2. Lambda 若只需要一个参数时,参数的小括号可以省略
    @Testpublic void test4() {Consumer<String> c1 = s -> {System.out.println(s);};c1.accept("省略参数小括号");}
  1. Lambda 方法体有多条语句时,允许有 return 返回值

  2. Lambda 方法体只有一条语句时,return 和 大括号 都可以省略

    @Testpublic void test5() {Comparator<Integer> c2 = (o1, o2) -> Integer.compare(o1, o2);System.out.println(c2.compare(21, 2));}

Lambda表达式的本质: 就是接函数式口的实例,重写接口中的方法

函数式(Functional)接口

如果一个接口中,只声明了一个抽象方法,该接口就是函数式接口

  • 只包含一个抽象方法的接口,称为函数式接口。
  • 你可以通过Lambda表达式来创建该接口的对象。 (若Lambda表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)
  • 我们可以在一一个接口.上使用==@FunctionalInterface==注解,这样做可以检查它是否是-一个函数式接口。同时javadoc也会包含一条声明, 说明这个接口是一个函数式接口。
  • 在java.util.function包下定 义了Java 8的丰富的函数式接口

Java提供的四大函数式接口:

Consumer接口:

    @Testpublic void test() {// 普通写法method1(200d, new Consumer<Double>() {@Overridepublic void accept(Double aDouble) {System.out.println("消费了 " + aDouble);}});System.out.println("********************************");// Lambda 写法method1(300d, money -> System.out.println("消费了 " + money));}public void method1(Double money, Consumer<Double> consumer) {consumer.accept(money);}

Predicate接口:

    @Testpublic void test2() {List<String> lists = new ArrayList<>();lists.add("普京");lists.add("北京");lists.add("西京");lists.add("南京");// 普通写法List<String> list = method2(lists, new Predicate<String>() {@Overridepublic boolean test(String s) {return s.contains("京");}});System.out.println(list);System.out.println("*************************************");// Lambda 写法List<String> list1 = method2(lists,s -> s.contains("京"));System.out.println(list1);}public List<String> method2(List<String> list, Predicate<String> pre) {ArrayList<String> newList = new ArrayList<>();for (String s : list) {if (pre.test(s)) {newList.add(s);}}return newList;}

其他接口:

方法引用与构造器引用

方法引用

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用 !
  • 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一一个语法糖。

要求 : 实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致 !(针对情况一和情况二)

格式: 使用操作符 “::” 将类(或对象)与方法名分隔开来。

  • 如下三种主要使用情况:

    ➢对象::实例方法名

    ➢类::静态方法名

    ➢类::实例方法名 (特殊)

个人理解:

​ Lambda 和 方法引用都可以看做是函数式接口的实例,主要目的都是为了重写接口中的抽象方法。

​ Lambda 重写抽象方法主要是自己编写方法体

​ 方法引用重写抽象方法主要是 使用 方法的引用 编写方法体。但是具体是什么样的方法是由要求的。

代码演示:

   // 情况一:对象::实例方法@Testpublic void test1() {// Lambda 方式Consumer<String> con = s -> System.out.println(s);con.accept("Lambda方式");// 方法引用// void accept(T t);// void println(T t)// 接口中的抽象方法的形参列表和返回值,与方法引用的方法形参列表、返回值都一样。Consumer<String> con1 = System.out::println;con1.accept("方法引用");}// 情况二:类::静态方法@Testpublic void test3() {// Lambda方式// int compare(T o1, T o2);//  static int compare(int x, int y)Comparator<Integer> com1 = (o1,o2) -> Integer.compare(o1,o2);System.out.println(com1.compare(21, 22));// 方法引用的方式Comparator<Integer> com2 = Integer::compare;System.out.println(com1.compare(23, 22));}// 情况三: 类::实例方法(比较特殊)@Testpublic void test4() {// Lambda 方式// int compare(T o1, T o2);// int compareTo(String anotherString)// 这种情况比较特殊,接口中抽象方法的形参列表和方法引用中的形参列表不一样// 但是该方法是通过另外一个参数调用的,因此也可以使用方法引用Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);// 方法引用方式Comparator<String> com2 = String::compareTo;}

情况三比较特殊:当方法引用中的形参列表中的一个参数作为方法的调用者时,也可以使用方法引用

构造器引用

  // 传一个参数@Testpublic void test1() {// Lambda 方式Function<Long,User> fun1 = id -> new User(id);System.out.println(fun1.apply(10001L));// 构造器引用Function<Long,User> fun2 = User::new;System.out.println(fun2.apply(10002L));}// 传俩个参数@Testpublic void test2() {// Lambda 方式BiFunction<Long,String,User> bifun1 = (id,name) -> new User(id,name);System.out.println(bifun1.apply(10L, "李四"));// 构造器引用BiFunction<Long,String,User> bifun2 = User::new ;System.out.println(bifun2.apply(20L, "王五"));}// 数组引用: 将数组看成一个类,和构造器引用一样@Testpublic void test3() {// Lambda 方式Function<Integer,String[]> fun1 = length -> new String[length];System.out.println(Arrays.toString(fun1.apply(5)));// 数组引用Function<Integer,String[]> fun2 = String[]::new;System.out.println(Arrays.toString(fun2.apply(10)));}

强大的 StreamAPI

Java8中有两大最为重要的改变。第一一个是Lambda表达式;另外- 一个则是Stream API。|

  • Stream API ( java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充
  • Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。

简言之,StreamAPl 提供了一种高效且易于使用的处理数据的方式。

为什么要使用 Stream Api ?

  • 实际开发中,项目中多数数据源都来自于Mysq|l,Oracle等。 但现在数据源可以更多了,有MongDB,Radis等, 而这些NoSQL的数据就需要Java层面去处理。

  • Stream和Collection集合的区别: Collection是一种静态的内存数据结构,而Stream是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。

Stream到底是什么呢?

是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,Stream讲的是计算!”

注意

  • Stream 自己不会存储元素。
  • Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream.
  • Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream的操作三个步骤

  • 创建Stream

    • 一个数据源(如:集合、数组),获取一个流
  • 中间操作
    • 一个中间操作链,对数据源的数据进行处理
  • 终止操作(终端操作)
    • 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

创建Stream方式

通过集合

Java8中的Collection接口被扩展,提供了两个获取流的方法:

default Stream stream(): 返回一个顺序流
default Stream parallelStream(): 返回一一个并行流

    @Testpublic void test1() {// 方式一:通过集合List<User> userList = User.getUserList();Stream<User> stream = userList.stream();// 返回一个并行流Stream<User> parallelStream = userList.parallelStream();}

通过数组

Arrays 中定义了获取 stream 的方法:

public static <T> Stream<T> stream(T[] array) {}
    @Testpublic void test2() {// 方式二:通过数组User[] userArray = User.getUserArray();Stream<User> stream = Arrays.stream(userArray);}

通过Stream的of

    @Testpublic void test3() {// 通过Stream的ofStream<Integer> integerStream = Stream.of(1, 2, 3, 4);}

可以使用静态方法Stream.iterate()和Stream.generate(),创建无限流。

public static Stream iterate(final T seed, final UnaryOperator f) 迭代
public static Stream generate(Supplier s) 生成

    @Testpublic void test4() {// 方式四: 通过 iterate 和 generate// 获取20以内的偶数Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);// 生成数据Stream<List<User>> generate = Stream.generate(User::getUserList);}

Stream 的中间操作

筛选与切片

代码演示:

   // 1. 筛选与切片@Testpublic void test1() {Stream<User> stream = User.getUserList().stream();// Stream<T> filter(Predicate<? super T> predicate); 从流中排除某些元素// forEach: 流的终止操作// 排除工资低于 2000 的stream.filter(user -> user.getSalary() > 2000).forEach(System.out::println);System.out.println("*****************************************************");Stream<User> stream1 = User.getUserList().stream();// Stream<T> limit(long maxSize); 截断流,是其元素不得超过指定数stream1.limit(2).forEach(System.out::println);// 报错:java.lang.IllegalStateException: stream has already been operated upon or closed// 流一旦执行终止操作就会关闭,想要在使用再重新创建一个流// stream1.limit(3).forEach(System.out::println);System.out.println("*****************************************************");Stream<User> stream2 = User.getUserList().stream();// Stream<T> distinct(); 筛选流,通过元素的的hashCode和equals方法去除重复元素stream2.distinct().forEach(System.out::println);System.out.println("*****************************************************");Stream<User> stream3 = User.getUserList().stream();// Stream<T> skip(long n); 跳过 n 个元素,若不足n个元素,则返回一个空流stream3.skip(3).forEach(System.out::println);}

映射

    // 映射@Testpublic void test2() {List<User> users = User.getUserList();// <R> Stream<R> map(Function<? super T, ? extends R> mapper);Stream<Double> stream = users.stream().map(User::getSalary);System.out.println(stream);}
}

排序

代码演示:

    @Testpublic void test1() {Stream<Integer> stream = Arrays.asList(2, 1, 33, 22, 11).stream();// Stream<T> sorted(); 按自然顺序排序stream.sorted().forEach(System.out::println);Stream<User> stream1 = User.getUserList().stream();//    Stream<T> sorted(Comparator<? super T> comparator); 自定义排序规则stream1.sorted(Comparator.comparingDouble(User::getSalary)).forEach(System.out::println);}

Stream 的终止操作

匹配与查找

boolean allMatch(Predicate<? super T> predicate); 检查流中所有元素都匹配
boolean anyMatch(Predicate<? super T> predicate); 检查流中元素是否至少有一个匹配
boolean noneMatch(Predicate<? super T> predicate); 检查流中元素是否都不匹配
Optional findFirst(); 返回流中第一个元素
Optional findAny(); 返回流中最后一个元素
long count(); 返回流中的个数
Optional max(Comparator<? super T> comparator); 返回流中最大的的元素
Optional min(Comparator<? super T> comparator); 返回流中最小的元素
void forEach(Consumer<? super T> action); 迭代遍历

代码演示:

 @Testpublic void test1() {List<User> users = User.getUserList();// boolean allMatch(Predicate<? super T> predicate); 检查流中是否所有元素都匹配// 检查是否所有的用户工资都大于 2000boolean allMatch = users.stream().allMatch(user -> user.getSalary() > 2000);System.out.println(allMatch);//  boolean anyMatch(Predicate<? super T> predicate); 检查流中是否有元素匹配上boolean anyMatch = users.stream().anyMatch(user -> user.getSalary() > 10000);System.out.println(anyMatch);// boolean noneMatch(Predicate<? super T> predicate); 检查流中是否都不匹配boolean noneMatch = users.stream().noneMatch(user -> user.getName().startsWith("王"));System.out.println(noneMatch);// Optional<T> findFirst(); 返回流中的第一个元素Optional<User> first = users.stream().findFirst();System.out.println(first);// Optional<T> findAny(); 随机返回流中的元素Optional<User> any = users.stream().findAny();System.out.println(any);//long count(); 返回流中元素的个数long count = users.stream().count();System.out.println(count);//  Optional<T> max(Comparator<? super T> comparator); 返回流中的最大值// 练习:返回工资最高的用户Optional<User>   max = users.stream().max(Comparator.comparingDouble(User::getSalary));System.out.println(max);//Optional<T> min(Comparator<? super T> comparator); 返回流中的最小值// 练习:返回用户中最少的工资// 使用 map 映射 工资,返回一个只有工资的流Optional<Double> min = users.stream().map(User::getSalary).min(Double::compare);System.out.println(min);// void forEach(Consumer<? super T> action); 迭代遍历users.stream().forEach(System.out::println);}

归约

代码演示:

    // 归约@Testpublic void test2() {List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// T reduce(T identity, BinaryOperator<T> accumulator); 将流中的值反复结合起来得到一个新的值// 练习:计算1-10的和Integer reduce = integerList.stream().reduce(0, Integer::sum);System.out.println(reduce);List<User> users = User.getUserList();// Optional<T> reduce(BinaryOperator<T> accumulator); 将流中的值反复结合起来得到一个新的值,返回Optional<T>// 练习:计算所有用户的工资总和Optional<Double> reduce1 = users.stream().map(User::getSalary).reduce(Double::sum);System.out.println(reduce1);}

收集

形参需要使用 Collectors 提供实例,调用以下方法

Optional 类

  • 到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类 已经成为Java 8类库的一部分。

  • Optional 类(java.util.Optional) 是-一个 容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示-一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。

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

jdk8新特性(Lambda、Steam、函数式接口)相关推荐

  1. JDK8新特性-Lambda

    JDK8新特性-Lambda 说明 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). 使用 L ...

  2. Java JDK1.8新特性之四大函数式接口

    JDK 1.8的一些新特性 四大核心函数式接口(Consumer.Predicate.Supplier.Function),结合lambda表达式 import java.util.ArrayList ...

  3. Java新特性:Java8函数式接口与Lambda表达式(一)

    摘要 何为函数式接口? 什么是lambda表达式,lambda表达式的本质: 函数式接口与lambda表达式的联系:lambda是实现函数式接口的一个快捷方式,可以作为函数式接口的一个实例: 常用Ja ...

  4. JDK8新特性-java.util.function-Function接口

    14年,Oracle公司如期发布了Java 8正式版.现如今4年过去了,终于鼓起勇气认真对待它,就好似虽然认识了好几年的伙伴,突然感觉要成为情侣的感觉-- JDK 1.8 API包含了很多内建的函数式 ...

  5. jdk8新特性 lambda表达式详解

    本文主要讲到的内容有: 一- 前言 二- 背景 三- lambda表达式的语法 四- Lambda程序例子 4-1 Runnable Lambda 4-2 Comparator Lambda 4-3 ...

  6. JDK8新特性-Lambda表达式查找

    2019独角兽企业重金招聘Python工程师标准>>> 1. Lambda语法的三种形式 (参数) -> 单行语句 (参数) -> {多行语句} (参数) -> 表 ...

  7. JDK8新特性-java.util.function-Predicate接口

    上篇主要对Function函数进行了简单了解,本篇则主要了解Predicate.该函数的主要作用其实就是判定输入的对象是否否和某个条件,然后将其布尔值返回. 主要使用方法如下: //唯一的抽象方法 b ...

  8. jdk8新特性-Lambda表达式,方法引用

    Lambda方法引用的概念 1).什么是"方法引用":当我们使用Lambda实现一些功能时,发现已有的类库中已经有方法实现了这样的功能,这时,我们就可以引用已实现的方法来代替Lam ...

  9. 反射、注解、动态代理、JDK8新特性

    反射.注解.动态代理.JDK8新特性 第一章.反射 1.类的加载 源文件--通过javac编译-->字节码文件---通过Java命令(通过ClassLoader)--->JVM运行字节码文 ...

最新文章

  1. modalDialog注意点
  2. Coursera系列-R Programming第三周-词法作用域
  3. Synchronize锁重入
  4. Jaspersoft Studio简介
  5. URAL 1047 Simple Calculations
  6. 【算法】广度遍历算法的应用 求出距离顶点v0的最短路径长度为最长的一个顶点,图结构的bfs生成树及其双亲表示形式
  7. Netweaver工作进程的内存限制 VS CloudFoundry应用的内存限制
  8. VxWorks关于任务创建的几个函数的概述
  9. [转载] JVM中对象的回收过程
  10. 第 1-6 课:玩转时间 + 面试题
  11. 逆波兰式数学表达式求解
  12. matlab滤波器函数6,matlab中滤波器函数filter的c语言实现
  13. 微型四轴飞行器(1)
  14. ARCH模型的R语言实现
  15. iOS常用的功能(打电话、发短信、发邮件等)
  16. 比较好的Java 网站
  17. Weighted Interval Scheduling VS Interval Scheduling
  18. 高防服务器的适用场景
  19. LINUX-挂载(如U盘挂载)
  20. 「镁客早报」未来中国数据量将超美国;巴菲特四季度股票资产缩水380亿美元,减持苹果甲骨文...

热门文章

  1. 亚商投资顾问 早餐FM/0116《证券经纪业务管理办法》发布
  2. 《数字图像处理》DFT(离散傅里叶变换)及HF(同态滤波)的实现
  3. Storwize V7000剖析:走进存储系统的SVC
  4. 大容量U盘/移动硬盘100%成功制作WINPE启动盘
  5. 纸鸢|对物联网平台的全面实践认知
  6. windows phone(成语典籍游戏开发)
  7. 企服三会亮点抢先看,与1200位大咖一起洞见2019
  8. Java中Array、List、Map相互转换
  9. 计算机网络系统设备安装工程,第一章-计算机网络系统设备安装工程-定额(14页)-原创力文档...
  10. linux环境下将nginx编译安装至指定目录步骤详解