前言
Java8早在2014年便发布了,它具有很多新的特性以及优化。主要如下:
- 速度更快:对底层的数据结构,垃圾回收机制做了优化。
对HashMap进行优化:使用数组-链表-红黑树的数据结构。
2.代码更少:增加新的语法Lambda表达式。
3.强大的Stream API
Java 8 API添加了一个新的抽象称为流Stream,可以以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。这种风格将要处理的元素集合看作一种流(不同于字符流、字节流), 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等(工厂里流水线的感觉)。
4. 支持并行操作、便于并行处理
5. 最大化减少空指针异常。
Lambda表达式
匿名内部类具有诸多缺点:语法过于冗余、可读性差、使用不够灵活、无法使用非final的局部变量等,因此在Java8中提供了一种更简洁、更灵活的语法,Lambda表达式。
基础语法
基本语法:(parameters) -> expression 或 (parameters) ->{ statements; }
Lambda的操作符为“->”,此操作符将Lamdba表达式拆分成两部分。
左侧,对应方法的参数列表。
右侧,Lambda表达式中所需执行的功能。
通过Lambda表达式即可生成我们需要的目标实现类。
1. 无参数,无返回值
@FunctionalInterface
interface Consumer{
abstract void consume();
}
@Test
public void testLambda(){
// 无参数、无返回值
fun(() -> System.out.println("消费..."));
}
private void fun(Consumer m){
m.consume();
}
2.有参数,无返回值
@FunctionalInterface
interface Consumer{
abstract void consume(float money);
}
@Test
public void testLambda(){
float meoney = 123;
// 有参数、无返回值
fun(meoney, (x) -> System.out.println("消费..." + x +"元"));
// 仅一个参数时,左侧小括号可以省略
fun(meoney, x -> System.out.println("消费..." + x +"元"));
}
private void fun(Float m, Consumer mi){
mi.consume(m);
}
3. 有参数、有返回值
@FunctionalInterface
interface MyOperation{
abstract float operation(float a, float b);
}
@Test
public void testLambda(){
float a = 123;
float b = 234;
// 有参数、有返回值、多条语句使用{ }
float ret1 = fun(a, b, (float x, float y) -> {
System.out.println("求和计算");
return x + y;
});
System.out.println(ret1);
// 参数类型可省略,仅一条返回值语句,return可省略
float ret2 = fun(a, b, ( x, y) -> x + y);
System.out.println(ret2);
}
private float fun(float a, float b, MyOperation m){
return m.operation(a, b);
}
在哪里可以使用Lambda?
通过上面的实例可以看出,在使用Lambda的参数位置原本是需要传递一个类,例如在实例1中需要传递实现Consumer的类,但是我们仅传递了参数列表以及实现的功能。使用Lambda表达式实现的接口都有一个共同的特点,他们都是函数式接口。
函数式接口
函数式接口本质还是接口,只不过是一种特殊的接口,在这个接口中仅有一个抽象方法。可使用@FunctionalInterface注解进行修饰。在Java8之前便有函数式接口,例如:
1. java.lang.Runnable
2. java.io.FileFilter
3. java.util.Comparator
...
此外,在Java8中增加了一些新的函数式接口,在java.util.function包下,大致可以将java.util.function包下的函数式接口分为四类:
1. Supplier 供给型,无参数有返回值
public interface Supplier<T> {
T get();
}
Supplier<Date> dateSupplier = new Date();
System.out.println(dateSupplier.get());
2. Consumer 消费型,有参数无返回值
public interface Consumer<T> {
void accept(T t);
}
Consumer shopping = (x) -> System.out.println("消费了:" + x);
shopping.accept(100);
3. Function 转换型,有参数有返回值
public interface Function<T, R> {
R apply(T t);
}
Function<String, Integer> fun = (x) -> Integer.parseInt(x);
System.out.println(fun.apply("100"));
4. Predicate 断言型,有参数返回布尔值
public interface Predicate<T> {
boolean test(T t);
}
Predicate<Integer> predicate = (num) -> num > 100;
System.out.println(predicate.test(100));
方法引用
lambda表达式允许我们使用参数列表和具体功能来生成实现类,如果我们想实现的功能已经存在,那么我们可以使用方法引用来简化我们的代码。方法引用操作符为“::”,主要分为以下三种:
1. 引用静态方法
Function<String, Integer> shopping = Integer::parseInt;
System.out.println(shopping.apply("100"));
// 构造方法引用
Supplier<Date> dateSupplier = Date::new;
System.out.println(dateSupplier.get());
需要注意的是,函数式接口的抽象方法的入参类型和返回值类型需要和被引用方法的类型保持一致。例如上面实例中Function接受一个String参数,返回一个Integer值,这和Integer的parseInt参数和返回值是一致的。
2. 引用类型实例方法
3. 引用现有对象的实例方法
// 不使用方法引用
Function<String, Integer> fun = (String s) -> s.length();
System.out.println(fun.apply("zhuxiaoyuan"));
// 使用方法引用
Function<String, Integer> fun = String::length;
System.out.println(fun.apply("zhuxiaoyuan"));
剩下的两种类型,主要是引用对象的方法,(String s) -> s.length()可写为String::length。