简介
jdk8的好处
- 1.速度更快
- 2.代码更少(增加新的语法Lambda表达式)
- 3.强大的Stream API
- 4.便于并行
- 5.最大化减少空指针异常 Optional
其中最为核心的为 Lambda 表达式与Stream API
1. Lambda 表达式
Lambda 是一个 匿名函数,我们可以把 Lambda
表达式理解为是 一段可以传递的代码(将代码
像数据一样进行传递)。可以写出更简洁、更
灵活的代码。作为一种更紧凑的代码风格,使
Java的语言表达能力得到了提升
1.1 从匿名类到 Lambda 的转换
1.2 参数传递
1.3 Lambda表达式语法
Lambda 表达式在Java 语言中引入了一个新的语法元
素和操作符。这个操作符为 “- -> >” , 该操作符被称
为 Lambda 操作符或剪头操作符。它将 Lambda 分为
两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行
的功能。
-
语法格式一 : 无参,无返回值,Lambda 体只需一条语句
-
语法格式二 :Lambda 需要一个参数(有参,无返回值)
-
语法格式三 :Lambda 只 需 要一个参数时,参数的小括号可以省略
-
语法格式四 :Lambda 需要两个参数,并且有返回值
-
语法格式五 : 当 Lambda 体只有 一条 语句时,return 与大括号 可以省略
-
语法格式六:数据类型可以省略, 因为可由编译器推断得出,称为"类型推断"
上述 Lambda 表达式中的参数类型都是由编译器推断
得出的。Lambda 表达式中无需指定类型,程序依然可
以编译,这是因为 javac 根据程序的上下文,在后台
推断出了参数的类型。Lambda 表达式的类型依赖于上
下文环境,是由编译器推断出来的。这就是所谓的
“类型推断”
2. 函数式接口
- 只包含一个抽象方法的接口,称为 函数式接口。
- 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda
表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方
法上进行声明)。 - 我们可以在任意函数式接口上使用
@FunctionalInterface
注解,
这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包
含一条声明,说明这个接口是一个函数式接口。
2.1 自定义函数式接口
2.1.1 函数式接口中使用泛型
2.2 作为参数传递 Lambda
作为递 参数传递 Lambda 将 表达式:为了将 Lambda 表达式作为参数传递,接
收 Lambda 该 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口
的类型。
4.Java内置四大核心函数是接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer<T> 消费型接口 |
T | void | 对类型为T的对象应用操作,包含方法:void accept(T t) |
Supplier<T> 供给型接口 |
无 | T | 返回类型为T的对象,包含方法:T get(); |
Function<T, R> 函数型接口 |
T | R | 对类型为T的对象应用操作, 并返回结果.结果是R类型的对象.包含方法: R apply(T t); |
Predicate<T> 断定型接口 |
T | boolean | 确定类型为T的对象是否满足某约束, 并返回Boolean值. 包含方法Boolean test(T t); |
public class Employee {
private int id;
private String name;
private int age;
private double salary;
public Employee() {
}
public Employee(String name) {
this.name = name;
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String show() {
return "测试方法引用!";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(salary);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (age != other.age)
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
return false;
return true;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
}
3. 方法引用与构造器引用
3.1 方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)
方法引用:使用操作符 “ ::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况 :
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
3.2 例子
PrintStream ps = System.out;
Consumer<String> con = (str) -> ps.println(str);
con.accept("Hello World!");
Consumer<String> con2 = ps::println;
con2.accept("Hello Java8!");
Hello World!
Hello Java8!
- 3.2.1 对象的引用 :: 实例方法名
Employee emp = new Employee(101, "zhangsan", 19, 99.9);
Supplier<String> sup = () -> emp.getName();
System.out.println(sup.get());
System.out.println("-------------");
Supplier supplier = emp :: getName;
System.out.println(supplier.get());
zhangsan
---
zhangsan
- 3.2.2 类名 :: 静态方法名
@Test
public void test03() {
BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x,y);
System.out.println(fun.apply(1.34, 20.22));
System.out.println("-----");
BiFunction<Double, Double, Double> function = Math:: max;
System.out.println(function.apply(34.22,10.33));
}
20.22
---
34.22
@Test
public void test04(){
Comparator<Integer> com = (x, y) -> Integer.compare(x,y);
System.out.println(com.compare(1, 2));
Comparator<Integer> comparator = Integer::compare;
System.out.println(comparator.compare(3,2));
}
-1
1
- 3.2.3 类名 :: 实例方法名
@Test
public void test05() {
//判断是否相同
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
System.out.println(bp.test("xu", "yu"));
System.out.println("----");
BiPredicate<String, String> bp1 =String:: equals;
System.out.println(bp1.test("xu", "yu"));
System.out.println("----");
Function<Employee, String> fun = (e) -> e.show();
System.out.println(fun.apply(new Employee()));
System.out.println("----");
Function<Employee, String> fun1 = Employee::show;
System.out.println(fun1.apply(new Employee()));
}
false
----
true
----
测试方法引用!
----
测试方法引用!
@Test
public void test06() {
Supplier<Employee> sup = () -> new Employee();
System.out.println(sup.get());
System.out.println("---");
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
}
Employee [id=0, name=null, age=0, salary=0.0]
---
Employee [id=0, name=null, age=0, salary=0.0]
3.3 构造器引用
- 3.3.1 简介
格式:
ClassName :: new
与函数式接口相结合,自动与函数式接口中方法兼容。
可以把构造器引用赋值给定义的方法,与构造器参数
列表要与接口中抽象方法的参数列表一致!
- 3.3.2 例子
@Test
public void test07() {
Function<String, Employee> fun = Employee::new;
System.out.println(fun.apply("xu"));
BiFunction<String, Integer, Employee> fun2 = Employee::new;
System.out.println(fun2.apply("xu", 2));
}
Employee [id=0, name=xu, age=0, salary=0.0]
Employee [id=0, name=xu, age=2, salary=0.0]
3.4 数组引用
- 3.4.1简介
格式:
type[] :: new
@Test
public void test08() {
Function<Integer, String[]> fun = (args) -> new String[args];
String[] strs = fun.apply(10);
System.out.println(strs.length);
System.out.println("------");
Function<Integer, Employee[]> fun2 = Employee[]::new;
Employee[] employees = fun2.apply(20);
System.out.println(employees.length);
}
10
------
20