JAVA8新特性
- 速度更快
- 代码更少——Lambda
- 强大的Stream API
- 便于并行
- 最大化减少空指针异常——optional
零、速度更快
速度更快指的是hashMap的结构增加了红黑树。
在之前的hashmap结构中,jdk采用的是数组+链表的方式进行。当发生碰撞时,会极大地降低查找的效率。所以在jdk1.8中,采用了数组+链表+红黑树的方式,前提是当发生碰撞的个数大于8时且总容量大于64时,才会将链表结构转换为红黑树,此时会造成添加元素的效率降低,但是查找和删除等的效率会大大提高:
一、Lambda表达式
在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情” 。相对而言,面向对过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。
- 面向对象的思想:做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情。
- 函数式编程思想:只要能获取到结果,谁去做的,怎么做的都不重要,重要的是结果,不重视过程。
Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
//原来的匿名内部类
@Test
public void test1(){
// 匿名内部类,即只存在实现的没有实例对象的类
Comparator<String> com = new Comparator<String>(){
@Override
public int compare(String o1, String o2) {
// 此句为核心的代码
return Integer.compare(o1.length(), o2.length());
}
};
TreeSet<String> ts = new TreeSet<>(com);
}
//现在的 Lambda 表达式
@Test
public void test2(){
// 简化代码的书写,将核心代码抽取出来
// Lambda表达式作为参数传递
Comparator<String> com = (x, y) -> Integer.compare(x.length(), y.length());
TreeSet<String> ts = new TreeSet<>(com);
}
1.1 语法
Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “ ->” , 该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:
- 左侧: 指定了 Lambda 表达式需要的所有参数
- 右侧: 指定了 Lambda 体,即 Lambda 表达式要执行的功能
1.1.1 无参数,无返回值
1.1.2 一个参数,无返回值
1.1.3 若只有一个参数,小括号可以省略不写
1.1.4 两个以上的参数,有返回值
1.1.5 若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
1.1.6 参数列表的数据类型可以省略不写
上述 Lambda 表达式中的参数类型都是由编译器推断得出的。 Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac编译器 根据程序的上下文,在后台推断出了参数的类型。 Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断” 。
1.2 优缺点
1.1.1 优点
-
简洁。
-
非常容易并行计算。
-
可能代表未来的编程趋势。
-
结合 hashmap 的 computeIfAbsent 方法,递归运算非常快。java有针对递归的专门优化。
1.1.2 缺点
由于省略了太多东西,代码可读性有可能在一定程度上会降低。
1.3 实现
拷贝小括号,写死右箭头,落地大括号
package com.zdp.java8;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
/**
* 一、Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符
* 箭头操作符将 Lambda 表达式拆分成两部分:
* <p>
* 左侧:Lambda 表达式的参数列表
* 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
* <p>
* 语法格式一:无参数,无返回值
* () -> System.out.println("Hello Lambda!");
* <p>
* 语法格式二:有一个参数,并且无返回值
* (x) -> System.out.println(x)
* <p>
* 语法格式三:若只有一个参数,小括号可以省略不写
* x -> System.out.println(x)
* <p>
* 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
* Comparator<Integer> com = (x, y) -> {
* System.out.println("函数式接口");
* return Integer.compare(x, y);
* };
* <p>
* 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
* Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
* <p>
* 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
* (Integer x, Integer y) -> Integer.compare(x, y);
* <p>
* 上联:左右遇一括号省
* 下联:左侧推断类型省
* 横批:能省则省
* <p>
* 二、Lambda 表达式需要“函数式接口”的支持
* 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰
* 注解 @FunctionalInterface可以检查是否是函数式接口
*/
public class LambdaStudy01 {
// Lambda体的作用是实现接口
// 前提是该接口中只含有一个抽象方法(函数式接口)
@Test
public void test1() {
// 同级别局部内部类
int num = 0;//jdk 1.7 前,必须是 final
// Runnable是一个无参无返回值的接口
Runnable r = new Runnable() {
@Override
public void run() {
// 匿名内部类引用同级别局部内部类
System.out.println("Hello World!" + num);
}
};
r.run();
System.out.println("-------------------------------");
// 语法格式一:无参数,无返回值
Runnable r1 = () -> System.out.println("Hello Lambda!");
r1.run();
}
// 语法格式二:有一个参数,并且无返回值
@Test
public void test2() {
/**
* Consumer是JAVA8中提供的一个函数式接口
* Performs this operation on the given argument.
*
* @param t the input argument
*
* 内部含有一个有参方法
* void accept(T t);
*/
// Lambda表达式 即去实现这个接口中的唯一一个方法
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("zdp牛逼!!!");
}
// 语法格式三:若只有一个参数,小括号可以省略不写
@Test
public void test3() {
Consumer<String> consumer = x -> System.out.println(x);
consumer.accept("zdp牛逼!!!");
}
// 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
@Test
public void test4() {
// 实现函数式接口
Comparator<Integer> comparator = (a, b) -> {
// 多条语句
System.out.println("函数式接口");
return Integer.compare(a, b);
};
// 执行
int compare = comparator.compare(1, 2);
System.out.println(compare);
}
// 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号 都可以省略不写
@Test
public void test5() {
// 实现函数式接口,实现时只有一条语句
// 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写
// 因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b);
// 执行
int compare = comparator.compare(1, 2);
System.out.println(compare);
}
}
二、 函数式接口
- 函数式接口有且仅有一个未被覆写的抽象方法。但是 Object 中方法不算,接口中的 default 方法和 static 方法也不算
/**
* 函数式接口
* 函数式接口有且仅有一个未被覆写的抽象方法。
* 但是Object 中方法不算,接口中的 default 方法不算
* 注解 @FunctionalInterface 修饰可以检查是否是函数式接口
*/
@FunctionalInterface
public interface FunctionalInterfaceTest {
// 只含有一个抽象方法
void test();
// 默认实现方法除外
default void defaultTest(){
System.out.println("这是函数式接口的默认实现方法");
}
// 静态方法除外
static void staticTest(){
System.out.println("这是函数式接口的静态实现方法");
}
// Object的方法
String toString();
int hashCode();
boolean equals(Object object);
}
-
使用注解 @FunctionalInterface 修饰可以检查是否是函数式接口
default方法:
java8在接口中新增default方法,是为了在现有的类库中新增功能而不影响他们的实现类。试想一下,如果不增加默认实现的话,接口的所有实现类都要实现一遍这个方法,这会出现兼容性问题,如果定义了默认实现的话,那么实现类直接调用就可以了,并不需要实现这个方法。
// 增强的接口 public interface MyInterface01 { // 使用default关键字,增加接口方法的默认实现,该默认方法也可以被实现类重写 default void testInterFace(){ System.out.println("增强接口的默认方法"); } void test(); }
注意:如果接口中的默认方法不能满足某个实现类需要,那么实现类可以覆盖默认方法。不用加default关键字,例如:
// 增强接口的实现类 public class InterfaceTest implements MyInterface01 { // // 重写接口的默认方法,也可以不重写 // @Override // public void testInterFace() { // // } @Override public void test() { System.out.println("增强接口的test"); } }
2.1 自定义函数式接口
/**
* 函数式接口
* 函数式接口有且仅有一个未被覆写的抽象方法。
* 但是Object 中方法不算,接口中的 default 方法不算
* 注解 @FunctionalInterface 修饰可以检查是否是函数式接口
*/
@FunctionalInterface
public interface FunctionalInterfaceDemo {
// 只含有一个抽象方法
Integer test(int x);
// 默认实现方法除外
default void defaultTest(){