-
速度更快
-
对 HashMap 、ConcurrentHashMap低层的数据结构(数组+链表+二叉树)
-
低层的内存结构(将永久区更新为元空间,元空间使用的是物理内存)
-
-
代码更少(增加了新的语法 Lambda 表达式)
-
强大 Stream API
-
便于并行
-
最大化减少空指针异常 Optional
-
关于时间日期的 API
目录
一、Lambda 表达式
为什么使用 Lambda 表达式
//原来将匿名内部类作为参数进行传递
@Test
public void test1(){
TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
}
//java8中的 Lambda 表达式
@Test
public void test2(){
TreeSet<String> ts = new TreeSet<>((x, y) -> x.compareTo(y));
}
代码简洁。方便,快速的完成了接口实例和内部类的功能。
Lambda 表达式的基础语法
Lambda 提供了一个全新的操作符,该操作符为“ -> ”, 该操作符称为箭头操作或Lambda操作符。
箭头操作符将 Lambda 表达式分为两部分:
左侧:对应函数式接口中抽象方法的参数列表
右侧:对函数式接口中抽象方法的实现,即 Lambda 体
- 语法格式一:无参,无返回值
Runnable r1 = () -> System.out.println("Hello Lambda!");
- 语法格式二:有一个参数,无返回值
Cusumer<String> cus = (x) -> System.out.println(x);
- 语法格式三:若Lambda表达式左侧只有一个参数
Cusumer<String> cus = x -> System.out.println(x);
- 语法格式四:有两个以上参数,Lambda体中有多个条语句,有返回值
Comparator<Integer> com = (x, y) -> {
System.out.println("Lambda体中多条语句");
return Integer.compare(x, y);
};
- 语法格式五:若 Lambda 体中只有一条语句,return 和 大括号可以省略不写
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
- 语法格式六:Lambda 左侧参数列表可以省略不写,因为 Java 编译器可以通过上下文推断出数据类型,即“类型推断”
Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x, y);
注意:Lambda 表达式需要函数式接口的支持
函数式接口
若一个接口中只有一个抽象方法,该接口为函数式接口。可以使用 @FunctionalInterface 修饰,说明该接口必须是函数式接口
@FunctionalInterface
public interface MyFunction<T>{
T apply(T t);
}
Java8内置四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
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); |
其他接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
BiFunction<T, U, R> | T, U | R | 对类型为 T, U 参数应用操作,返回 R 类型的结果。包含方法为 R apply(T t, U u); |
UnaryOperator<T> (Function子接口) | T | T | 对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为 T apply(T t); |
BinaryOperator<T> (BiFunction 子接口) | T, T | T | 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为 T apply(T t1, T t2); |
BiConsumer<T, U> | T, U | void | 对类型为T, U 参数应用操作。包含方法为 void accept(T t, U u) |
ToIntFunction<T> ToLongFunction<T> ToDoubleFunction<T> | T | int long double | 分别计算int、long、double、值的函数 |
IntFunction<R> LongFunction<R> DoubleFunction<R> | int long double | R | 参数分别为int、long、double 类型的函数 |
二、方法引用、构造器引用、数组引用
方法引用
若 Lambda 体中需要完成的功能,已经有现成的方法,提供了实现,可以选择使用方法引用替代Lambda表达式。(方法引用是 Lambda 表达式的另外一种表现形式)
格式:
对象::实例方法名
Consumer<String> con = (x) -> System.out.println(x);
Consumer<String> con2 = System.out::println;
注意:接口中抽象方法的参数列表必须与Lambda体中调用方法的参数列表保持一致!
类::静态方法名
Compartor<Integer> com = Integer::compare;
类::实例方法名
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
BiPredicate<String, String> bp2 = String::equals;
注意:若Lambda参数列表中第一个参数,是 Lambda体中方法的调用者,第二个参数是Lambda体中方法的参数
构造器引用
格式: ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。
可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一致!
数组引用
格式: type[ ] :: new
三、Stream API
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*)。
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
Stream 操作的三个步骤:
-
创建 Stream
//1. 创建 Stream 的四种方式
@Test
public void test1(){
//1. 通过 Collection 系列集合提供两个 stream() 和 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2. 通过 Arrays 中的 stream() 获取一个数组流
Integer[] nums = new Integer[10];
Stream<Integer> stream2 = Arrays.stream(nums);
//3. 通过 Stream 类中静态方法 of
Stream stream3 = Stream.of("aaa", "bb", "cc");
//4. 创建无限流
//迭代
/*Stream stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.forEach(System.out::println);*/
//生成
Stream stream5 = Stream.generate(Math::random).limit(2);
stream5.forEach(System.out::println);
}
-
中间操作
中间操作流不会进行任何操作,只有做了终止操作后,流一次性的执行全部,“惰性求值”
筛选与切片 filter——接收 Lambda , 从流中排除某些元素。 limit——截断流,使其元素不超过给定数量。 skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
映射 map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
-
终止操作