新特性简介:
1、速度更快
2、代码更少(增加了新的语法:lambda表达式)
3、强大的Steam ApI
4、便于并行
5、最大化减少空指针异常:optional
6、Nashorn 引擎,允许在JVM上运行JS应用
“类型推断”——lambda表达式的类型依赖于上下文环境,是有编译器推断出来的
类型推断是根据 = 左边声明的数据类型,通常左边是接口类型,接口中抽象方法
我的理解:类型推断就是以接口中的抽象方法为模板 进行方法的刻录 我称之为给形参赋值的形参
lambda 是一个匿名函数,可以把lambda表达式理解为一段可以传递的代码。
可以写出更简洁、更灵活的、更紧凑的代码风格,是java的语言表达能力得到提升
lambd表达式 是Java语言中引入的一种新的语法元素和操作符
- > 操作符被称为lambda操作符,它将lambda分为两个部分
左侧:指定了lambda表达式需要的参数列表
右侧:指定了lambda体,是抽象方法的实现逻辑,也是lambda表达式要执行的功能
import org.junit.Test;
interface MyInterface{
void test(String str);
}
public class LambdaTest{
@Test
public void test1() {
MyInterface mi = new MyInterface() {
@Override
public void test(String str) {
System.out.println(str);
}
};
mi.test("匿名对象方法调用");
MyInterface mi2 = (String str) ->{
System.out.println(str);
};
mi2.test("lambda 匿名表达式");
}
}
只有一个抽象方法的接口称之为函数式接口
@FunctionalInterface 注解:检查该接口是否式一个函数式接口
Java内置四大核心函数式接口
消费型接口:有输入没输出
Consumer
void xxx (T t) 有参无返回值
抽象方法: void accept(T t)
@Test
public void test1() {
Consumer consumer1 = new Consumer() {
@Override
public void accept(String t) {
System.out.println(t);
}
};
consumer1.accept("abc");
Consumer consumer2 = t -> System.out.println(t);
consumer2.accept("123");
}
供给型接口:没输入有输出
Supplier
T xxx() 无参有返回值
抽象方法: T get()
@Test
public void test3() {
Supplier supplier1 = new Supplier() {
@Override
public Student get() {
return new Student(1,"小王",2,50.1);
}
};
System.out.println(supplier1.get());
Supplier supplier2 = () -> new Student(21,"小李",32,550.1);
System.out.println(supplier2.get());
}
函数型接口:有输入有输出
Function
R xxx(T t) 有一个参 有返回 有输入有输出
抽象方法:R apply(T t)
@Test
public void test4() {
Function function1 = new Function(){
@Override
public String apply(Integer t) {
return String.valueOf(t);
}
};
System.out.println(function1.apply(123));
Function function2 = t -> t.toString();
System.out.println(function2.apply(123));
}
判定型接口:有参 返回值为boolean
Predicate
boolean xxx
抽象方法 :boolean test(T t)
@Test
public void test6() {
Predicate predicate1 = new Predicate() {
@Override
public boolean test(Integer t) {
return t%2 != 0;
}
};
System.out.println(predicate1.test(1));
Predicate predicate2 = t -> t%2 != 0;
System.out.println(predicate2.test(2));
}
方法引用
当要传递给lambda体的操作,已经有实现的方法了,可以使用方法引用
方法引用:lambda表达式作为函数式接口的一个实例,通过方法的名字来指向一个方法
方法引用要求:实现抽象方法参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致
方法引用:使用操作符 " : : " 将类与方法名分隔开。
方法引用的三种情况:
1、对象 :: 实例方法名
2、类::静态方法名
3、类::实例方法名
构造器引用
把构造器引用赋值给定义的方法,要求构造器参数列表要与接口中抽象方法的参数列表一致,
且方法的返回值即为构造器对应类的对象
Function fun = (n) - > new MyClass()
// 等同于
Function fun = MyClass::new;
数组引用
格式:type[] :: new
Function fun = (n) -> new Integer[n];
// 等同于
Function fun = Integer[]:: new;
Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中
Stream API 是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用Stream API 对集合数据进行操作,类似于使用SQL执行的数据库查询
Steam API 提供了一种高效且易于使用的处理数据的方式。
Stream是数据渠道,用于操作数据源(集合、数组)所生成的元素序列
1、Stream不是集合,自己不会存储元素
2、Stream不会改变源对象,每次操作会返回一个新的Stream
3、Stream操作是延迟操作,必须搞清楚有那些数据才能往下执行
4、Stream只能消费一次,如果想继续做其他操作,需要重新获取Stream对象
5、更像一个高级的iterator, 单向,不可王府,数据只能遍历一次,遍历过一次后即用尽
一个数据源(如;集合、数组),获取一个流
创建Stream四种方式:
方式一:通过集合
Java8中的Collection接口被扩展,提供了两个获取流的方法:
default Stream
default Stream
@Test
public void test1() {
List list = StudentData.getList();
Stream stream = list.stream();
stream.forEach(System.out::println);
}
方式二:通过数组
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
static
@Test
public void test2() {
Integer[] arr = {2,3,9,10};
Stream stream = Arrays.stream(arr);
stream.forEach(System.out::println);
}
方式三:通过散数据
可以调用Stream类静态方法 of(), 通过显示值创建一个流。它可以接收任意数量的参数。
lpublic static
@Test
public void test3() {
Stream of = Stream.of("abc","qqq","yyy");
of.forEach(System.out::println);
}
方式四:使用供给器
可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。
迭代
public static
生成
public static
@Test
public void test4() {
Stream stream = Stream.generate(Math::random);
stream.forEach(System.out::println);
}
一个中间操作链,对数据源的数据进行处理
filter(判定器) : 把流中的所有对象都经过判断器, 如果结果是true留下, 如果是false丢弃.
@Test
public void test6() {
List list = StudentData.getList();
list.stream().filter(t -> t.getScore()>59).filter(t->t.getGrade() ==2 ).forEach(System.out::println);
}
@Test
public void test5() {
List list = StudentData.getList();
list.stream().filter(t -> t.getScore()>59).forEach(System.out::println);
}
一旦执行终止操作,就执行中间操作链,并产生结果,之后,不会再被使用。
forEach(消费器)
stream.forEach(System.out::println);
Stream的中间操作
筛选和切片操作
映射操作
排序操作
终止操作
•终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
•流进行了终止操作后,不能再次使用。
匹配和查找
归约操作
备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它来进行网络搜索而出名。
收集操作
Optional
常用方法:
Optional.empty() : 创建一个空的 Optional 实例
Optional.of(T t) : 创建一个 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
T get(): 如果调用对象包含值,返回该值,否则抛异常
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
为了解决空指针异常,引入Optional类
Optional类实际上是个容器,可以保存类型T的值,可以保存null
Optional提供很多方法,可以不用显示进行空值检测
Optional类的Javadoc描述:这是一个可以为null的容器对象,如果值存在,
则isPresent()方法会返回true,调用get()方法会返回该对象