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