Java8有哪些新特性
- Lambda 表达式
- 函数式接口
- 方法引用、构造器引用
- Stream API
- 接口中的默认方法、静态方法
- 新时间日期API
- 可重复注解、类型注解
Lambda表达式
什么是Lambda表达式
Lambda是一个匿名函数,可以理解为是对某个接口方法的实现的一段代码,省略了以前要实现接口的复杂过程,代码更加简洁、灵活。
为什么要使用它
在使用Comparator接口时,我们需要使用匿名内部类实现其方法。实际上最关键也就是Integer.compare(o1,o2)这一行代码,其他的作用不大。
/**
*
* 匿名内部类
*/
@Test
public void test01(){
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
@Override
public boolean equals(Object obj) {
return false;
}
};
int compare = comparator.compare(1, 2);
System.out.println(compare);
}
使用Lambda表达式后,代码瞬间变得简洁了许多!
/**
*
* Lambda 表达式
*/
@Test
public void test02(){
Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b);
int compare = comparator.compare(1, 2);
System.out.println(compare);
}
怎么用
Java8中引入了一个新的操作符"->",该操作符称为箭头操作符或者Lambda操作符。箭头操作符将Lambda表达式拆分陈2部分:
- 左侧:Lambda表达式的参数列表
- 右侧:Lambda表达式中所需执行的功能,即Lambda体
口诀
- 写死小括号,拷贝右箭头,落地大括号
- 左右遇一括号省
- 左侧推断类型省
语法格式1
无参数、无返回值
@Test
public void test1(){
Runnable runnable = ()-> System.out.println("hello");
runnable.run();
}
语法格式2
有1个参数、无返回值
@Test
public void test2(){
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("xxx1");
}
语法格式3
如果只有1个参数,小括号可以省略
@Test
public void test3(){
Consumer<String> consumer = x -> System.out.println(x);
consumer.accept("xxx2");
语法格式4
有2个以上的参数,并且Lambda体中有多条语句,必须使用大括号
@Test
public void test4(){
Comparator<Integer> comparator = (x,y) -> {
System.out.println("hello");
return Integer.compare(x,y);
};
int compare = comparator.compare(1, 1);
System.out.println(compare);
}
语法格式5
若Lambda体中只有1条语句,那么return和大括号都可以省略不写
@Test
public void test5(){
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
int compare = comparator.compare(1, 1);
System.out.println(compare);
}
语法格式6
Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”
@Test
public void test6(){
Comparator<Integer> comparator = (Integer x,Integer y) -> Integer.compare(x,y);
System.out.println(comparator.compare(1, 1));
Comparator<Integer> comparator2 = (x,y) -> Integer.compare(x,y);
System.out.println(comparator2.compare(1, 1));
}
函数式接口
Java8内置的四大核心函数式接口
- 消费型接口Consumer<T> => void accept(T t);
- 供给型接口Supplier<T> => T get();
- 函数型接口Function<T,R> => R apply(T t);
- 断言型接口 Predicate<T> => boolean test(T t);
消费型接口
//Consumer<T>
@Test
public void test1(){
shopping(100,(x) -> System.out.println("消费:" + x));
}
public void shopping(double pay, Consumer<Double> consumer){
consumer.accept(pay);
}
供给型接口
//Supplier<T>
@Test
public void test2(){
List<Integer> integers = numList(10, () -> (int) (Math.random() * 100));
for (Integer integer : integers) {
System.out.println(integer);
}
}
public List<Integer> numList(int num, Supplier<Integer> supplier){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer a = supplier.get();
list.add(a);
}
return list;
}
函数型接口
//Function<T,R>
@Test
public void test3(){
Integer a = doStr("aaaaas", (x) -> x.length());
System.out.println("長度:" + a);
}
public Integer doStr(String str, Function<String,Integer> function){
return function.apply(str);
}
断言型接口
//Predicate<T>
@Test
public void test4(){
List<String> list = Arrays.asList("www", "baidu", "123hhh", "zhangsna");
List<String> strs = filterStr(list, (x) -> x.length() > 3);
for (String str : strs) {
System.out.println(str);
}
}
public List<String> filterStr(List<String> strs, Predicate<String> predicate){
List<String> list = new ArrayList<>();
for (String string : strs){
if(predicate.test(string)){
list.add(string);
}
}
return list;
}
其他接口
引用
方法引用
若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”。可以理解为方法引用是Lambda,表达式的另外一种表现形式。
语法格式1
对象::实例方法名
注意:Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型保持一致。
//对象::实例方法名
@Test
public void test1(){
PrintStream ps = System.out;
Consumer<String> c1 = (x) -> ps.println(x);
c1.accept("hello");
PrintStream ps2 = System.out;
Consumer<String> c2 = ps2::println;
c2.accept("hello2");
}
//对象::实例方法名
@Test
public void test2(){
User u= new User();
Supplier<String> supplier = () -> u.getName();
String s = supplier.get();
System.out.println(s);
Supplier<String> supplier2 = u::getName;
String s1 = supplier2.get();
System.out.println(s1);
}
语法格式2
类::静态方法名
//类::静态方法名
@Test
public void test3(){
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
int compare = comparator.compare(1, 2);
System.out.println(compare);
Comparator<Integer> comparator2 = Integer::compare;
int compare2 = comparator2.compare(1, 2);
System.out.println(compare2);
}
语法格式3
类::实例方法名
注意若Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::menthod
// 类::实例方法名
@Test
public void test4(){
BiPredicate<String,String> biPredicate = (x,y) -> x.equals(y);
System.out.println(biPredicate.test("a","b"));;
BiPredicate<String,String> biPredicate1 = String::equals;
System.out.println(biPredicate1.test("a","b"));;
}
构造器引用
语法格式:ClassName::new
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致。