java8之lambda表达式
lambda表达式是java8提供了一个比较重要的新特性之一,简化了很多代码的编写。
1、先看一个简单的例子,不是用lambda表达式创建一个线程:
Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("hello world"); } });
在Thread构造函数内传入一个Runnable接口的实现类。
2、再看一下使用lambda表达式创建线程的例子:
Thread thread1 = new Thread(()->{ System.out.println("hello world"); });
使用lambda表达式以后回省略很多代码,不用再去重复的写要实现的方法名称,当然并不是所有的接口都能使用lambda表达式,必须要是函数式接口才能使用lambda。
函数式接口
有且只有一个抽象方法的接口被称为函数式接口。
函数式接口可以显示的被@FunctionalInterface所修饰,当被标识的接口不满足规定时,编译器会报错。
例:
@FunctionalInterface public interface Runnable { public abstract void run(); }
lambda表达式的转换方式
//下面是三个自定义的函数式接口 interface T1{ void say(int a); } interface T2{ String say(int a); } interface T3{ int say(int a,int b,int c); } //()里面的数据表示参数,后面跟一个箭头->,最后面是大括号{} Runnable runnable = ()->{ System.out.println("hello world"); }; //当参数只有一个时,可以省去() T1 t1 = a->{ System.out.println("hi"); }; //当方法体只有一行时,可以省去{} T1 t2 = a-> System.out.println("hi"); //有返回值的方法 T2 t21 = (a)->{ return a+"hi"; }; //同样的,方法体只有一行时,可以省略{},并且省略return T2 t22 = a -> a+ "hi"; //有多个参数的方法,只需要在()内写上参数就行,并不需要写参数类型,因为lambda会自己推断参数类型, T3 t3 = (a,b,c)-> a + b + c;
使用lambda在实际项目开发者确实能省略很多的代码,比如在使用线程池处理线程,使用Comparable进行比较等等。
Java8内置的函数式接口
Java8提供了一个java.util.function包,包含了很多函数式接口,下面是最为基本也是最常用的4个,这四个函数式接口在我上一篇说stream的时候基本上都提到过,所以下面只是列出以下代码并做一个简单的说明,就不再去写例子了,有兴趣的可以自己去写一些实现类去了解一下,都是非常简单的接口,这些接口在stream里面用到的非常多。
Function接口:
@FunctionalInterface public interface Function<T, R> { R apply(T t); default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } static <T> Function<T, T> identity() { return t -> t; } }
Function接口的唯一抽象方法是apply,作用是接收一个指定类型的参数,返回一个指定类型的结果
Consumer接口
@FunctionalInterface public interface Consumer<T> { void accept(T t); default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
Consumer接口中accept方法的作用是接收指定参数类型,无返回值,重点在于内部消费
Predicate接口
@FunctionalInterface public interface Predicate<T> { boolean test(T t); default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> negate() { return (t) -> !test(t); } default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
Predicate中的test方法,传入指定类型参数,返回布尔类型的结果,用于判断,断言
Supplier接口:
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
Supplier意为供应,只有一个方法get,不接收任何参数,只返回指定类型结果。