Java8新特性简介:
注意:
此篇主要整理的式Lambda表达式与Stream API以及Optional
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递). 可以写出更简洁,更灵活的代码. 作为一种更紧凑的代码风格, 使Java语言表达能力得到了提升.
在写代码的时候我们可能只需要return Integer.compare(o1,o2); Lambda表达式可以使代码更加简洁
import org.junit.Test;
import java.util.*;
/**
* @Author
* @Date
**/
public class TestLambda {
//匿名内部类的写法
@Test
public void test1(){
Comparator<Integer> integerComparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
TreeSet<Integer> integerComparators = new TreeSet<>(integerComparator);
}
//Lambda表达式
@Test
public void test2(){
Comparator<Integer> integerComparator = (x, y) -> Integer.compare(x, y);
TreeSet<Integer> integerComparators = new TreeSet<>(integerComparator);
}
}
基础语法:
Lambda表达式前提条件:
Lambda表达式需要"函数式接口"的支持
提示:
函数式接口: 接口中有且只有一个抽象方法的接口, 称为函数式接口. 可以使用注解@FunctionalInterface修饰, 可以检查是否是函数式接口.
Consumer : 消费型接口
void accept(T t);
Supplied : 供给型接口
T get();
Function
R apply(T t);
Predicate : 断言型接口
boolean test(T, t);
举例说明:
/**
* @Author
* @Date
**/
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class TestLambda3 {
//Consumer : 消费型接口
@Test
public void test1(){
happy(1000, (m) -> System.out.println("消费:" + m + "元"));
}
public void happy(double money, Consumer<Double> consumer){
consumer.accept(money);
}
//产生指定个随机数的集合
@Test
public void test2(){
List<Integer> list = getNumList(10, () -> (int) (Math.random() * 100));
for (Integer integer : list) {
System.out.println(integer);
}
}
public List<Integer> getNumList(int num, Supplier<Integer> supplier){
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < num; i++) {
Integer integer = supplier.get();
list.add(integer);
}
return list;
}
}
说明:
上面的代码就很好的解释了我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)
1. 方法引用:
若Lambda体中的内容已经有方法实现了, 我们就可以用"方法引用". 可以理解为方法引用时Lambda表达式的另外一种表现形式
主要有三种语法格式:
注意:
2. 构造器引用:
格式:
注意:
需要调用的构造器参数列表要和函数式接口抽象方法的参数列表保持一直
3. 数组引用:
格式:
上面三种类型的引用举例如下:
/**
* @Author
* @Date
**/
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class TestMethodRef {
//数组引用
@Test
public void test5(){
Function<Integer,String[]> fun = (x) -> new String[x];
String[] apply = fun.apply(10);
System.out.println(apply.length);
Function<Integer,String[]> fun1 = String[]::new;
String[] apply1 = fun1.apply(20);
System.out.println(apply1.length);
}
//构造器引用
@Test
public void test4(){
Supplier<Employee> sup = () -> new Employee();
//构造器引用方式
//这里使用的构造器也是根据Supplier接口中的抽象方法的参数进行匹配
Supplier<Employee> sup1 = Employee::new;
Employee employee = sup1.get();
System.out.println(employee);
//这里使用的构造器也是根据Function接口中的抽象方法的参数进行匹配
Function<Integer, Employee> fun = (x) -> new Employee(x);
Function<Integer, Employee> fun1 = Employee::new;
Employee apply = fun1.apply(21);
System.out.println(apply);
}
//类::实例方法名
@Test
public void test3(){
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
//②若Lambda参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数时就可以使用ClassName::method
BiPredicate<String, String> bp1 = String::equals;
}
//类::静态方法名
@Test
public void test2(){
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
//①Lambda体中的参数列表与返回值要和函数式接口抽象方法参数列表和返回值类型要一致
//也就是compare的参数列表和返回值和Comparator中的抽象方法的参数和返回值类型都是一致的
Comparator<Integer> com1 = Integer::compare;
int compare = com1.compare(12, 15);
System.out.println(compare);
}
//对象::实例方法名
@Test
public void test1(){
Consumer<String> con = (x) -> System.out.println(x);
PrintStream out = System.out;
Consumer<String> con1 = out::println;
}
}
Employee类
import java.util.Objects;
/**
* @Author
* @Date
**/
public class Employee {
private String name;
private int age;
private double salary;
public Employee(int age) {
this.age = age;
}
public Employee() {
}
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Double.compare(employee.salary, salary) == 0 &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
Java中有两个重要的改变. 一个是Lambda表达式, 另外一个则是Stream API(java.util.stream.*).
Stream是Java8中处理集合的关键抽象概念, 它可以指定你希望对集合进行的操作, 可以执行非常复杂的查找, 过滤和映射数据等操作. 使用Stream API对集合数据进行操作, 就类似于使用SQL执行的数据库查询. 也可以使用Stream API来并行执行操作. 简而言之,Stream API提供了一种高效且易于使用的处理数据的方式.
流(Stream)是数据渠道, 用于操作数据源(集合, 数组等)所生成的元素序列. 集合讲的是数据, 流讲的是计算.
注意:
创建流的四种方式:
举例说明:
/**
* @Author
* @Date
**/
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class TestStreamApi1 {
//创建Stream
@Test
public void test1(){
//1,可以通过Collection系列集合提供的stream()或者parallelStream() 并行的流
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2,通过Arrays中的静态方法stream()获取数组流
Employee[] employees = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(employees);
//3,通过Stream中的静态方法of()
Stream<String> stream3 = Stream.of("aaa", "bbb", "cc");
//4,创建无限流
//4.1迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return x + 2;
});
stream4.forEach(System.out::println);
//4.2生成
Stream<Double> stream5 = Stream.generate(Math::random);
stream5.forEach(System.out::println);
}
}
说明:
Employee类在上面的示例代码中有
方法 | 说明 |
---|---|
筛选与切片 | |
filter() | 接收Lambda,从流中排除某些元素 |
limit() | 截断流,使其元素不超过给定的数量 |
skip(n) | 跳过元素,返回一个丢掉前n个元素的流.若流中元素不足n个,则返回一个空流.与limit()互补 |
distinct() | 筛选,通过流所生成的元素的hashCode()和equals()方法去除重复元素 |
映射 | |
map() | 1. 接收Lambda,将元素转换为其他形式或提取信息. 2. 接收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素 |
flatMap() | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流 |
排序 | |
sorted() | 自然排序(comparable) |
sorted(Comparator com) | 定制排序(comparator) |
查找与匹配 | |
allMatch() | 检查是否匹配所有元素 |
anyMatch() | 检查是否至少匹配一个元素 |
noneMatch() | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中任意元素 |
count() | 返回流中元素的综合 |
max() | 返回流中的最大值 |
min() | 返回流中的最小值 |
方法 | 说明 |
---|---|
归约 | |
reduce(T identity, BinaryOperator accumulator) | 可以将流中的元素反复结合起来,得到一个新值 |
reduce(BinaryOperator accumulator) | 可以将流中的元素反复结合起来,得到一个新值 |
收集 | |
collect() | 将流转换为其他形式. 接收一个collector接口的实现,用于给Stream中的元素做汇总的方法 |
以上方法的部分示例代码:
/**
* @Author
* @Date
**/
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
public class TestStreamApi2 {
List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.9),
new Employee("李四",38,5555.5),
new Employee("王五",50,6666.6),
new Employee("王五",50,6666.6),
new Employee("王五",50,6666.6),
new Employee("赵六",16,3333.3),
new Employee("田七",8,7777.7)
);
//中间操作
/**
* 排序
* sorted() ----自然排序(comparable)
* sorted(Comparator com) ----定制排序(comparator)
*/
@Test
public void test7(){
List<String> list = Arrays.asList("aaa","ddd","rrr","ccc");
list.stream()
.sorted()
.forEach(System.out::println);
employees.stream()
.sorted((e1,e2) -> {
if (e1.getAge() == e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else {
return e1.getName().compareTo(e2.getName());
}
}).forEach(System.out::println);
}
/**
* 映射
* map ----接收Lambda,将元素转换为其他形式或提取信息.接受一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素
* flatMap ----接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流
*
* map和flatMap的操作类似于list的add(Object obj) 和 addAll(collection coll)
*
*/
@Test
public void test5(){
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
list.stream().map(String::toUpperCase)
.forEach(System.out::println);
System.out.println("======================================");
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
System.out.println("======================================");
}
@Test
public void test6(){
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
list.stream()
.flatMap(TestStreamApi2::filterCharcter)
.forEach(System.out::println);
}
public static Stream<Character> filterCharcter(String str){
List<Character> list = new ArrayList<>();
for (char ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
/**
* 筛选与切片
* filter ----接收Lambda,从流中排除某些元素
* limit ----截断流,使其元素不超过给定数量
* skip(n) ----跳过元素,返回一个丢掉了前n个元素的流。若流中元素不足n个,则返回一个空流,与limit(n)互补
* distinct ----筛选,通过流所生成的元素的hashCode()和equals()去除重复元素
*/
@Test
public void test4(){
employees.stream()
.filter((x) -> x.getSalary() > 5000)
.skip(2)
.distinct()
.forEach(System.out::println);
}
@Test
public void test3(){
employees.stream()
.filter((x) -> {
System.out.println("短路!");
return x.getSalary() > 5000;
})
.limit(2)//获取到2条结果后就结束循环,有&& || 的效果
.forEach(System.out::println);
}
//内部迭代:迭代由Stream API完成
@Test
public void test1(){
employees.stream()
//中间操作:不会执行任何操作
.filter((x) -> {
System.out.println("filter的中间操作!");
return x.getAge() >= 35;
})
//终止操作:一次性执行全部操作,即"惰性求值"
.forEach(System.out::println);
}
//外部迭代
@Test
public void test2(){
Iterator<Employee> iterator = employees.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
/**
* @Author
* @Date
**/
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
public class TestStreamApi3 {
//终止操作
List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.9),
new Employee("李四",38,5555.5),
new Employee("王五",50,6666.6),
new Employee("王五",50,6666.6),
new Employee("王五",50,6666.6),
new Employee("赵六",16,3333.3),
new Employee("田七",8,7777.7)
);
/**
* 收集
* collect ----将流转换为其他形式.接收一个collector接口的实现,用于给Stream中元素做汇总的方法
*/
@Test
public void test03(){
List<String> list = employees.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
Set<String> set = employees.stream()
.map(Employee::getName)
.collect(Collectors.toSet());//去重
set.forEach(System.out::println);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
HashSet<String> hashSet = employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new));
hashSet.forEach(System.out::println);
}
/**
* 规约
* reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ---- 可以将流中的元素反复结合起来,得到一个新值
*/
@Test
public void test02(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream()
.reduce(0, Integer::sum);
System.out.println(sum);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
Optional<Double> sarlySum = employees.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(sarlySum.get());
}
/**
* 查找和匹配
* allMatch ----检查是否匹配所有元素
* anyMatch ----检查是否至少匹配一个元素
* noneMatch ----检查是否没有匹配所有元素
* findFirst ----返回第一个元素
* findAny ----返回当前流中的任意元素
* count ----返回流中元素的综合
* max ----返回流中的最大值
* min ----返回流中的最小值
*/
@Test
public void test(){
boolean b = employees.stream()
.noneMatch((e) -> e.getName().equals("郑八"));
System.out.println(b);//true
}
}
Optional
常用方法:
方法名 | 说明 |
---|---|
Optional.of(T t) | 创建一个Optional实例 |
Optional.empty() | 创建一个空的Optional实例 |
Optional.ofNullable(T t) | 若 t 不为null, 创建Optional实例, 否则创建空Optional实例 |
isPresent() | 判断是否包含值 |
orElse(T t) | 如果调用对象包含值, 返回该值,否则返回t |
orELseGet(Supplier s) | 如果调用对象包含值,返回该值,否则返回s获取的值 |
map(Function f) | 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty() |
flatMap(Function f) | 与map类似,要求返回值必须是Optional |
简单示例如下:
import org.junit.Test;
import java.util.ArrayList;
import java.util.Optional;
/**
* @Author
* @Date
**/
public class OptionalTest1 {
/**
* Optional.of(T t) -- 创建一个Optional实例
* Optional.empty() -- 创建一个空的Optional实例
* Optional.ofNullable(T t) -- 若 t 不为null, 创建Optional实例, 否则创建空Optional实例
* isPresent()
*/
@Test
public void test1(){
ArrayList<String> arr1 = new ArrayList<>();
ArrayList<String> arr2 = new ArrayList<>();
Optional<ArrayList<String>> opt1 = Optional.ofNullable(null);
Optional<ArrayList<String>> opt2 = Optional.ofNullable(arr2);
arr1.add("Hello");
arr1.add("world");
Optional<ArrayList<String>> opt3 = Optional.of(arr1);
Optional<Object> opt4 = Optional.empty();
System.out.println(opt1.isPresent());
System.out.println(opt2.isPresent());
System.out.println(opt3.isPresent());
System.out.println(opt4.isPresent());
}
/**
* orElse(T t)和orElseGet(Supplier s)的区别
* 调用对象为空时,返回的都是后面参数的值
* 若不为空,orElse(T t)还是会执参数中的代码,并产生了调用方法中的对象,而orElseGet(Supplier s)只会返回调用对象中的值,并不会产生对象
*/
@Test
public void test2(){
ArrayList<String> arr1 = new ArrayList<>();
ArrayList<String> arr2 = new ArrayList<>();
Optional<ArrayList<String>> opt1 = Optional.ofNullable(null);
Optional<ArrayList<String>> opt2 = Optional.ofNullable(arr2);
arr1.add("Hello");
arr1.add("world");
Optional<ArrayList<String>> opt3 = Optional.of(arr1);
Optional<Object> opt4 = Optional.empty();
System.out.println(opt1.orElse(getDefaultValue()));
System.out.println(opt1.orElseGet(this::getDefaultValue));
System.out.println("===========================================");
System.out.println(opt3.orElse(getDefaultValue()));
System.out.println(opt3.orElseGet(this::getDefaultValue));
}
public ArrayList<String> getDefaultValue(){
System.out.println("我被调用了");
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("我是默认值");
return arrayList;
}
/**
* map(Function f)
* flatMap(Function f)
*/
@Test
public void test3(){
ArrayList<String> arr1 = new ArrayList<>();
ArrayList<String> arr2 = new ArrayList<>();
Optional<ArrayList<String>> opt1 = Optional.ofNullable(null);
Optional<ArrayList<String>> opt2 = Optional.ofNullable(arr2);
arr1.add("Hello");
arr1.add("world");
Optional<ArrayList<String>> opt3 = Optional.of(arr1);
Optional<Object> opt4 = Optional.empty();
Optional<String> s = opt3.map((x) -> x.get(1));
System.out.println(s.orElse("没有值"));
System.out.println("=============================");
Optional<String> s1 = opt3.flatMap((x) -> Optional.ofNullable(null));
System.out.println(s1.orElse("没有值"));
}
}
至此,Java8的部分新特性整理完毕!