java提供了一些新的特性,首当其中的就是Lambda表达式。接下来看一下Lambda表达式的最基础语法。
Lambda表达式使用 -> 箭头操作符。将表达式分为两个部分。
左侧 : Lambda表达式的参数列表
右侧: Lambda表达式中所需要在执行的功能,即Lambda体。
下面来简单的看一下Lambda简单的用法。
语法一 : 无参数,无返回值。
@Test
public void Test1(){
Runnable runnable = () -> System.out.println("hello Lambda!");
runnable.run();
}
语法二 : 有一个参数并且没有返回值
@Test
public void Test2(){
Consumer<String> con = (x) -> System.out.println(x);
con.accept("hello Lambda!");
}
语法三 :若只有一个参数,小括号可以省略
@Test
public void Test2(){
Consumer<String> con = x -> System.out.println(x);
con.accept("hello Lambda!");
}
语法四 : 有两个以上的参数,有返回值,并且Lambda体中有多条语句
@Test
public void Test3(){
Comparator<Integer> comparable = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
}
语法五 :若Lambda体中只有一条语句 return和大括号可以省略不写
@Test
public void Test3(){
Comparator<Integer> comparable = (x, y) -> Integer.compare(x,y);
}
语法六 :Lambda表达式的参数列表的数据类型可以省略不写,因为jvm会编译器会通过上下文推断出参数类型
上面所有的例子 都没有指定参数的类型。
Lambda必须配合函数式接口一起使用。
什么是函数式接口呢?
接口中只有一个抽象方法的接口,成为函数式接口。
java8中内置有四大内置的核心函数式接口。
1 Consumer<T> : 消费型接口
void accept(T t);
@Test
public void Test4(){
happy(1000d, (m) -> System.out.println("消费了"+ m));
}
public void happy(double money, Consumer<Double> con){
con.accept(money);
}
2 Supplier<T> : 供给型接口
T get();
//需求: 产生指定个数的整数 放入集合中
public List<Integer> getNumberList(int nums, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < nums; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
@Test
public void Test5(){
List<Integer> numberList = getNumberList(10, () -> (int) Math.random() * 100);
numberList.forEach(System.out::println);
}
3 Function(T, R) : 函数型接口
R apply(T t);
@Test
public void Test6(){
String newStr = strHandler("Hello Lambda", (str) -> str.substring(0, 6));
System.out.println(newStr);
}
//需求: 用处处理字符串
public String strHandler(String str, Function<String , String> fun){
return fun.apply(str);
}
4 Predicate<T> : 断言型接口
boolean test(T t);
@Test
public void test6(){
List<String> list = Arrays.asList("Hello","JIY","Lambda","haah");
List<String> strings = filterStr(list, (str) -> str.length() > 3);
strings.forEach(System.out::println);
}
//需求: 将满足条件的字符串添加到集合中
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> stringList = new ArrayList<>();
list.forEach((str) -> {
if(pre.test(str)){
stringList.add(str);
}
});
return stringList;
}
方法引用
若Lambda体中的内容已经实现了,我们可以用“方法引用”,可以理解为方法引用时Lambda表达式的另外一种表现形式
主要有三种引用格式:
对象::实例方法名
public void test1(){
PrintStream ps = System.out;
//传统方式
Consumer<String> con = (x) -> ps.println(x);
Consumer<String> con1 = ps::println;
}
@Data
@AllArgsConstructor
@ToString
@NoArgsConstructor
public class Employee {
private String name;
private int age;
}
public void test2(){
Employee emp = new Employee();
//传统Lambda方式
Supplier<String> sup = () -> emp.getName();
System.out.println(sup.get());
//方法引用方式
Supplier<Integer> sup1 = emp::getAge;
System.out.println(sup1.get());
}
注意 : 需要实现的接口中的抽象方法的参数列表与返回值类型要与当前调用这个方法的参数列表和返回值类型保持一致
类::静态方法名
//类::静态方法
public void test3(){
Comparator<Integer> com = (x, y) -> Integer.compare(x,y);
//方法引用
Comparator<Integer> com1 = Integer::compare;
}
注意: Lambda体中的调用方法的参数列表和返回值类型要与函数式接口中的抽象方法的参数列表和返回值类型保持一致
类::实例方法名
//类::实例方法
public void test4(){
BiPredicate<String, String> bp = (x ,y) -> x.equals(y);
//方法引用
BiPredicate<String, String> bp1 = String::equals;
}
注意:如果说Lambda参数列表有两个参数,第一个参数(x)是实例方法的调用者,而第二个参数(y)是实例方法调用的参数。
构造器引用
格式 : ClassName ::new
//构造器引用
public void test5(){
Supplier<Employee> sup = () -> new Employee();
//构造器引用
Supplier<Employee> sup2 = Employee::new;
}
注意: 构造器的参数列表和接口中参数列表一致。(Suppier接口方法是无参数的,所以调用的也是Employee的无参构造方法)
数组引用
格式 : Type::new
//数组引用
public void test6(){
Function<Integer, String[]> fun = (x) -> new String[x];
String[] strings1 = fun.apply(10);
//方法引用
Function<Integer, String[]> fun2 = String[]::new;
String[] strings2 = fun2.apply(5);
System.out.println(strings1.length);
System.out.println(strings2.length);
}