Lambda的简介
Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。下面这个例子就是使用Lambda表达式代替匿名内部类,代码简单且可读
沒有使用Lambda表达式的匿名内部类:
@Test
public void test1() {
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
TreeSet<Integer> ts = new TreeSet<>(com);
}
使用Lambda表达式后:
//Lambda表达式
@Test
public void test2() {
Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
}
是不是感觉写起来简单了许多,下来我们就学习一下这种新的语法格式,首先我们要先知道什么是函数式接口
函数式接口(Functional Interfaces):如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口。同时,引入了一个新的注解:@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口。这个注解是非必须的,只要接口只包含一个方法的接口,虚拟机会自动判断,不过最好在接口上使用注解 @FunctionalInterface 进行声明。在接口中添加了 @FunctionalInterface 的接口,只允许有一个抽象方法,否则编译器也会报错。
例:
@FunctionalInterface
public interface MyFunction2<R, T> {
public R getValue(T t1, T t2);
}
Lambda表达式:可以让你的代码更加的简洁。Lambda无法单独出现,需要一个函数式接口来盛放,可以说lambda表达式方法体是函数式接口的实现,lambda实例化函数式接口,可以将函数作为方法参数,或者将代码作为数据对待。
Java8引入新的操作符 "->" 箭头操作符 或 Lambda操作符
左侧:Lambda表达式参数列表
右侧:Lambda表达式所需执行的功能 即Lambda体
Lambda对接口的操作实例
public class TestLambda2 {
// 无参,无返回值
// () -> System.out.println("hello lambda");
@Test
public void test1() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("hello world!");
}
};
r1.run();
System.out.println("-------------");
Runnable r2 = () -> System.out.println("hello lambda");
r2.run();
}
// 有一个参数 且无返回值
// (x) -> System.out.println(x);
@Test
public void test2() {
Consumer<String> c = (x) -> System.out.println(x);
c.accept("hello xiaohui");
}
/**
* 有两个以上的参数,有返回值
*/
public void test3() {
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
}
/**
* 有两个以上的参数,有返回值 只有一条语句 参数列表的数据类型可以省略不写 JVM有类型推断功能
*/
public void test4() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
}
// 对一个数进行运算
@Test
public void test5() {
Integer num = operation(100, (x -> x * x));
System.out.println(num);
}
private Integer operation(Integer num, MyFun mf) {
return mf.getValue(num);
}
在Java8中提供了四大核心接口
Consumer<T>:消费型接口 void accept(T t);
// Consumer<T> 消费型接口:
@Test
public void test1() {
happy(1000, (m) -> System.out.println("腿腿喜欢老虎机,每次都输" + m + "元"));
}
public void happy(double money, Consumer<Double> con) {
con.accept(money);
}
Supplier<T>:供给型接口 T get();
// Supplier<T> 供给型接口:
@Test
public void test2() {
List<Integer> numList = getNumList(10, () -> (int)(Math.random()*100));
for (Integer num : numList) {
System.out.println(num);
}
}
// 产生指定个数的整数,并放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
Function<T,R>:函数型接口 R apply(T t);
//Function<T,R> 函数型接口:
@Test
public void test3() {
String strHandler = strHandler("\t\t\t hello xiaohui ", (str) -> str.trim());
System.out.println(strHandler);
String upper = strHandler("xiaohui", (str) -> str.toUpperCase());
System.out.println(upper);
String newstr = strHandler("代虎虎是个二傻子", (str) -> str.substring(5, 8));
System.out.println(newstr);
}
//用于处理字符串
public String strHandler(String str, Function<String, String> fun) {
return fun.apply(str);
}
Predicate<T>:断言型接口 boolean test(T t);
//Predicate<T> 断言型接口:
@Test
public void test4() {
List<String> list = Arrays.asList("hello","xiaohui","java","www");
List<String> string = filterStr(list, (s) -> s.length() > 3);
for (String str : string) {
System.out.println(str);
}
}
//将满足条件的字符串添加到集合中
public List<String> filterStr(List<String> list,Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String str : list) {
if(pre.test(str)) {
strList.add(str);
}
}
return strList;
}
Lambda对方法的引用
一:方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用"方法引用"
(可以理解为方法引用是Lambda 表达式的另外一种表现形式)
主要有三种语法格式:
对象::实例方法名
类::静态方法名
类::实例方法名
// 类::静态方法名
@Test
public void test4() {
BiPredicate<String, String> bp = (x,y) -> x.equals(y);
BiPredicate<String, String> bp1 = String::equals;
}
// 类::静态方法名
@Test
public void test3() {
Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
Comparator<Integer> com1 = Integer::compare;
int compare = com1.compare(100, 200);
System.out.println(compare);//-1
}
// 对象::实例方法名
@Test
public void test1() {
PrintStream ps1 = System.out;
Consumer<String> con1 = (x) -> ps1.println(x);
PrintStream ps2 = System.out;
Consumer<String> con2 = ps2::println;
Consumer<String> con3 = System.out::println;
con3.accept("asdfg");
}
注意:
①Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!
②若Lambda参数列表中的第一个参数是 实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method
Lambda对构造器引用
格式:
ClassName::new
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致!
//构造器引用
@Test
public void test5() {
Supplier<Emploee> sup = () -> new Emploee();
//构造器引用方式 无参
Supplier<Emploee> sup2 = Emploee::new;
Emploee emploee = sup2.get();
System.out.println(emploee);
}
Lambda数组引用
//数组引用
@Test
public void test7() {
Function<Integer, String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(10);
System.out.println(strs.length);
Function<Integer, String[]> fun2 = String[]::new;
String[] strs2 = fun2.apply(20);
System.out.println(strs2.length);
}