在今年的九月份Java9刚刚发布,而Java8的几大新特性还不了解。
Java8新特性的特点:
- 速度更快
- 代码更少(增加了新语法 Lambda表达式)
- 强大的Stream API
- 便于并行
- 最大减少空指针异常 optional
Lambda 表达式与 Stream API 最为核心。
Lambda 是一个匿名函数,我们可以把Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。
一、 lambda 表达式的基础语法: Java8中引入了新的操作符 “->”
箭头操作符”->” 将lambda 表达式拆分成两部分:
左侧: lambda 表达式的参数列表
右侧: lambda 表达式中所需执行的功能–lambda体
二、 lambda 表达式需要“函数式接口”的支持
函数式接口: 接口中只有一个抽象方法的接口,称为函数式接口,可以使用注解
@FunctionInterface 修饰,可以检查是否是函数式接口。
/*
* 语法格式一: 无参数、无返回值
* () -> System.out.println("Hello Lambda!");
* 注: jdk1.7 以前 局部内部类 变量必须声明 final, jdk1.8以后可以不用声明,但依然是final类型的。
*/
@Test
public void test1(){
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello world!");
}
};
runnable.run();
System.out.println("-------------------------------");
Runnable runnable2 = () -> System.out.println("Hello Lambda!");
runnable2.run();
}
/*
* 语法格式二: 有一个参数,无返回值
* (e) -> System.out.println(e);
* 若有一个参数的话,小括号可以不写
* e -> System.out.println(e);
*/
@Test
public void test2(){
Consumer<String> consumer = (e) -> System.out.println(e);
consumer.accept("我就是参数!");
}
/*
* 语法格式三: 有两个以上的参数,有返回值,并且lambda体中有多条语句 要加上 大括号和分号
* Comparator<Integer> comparable = (x, y) -> {
System.out.println("123");
return Integer.compare(x, y);
};
若只有一个返回值语句,可以直接省略大括号:(x, y) -> Integer.compare(x, y);
lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
*/
@Test
public void test3(){
Comparator<Integer> comparable = (x, y) -> {
System.out.println("123");
return Integer.compare(x, y);
};
}
//需求: 对一个数进行操作
@Test
public void test4(){
Integer num = operation(100, e -> e*e);
System.out.println(num);
System.out.println(operation(200, (e) -> e+300));
}
public Integer operation(Integer num, Myfun myfun){
return myfun.getValue(num);
}
三、Java8 内置四大核心函数式接口
Consumer< T > : 消费型接口 void accept(T t);
Supplier< T >: 供给型接口 T get();
Function< T, R >: 函数型接口 R apply(T t);
Predicate< T > : 断言型接口 boolean test(T t);
//断言型接口: Predicate<T> boolean test(T t);
@Test
public void test4(){
List<String> list = Arrays.asList("Hello, World", "你好,世界", "Lambda", "ok");
List<String> strs = filterStr(list, (e) -> e.length()>5);
System.out.println(strs);
}
//将满足条件的字符串加入集合中
public List<String> filterStr(List<String> str, Predicate<String> pre){
List<String> list = new ArrayList<>();
for (String string : str) {
if (pre.test(string)) {
list.add(string);
}
}
return list;
}
// 函数式接口 Function<T,R> R apply(T t);
@Test
public void test3(){
String string = strHandler("好好学习, 天天向上", (e) -> e.substring(2,5));
System.out.println(string);
}
//用于处理字符串
public String strHandler(String str, Function<String, String> fun){
return fun.apply(str);
}
// 消费型接口: Consumer<T> void accept(T t);
@Test
public void test1(){
happy(10000, (e) -> System.out.println("买衣服花了 "+ e + "元"));
}
public void happy(double money, Consumer<Double> consumer){
consumer.accept(money);
}
//供给型接口: Supplier<T> T get();
@Test
public void test2(){
List<Integer> list = getNumberList(10, () -> (int)(Math.random() * 100));
for (Integer integer : list) {
System.out.println(integer);
}
}
//生成指定数量的整数,放入集合中
public List<Integer> getNumberList(int num, Supplier<Integer> supplier){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
list.add(supplier.get());
}
return list;
}
四、方法引用
方法的引用: 若Lambda 体中 的功能,已经有方法提供了实现,可以使用方法引用
(可以将方法引用理解为lambda表达式的另外以一种形式)
1、对象的引用 ::实例方法名
2、类名 ::静态方法名
3、类名 ::实例方法名
注意: ①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的 参数列表和返回值类型 保持一致。
②若lambda的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,
格式为 ClassName ::MethodName
//对象的引用 ::实例方法名
@Test
public void test2(){
Employee emp = new Employee("lbh", 23, 5500);
Supplier<Integer> sup = () -> emp.getAge();
System.out.println(sup.get());
Supplier<Integer> sup2 = emp::getAge;
System.out.println(sup2.get());
}
@Test
public void test1(){
Consumer<String> consumer = (str) -> System.out.println(str);
consumer.accept("Hello");
Consumer<String> consumer2 = System.out::println;
consumer2.accept("World");
}
//类名 ::静态方法名
@Test
public void test3(){
Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);
Comparator<Integer> comparator2 = Integer::compare;
}
//类名 ::实例方法名
@Test
public void test4(){
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
BiPredicate<String, String> bp2 = String::equals;
}
五、构造器引用
格式: ClassName::new;
注意: 需要调用的构造器的参数列表要与函数式接口中的抽象方法的参数列表保持一致!
//构造器引用
@Test
public void test5(){
Supplier<Employee> emp = () -> new Employee();
Supplier<Employee> emp2 = Employee::new;
System.out.println(emp2.get());
}
@Test
public void test6(){
Function<Integer, Employee> fun = (e) -> new Employee(e);
Function<Integer, Employee> fun2 = Employee::new;
System.out.println(fun2.apply(23));
}
六、数组引用
格式: type[]::new;
//数组引用
@Test
public void test7(){
Function<Integer, String[]> fun = (e) -> new String[e];
String[] str = fun.apply(10);
System.out.println(str.length);
Function<Integer, String[]> fun2 = String[]::new;
String[] str2 = fun2.apply(20);
System.out.println(str2.length);
}