从SpringBoot 2.0.0开始,对于jdk的版本要求从原来的1.7改至1.8,很多人可能对这些新特性完全没有概念。那么对于2014年发布的jdk1.8的特性,你了解多少呢?在实际的编码中,你会想起用到的特性又有哪些?他究竟有哪些优势呢?请跟随我一起揭开它神秘的面纱,(#^.^#)
1.特点简介
- 速度更快
- 代码更少(增加了新的语法 Lambda 表达式)
- 强大的 Stream API
- 便于并行
- 最大化减少空指针异常 Optional
- Nashorm引擎,允许在JVM上运行JS应用
其中最为核心的为 Lambda 表达式与Stream API
2.Lambda表达式
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
2.1示例
匿名内部类方式:
Comparator<Integer> comparable = new Comparator<Integer>() {@Overridepublic int compare(Integer x, Integer y) {return Integer.compare(x, y);}};
lambda表达式:
Comparator<Integer> comparable = (x, y) -> Integer.compare(x, y);## 如果多个参数的顺序与执行的顺序一致,并且只有一条语句,可以进一步简化====>Comparator<Integer> comparable = Integer::compare;
总结:lambda的本质:作为函数式接口的实例
左边:
- 参数类型可以省略(lambda表达式运行依赖于上下文环境,是由编译器自动推断的,就是所谓的类型推断)
- 单个参数可以省略 (),如果只有一句执行语句,可以都省略
2.函数式接口
- 如果一个接口中,只拥有一个抽象方法,那么就是一个函数式接口。我们也可以自定义接口实现。
- 在任何接口上使用@FunctionalInterface 注解作为检查是否符合规范使用。
如果lambda表达式抛出一个受检异常,那么需要在接口上声明这个异常。 ```java @FunctionalInterface //作为检查是否符合规范使用 public interface MyFunction2
{ public R getValue(T t1, T t2);
}
@Testpublic void test3(){op(100L, 200L, (x, y) -> x + y);op(100L, 200L, (x, y) -> x * y);}//需求:对于两个 Long 型数据进行处理public void op(Long l1, Long l2, MyFunction2<Long, Long> mf){System.out.println(mf.getValue(l1, l2));}
<a name="nhPv9"></a>## 2.1JAVA内置四大接口函数<a name="zlFxV"></a># 3.方法引用和构造器引用<a name="l3X7A"></a>## 3.1方法引用当要传递给Lambda体的操作,已经有实现的方法了,可以用方法引用。注意:实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致,包括顺序。<br />主要有以下三种使用情况:- 对象::实例方法- 类::静态方法- 类::实例方法**_类::静态方法_**```javaMyFunction001 myFunction001 = str -> System.out.println(str);转化为=====>MyFunction001 myFunction001 = System.out::println;=====================================如果是以下形式,则不能使用MyFunction001 myFunction001 = str -> System.out.println(str+"");
对象::实例方法
Comparator<Integer> comparable = (x, y) -> Integer.compare(x, y);int compare = comparable.compare(6, 4);转化为=====>Comparator<Integer> comparable = Integer::compare;int compare = comparable.compare(6, 4);
类::实例方法
注意:当需要引用方法的第一个参数是调用对象,并且第二个参数是需要引
用方法的第二个参数(或无参数)时:ClassName::methodName
MyFunction001 myFunction001 = (str1, str2) -> str1.equals(str2);myFunction001.test("aa","bb");转化为=====>//标记为String是因为类型推断为String类MyFunction001 myFunction001 = String::equals;myFunction001.test("aa","bb");
3.2构造器引用

Supplier<Employee> supplier = new Supplier<Employee>() {@Overridepublic Employee get() {return new Employee();}};或者MyFunction001<Employee> supplier = (name, age) -> new Employee(name, age);均可以转化为=====>Supplier<Employee> supplier = Employee::new;
3.3数组引用
格式:type[]::new
Function<Integer,Integer[]> function = new Function<Integer, Integer[]>() {@Overridepublic Integer[] apply(Integer integer) {return new Integer[integer];}};转化==>Function<Integer,Integer[]> function = integer -> new Integer[integer];转化==>Function<Integer,Integer[]> function = Integer[]::new;
4.Stream API
4.1简介
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*)。Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
目的是写出高效、简洁的代码。
为什么使用 Stream API?
实际项目过程中,除了多数来自于Mysql等关系型数据库的数据以外,还会使用redis、MongDB等NoSql数据库。而这些数据需要Java来进行处理。
Stream和Collection集合的区别:
Collection是一种静态的内存数据结构,而Stream是有关计算的。前者面向内存进行存储,而后者面向CPU进行计算。
流(Stream) 到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”
注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
4.2Stream 操作三个步骤
创建Stream:
一个数据源(如:集合或者数组)
中间操作:
一个中间操作链,对上游数据进行处理然后交给下游。
终止操作(终端操作)
一旦执行终止操作,就会执行中间操作链得到结果,操作完成后就结束。
4.3Stream创建方式
//方式一:通过集合List<Employee> emps = Arrays.asList(new Employee(101, "张三", 18, 9999.99),new Employee(102, "李四", 59, 6666.66),new Employee(103, "王五", 28, 3333.33),new Employee(104, "赵六", 8, 7777.77),new Employee(105, "田七", 38, 5555.55));//返回一个顺序流Stream<Employee> stream = emps.stream();//返回一个并行流Stream<Employee> employeeStream = emps.parallelStream();//方式二:通过数组int[] arr = new int[]{1, 2, 3, 1, 4};IntStream stream1 = Arrays.stream(arr);//方式三:通过 of 方法Stream<Object> stream2 = Stream.of(1, 2, 3, 4, 5, "66");//方式四:创建无限流,自定义一些数据Stream.iterate(0, integer -> integer + 2).limit(10).forEach(System.out::println);
4.3Stream的中间操作
- 筛选和切片
多个中间操作可以连接起来形成流水链,只有触发了终止操作,中间操作一次性处理完成,称为“惰性求值”。
filter——接收 Lambda , 从流中排除某些元素。
limit——截断流,使其元素不超过给定数量。
skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
Stream API 和 传统遍历操作区别
//内部迭代:迭代操作 Stream API 内部完成@Testpublic void test2(){//所有的中间操作不会做任何的处理Stream<Employee> stream = emps.stream().filter((e) -> {System.out.println("测试中间操作");return e.getAge() <= 35;});//只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”stream.forEach(System.out::println);}//外部迭代@Testpublic void test3(){Iterator<Employee> it = emps.iterator();while(it.hasNext()){System.out.println(it.next());}}
映射
方法 | 描述-|-map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。 |mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。 |mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。|flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。|
排序
sorted():产生一个新流,按照自然排序。
sorted(Comparator comp):产生一个新流,按照比较器排序。
emps.stream().sorted((x, y) -> {if(x.getAge() == y.getAge()){return x.getName().compareTo(y.getName());}else{return Integer.compare(x.getAge(), y.getAge());}}).forEach(System.out::println);
4.3Stream的终止操作
终端操作会从流的流水线中生成结果,结果可以是任何不是流的值,例如 list、set、void。
查找与匹配
- allMatch——检查是否匹配所有元素
- anyMatch——检查是否至少匹配一个元素
- noneMatch——检查是否没有匹配的元素
- findFirst——返回第一个元素
- findAny——返回当前流中的任意元素
- count——返回流中元素的总个数
- max——返回流中最大值
- min——返回流中最小值
- forEach——内部迭代
注意:流进行了终止操作后,不能再进行操作了
@Testpublic void test1(){boolean bl = emps.stream().allMatch((e) -> e.getStatus().equals(Status.BUSY));System.out.println(bl);boolean bl1 = emps.stream().anyMatch((e) -> e.getStatus().equals(Status.BUSY));System.out.println(bl1);boolean bl2 = emps.stream().noneMatch((e) -> e.getStatus().equals(Status.BUSY));System.out.println(bl2);}@Testpublic void test2(){Optional<Employee> op = emps.stream().sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).findFirst();System.out.println(op.get());System.out.println("--------------------------------");Optional<Employee> op2 = emps.parallelStream().filter((e) -> e.getStatus().equals(Status.FREE)).findAny();System.out.println(op2.get());}//注意:流进行了终止操作后,不能再次使用@Testpublic void test4(){Stream<Employee> stream = emps.stream().filter((e) -> e.getStatus().equals(Status.FREE));long count = stream.count();//下面代码无效,会报错stream.map(Employee::getSalary).max(Double::compare);}
归约
reduce(T iden,BinaryOperator b)——可以将流的元素反复结合起来,得到一个值,返回 T。
reduce(BinaryOperator b)——可以将流的元素反复结合起来,得到一个值,返回 Optional
@Testpublic void test1(){List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);Integer sum = list.stream().reduce(0, (x, y) -> x + y);System.out.println(sum);System.out.println("----------------------------------------");Optional<Double> op = emps.stream().map(Employee::getSalary).reduce(Double::sum);System.out.println(op.get());}
收集
collect(Collecttor c)——接收一个Collection接口的实现,用于给Stream做元素汇总方法。
@Testpublic void test4(){Optional<Double> max = emps.stream().map(Employee::getSalary).collect(Collectors.maxBy(Double::compare));System.out.println(max.get());Optional<Employee> op = emps.stream().collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));System.out.println(op.get());Double sum = emps.stream().collect(Collectors.summingDouble(Employee::getSalary));System.out.println(sum);Double avg = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary));System.out.println(avg);Long count = emps.stream().collect(Collectors.counting());System.out.println(count);System.out.println("--------------------------------------------");DoubleSummaryStatistics dss = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));System.out.println(dss.getMax());}//分组@Testpublic void test5(){Map<Status, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));System.out.println(map);}//多级分组@Testpublic void test6(){Map<Status, Map<String, List<Employee>>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {if(e.getAge() >= 60)return "老年";else if(e.getAge() >= 35)return "中年";elsereturn "成年";})));System.out.println(map);}//分区@Testpublic void test7(){Map<Boolean, List<Employee>> map = emps.stream().collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));System.out.println(map);}//@Testpublic void test8(){String str = emps.stream().map(Employee::getName).collect(Collectors.joining("," , "----", "----"));System.out.println(str);}@Testpublic void test9(){Optional<Double> sum = emps.stream().map(Employee::getSalary).collect(Collectors.reducing(Double::sum));System.out.println(sum.get());}
5.Optional类
Optional 容器类:用于尽量避免空指针异常
- Optional.of(T t) : 创建一个 Optional 实例
- Optional.empty() : 创建一个空的 Optional 实例
- Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
- isPresent() : 判断是否包含值
- orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
- orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
- map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回
- Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
public String getGodnessName2(Optional<NewMan> man){return man.orElse(new NewMan()).getGodness().orElse(new Godness("老师")).getName();@Testpublic void test4(){Optional<Employee> op = Optional.of(new Employee(101, "张三", 18, 9999.99));Optional<String> op2 = op.map(Employee::getName);System.out.println(op2.get());Optional<String> op3 = op.flatMap((e) -> Optional.of(e.getName()));System.out.println(op3.get());}@Testpublic void test3(){Optional<Employee> op = Optional.ofNullable(new Employee());if(op.isPresent()){System.out.println(op.get());}Employee emp = op.orElse(new Employee("张三"));System.out.println(emp);Employee emp2 = op.orElseGet(() -> new Employee());System.out.println(emp2);}
6.重复注解与类型注解
7.并行流和串行流
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
//返回一个顺序流Stream<Employee> stream = emps.stream();//尝试返回一个可能存在的并行流,允许返回顺序流Stream<Employee> employeeStream = emps.parallelStream();
8.接口中的默认方法和静态方法
8.1默认方法
JAVA8允许接口中包含有具体实现的方法,该方法称为默认方法。使用 default关键字修饰
接口默认方法的”类优先”原则
若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时。
- 选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
- 接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突。
8.2静态方法
java8中,接口中允许添加静态方法。
9.新时间日期API
这一段没有细看,直接贴图了,还望谅解!








