Lambda表达式能够取代大部分匿名内部类,能够优化代码结构。java
能够取代匿名内部类?什么意思呢?数组
在之前若是咱们须要对集合排序,咱们是这样作:app
Integer[] arr= {3,2,1}; Arrays.sort(arr, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1-o2; } }); System.out.println(Arrays.toString(arr));
使用Arrays类提供的sort方法传入一个指定排序规则的Comparator,若是咱们使用匿名内部类的话,能够看到整个内部类中只用return o1-o2;语句是有用的,其余的都是多余的,为了这一句话咱们多写了不少代码。那么,有了Lambda表达式后咱们就能够很轻松的解决这个问题了。ide
java8中新增了Lambda表达式,如今咱们能够这样作:函数
Integer[] arr= {3,2,1}; Arrays.sort(arr, (x,y)->x-y); System.out.println(Arrays.toString(arr));
那么Lambda是如何实现的呢?咱们知道sort方法须要传入一个Comparator,而Comparator是一个接口,那么咱们来看看Comparator接口是怎样定义的:优化
@FunctionalInterface public interface Comparator<T> {
Comparator可以支持Lambda表达式的秘密就是类上标注的@FunctionalInterface注解,被这个注解标注的接口只能有一个抽象方法,咱们知道咱们写Lambda表达式时并无指定方法,那么当使用Lambda表达式时咱们从新的就是这个方法。this
语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符code
接口无参无返回对象
@FunctionalInterface interface NoParamNoReturn { void lambda(); } @Test public void test() { NoParamNoReturn noParamNoReturn=()->{System.out.println("No param No return");}; noParamNoReturn.lambda(); } //若是方法内只有一个语句那么{}能够省略 @Test public void test() { NoParamNoReturn noParamNoReturn=()->System.out.println("No param No return"); noParamNoReturn.lambda(); }
接口有一个或多个参数无返回排序
@FunctionalInterface interface OneParamNoReturn{ void lambda(int x); } @Test public void test() { OneParamNoReturn oneParamNoReturn=(int x)->System.out.println(x); oneParamNoReturn.lambda(10); } //若是方法只有一个参数那么()能够省略 //方法参数的类型也能够省略,编译器会根据方法参数类型推断 @Test public void test() { OneParamNoReturn oneParamNoReturn=x->System.out.println(x); oneParamNoReturn.lambda(10); }
接口无参数有返回值
@FunctionalInterface interface NoParamHasReturn{ int lambda(); } @Test public void test() { NoParamHasReturn noParamHasReturn=()->{return 10;}; noParamHasReturn.lambda(); } //当方法只有return语句时,能够省略{}和return @Test public void test() { NoParamHasReturn noParamHasReturn=()->10; noParamHasReturn.lambda(); }
接口有一个或多个参数有返回值
@FunctionalInterface interface HasParamHasReturn{ int lambda(int x,int y); } @Test public void test() { HasParamHasReturn hasParamHasReturn=(x,y)->x+y; hasParamHasReturn.lambda(10, 20); }
咱们可使用lambda表达式把接口快速指向一个已经实现了的方法
语法:方法归属者::方法名 静态方法的归属者为类名,普通方法归属者为对象
@FunctionalInterface interface HasParamHasReturn{ int lambda(int x,int y); } public class LambdaTest{ public int add(int x,int y) { return x+y; } //lambda表达式指向对象方法 @Test public void test() { LambdaTest lt=new LambdaTest(); HasParamHasReturn hasParamHasReturn=lt::add; hasParamHasReturn.lambda(10, 20); } public static int sub(int x,int y) { return x-y; } //lambda表达式引用静态方法 @Test public void test12() { HasParamHasReturn hasParamHasReturn=LambdaTest::sub; hasParamHasReturn.lambda(10, 20); } } //类名::实例方法 特殊状况,只有当参数列表为一个参数而且这个参数是方法调用者或多个参数而且第一个参数是调用者其余参数是参数列表 @Test public void test() { BiPredicate<String,String> bp=(x,y)->x.equals(y); //也能够简写为 BiPredicate<String,String> bp2=String::equals; }
lambda表达式引用构造函数建立对象
语法:类名::new;
class User{ String name; int age; public User() {} public User(String name, int age) { super(); this.name = name; this.age = age; } } @FunctionalInterface interface UserCreatorBlankConstruct{ User getUser(); } //使用lambda表达式引用构造器 @Test public void test() { UserCreatorBlankConstruct creator1=User::new; creator1.getUser(); } @FunctionalInterface interface UserCreatorParamConstruct{ User getUser(String name,int age); } @Test public void test13() { UserCreatorParamConstruct creator2=User::new; creator2.getUser("tom", 20); }
@FunctionalInterface public interface Consumer<T> { void accept(T t); }
供给型接口
@FunctionalInterface public interface Supplier<T> { T get(); }
函数型接口
@FunctionalInterface public interface Function<T, R> { R apply(T t); }
断言型接口
@FunctionalInterface public interface Predicate<T> { boolean test(T t); }
怎么用呢?
遍历数组
@Test public void test() { List<Integer> list=new ArrayList<>(); list.add(1); list.add(3); list.add(5); list.add(7); list.forEach(System.out::println); }
建立对象
@Test public void test() { Supplier<User> supplier=User::new; User user = supplier.get(); }
去除先后空格并转为大写
@Test public void test16() { Function<String, String> fun=s->{s=s.trim();s=s.toUpperCase();return s;}; String apply = fun.apply(" abCd"); }
删除集合元素
@Test public void test() { List<User> list=new ArrayList<>(); list.add(new User("tom",20)); list.add(new User("jack",18)); list.add(new User("marry",22)); list.removeIf(e->e.getName()=="jack"); }
那若是咱们要用内置函数式接口建立对象,怎么作呢?
@Test public void test() { Supplier<User> supplier=User::new; User user = supplier.get(); System.out.println(user);//User [name=null, age=0] }
那到底使用的是哪一个构造器呢?经过输出建立的对象能够发现调用的是无参构造器,即调用构造器参数个数对应Supplier中get方法的参数个数的构造器
那么问题又来了,若是咱们要使用两个参数的构造器,那Supplier也不行啊,Function的apply方法也只有一个参数,怎么办?那咱们去java.util.function包下找找有没有能够用的接口
@FunctionalInterface public interface BiFunction<T, U, R> { R apply(T t, U u); } //使用内置函数式接口建立对象 @Test public void test20() { BiFunction<String,Integer,User> biFunction=User::new; User user = biFunction.apply("tom", 20); System.out.println(user);//User [name=tom, age=20] }
四个基本接口参数个数不够用也能够相似的去java.util.function包下找找有没有申明好的函数式接口
最后一个问题,我发现
list.forEach(System.out::println);
遍历List时,使用的forEach的参数Consumer的accept方法是这么写的,我第一个想到的是,out是System的一个内部类,可是当我点进去,发现是这样的
public final static PrintStream out = null;
out是一个静态的成员变量,那个人理解就是System.out实际上是一个对象
这样System.out::println的写法其实也就是 对象名::方法名
我是这样理解的,若是错了还请赐教!