Java8实用指北1-lambda表达式与函数式接口
直接开干前,最好知道的几点
lambda表达式与函数式编程
- 函数式编程(Functional Programming)在
JavaScript
中到处都是(各种回调匿名函数),Java8的lambda表达式语法与ES6的箭头函数尤其相像,但是不能简单地将lambda当作语法糖看待(比如干掉匿名内部类)。 - 函数式编程优点多多,简单的说就是:
将函数当成对象作为方法参数传递,开发更加灵活开放,并且语法更加简洁紧凑。 - lambda表达式是Java支持函数式编程的关键标志,是推动Java8发布的最重要的特性
lambda表达式与函数式接口
- lambda表达式本身是中性的,只有在真正的语境下才有它的实现代表类型。
- 至于lambda表达式可以是哪些类型,为此Java8没有选择新增一个单独的类或者接口,而是新增了函数式接口(Functional Interface)的概念。
- 函数式式接口就是原来的interface,只是它有一个标记和一个限制。
标记就是一个@FunctionalInterface
注解,限制就是有且仅有一个抽象方法。 - 使用lambda表达式很容易得到一个函数式接口的实现,因此绝大多数匿名内部类的场合都可以使用lambda表达式取代,这也是我们最常使用它的场景。
- Java8对原先的一些接口进行了函数式化,比如
java.lang.Runnable
、java.util.Comparator
等,并提供了典型常用的函数式接口集,它们都在java.util.function
包下,之后会进一步说明和应用。
开始lambda表达式
从匿名内部类开始
- 对一个bean集合进行排序
- 代码
@Test public void testLambdaAndAnonymousClass1() { List<TestBean> list = TestBean.list(); //初始顺序(即加入list的顺序) list.forEach(o -> System.out.print(o.getName() + " ")); System.out.println("\n============================="); //根据名称排序,匿名内部类方式 list.sort(new Comparator<TestBean>() { @Override public int compare(TestBean o1, TestBean o2) { return o1.getName().compareTo(o2.getName()); } }); //操作后顺序 list.forEach(o -> System.out.print(o.getName() + " ")); } //Bean类 public class TestBean extends SerializableBean{ private static final long serialVersionUID = 2394995648350379173L; private Integer id; private String name; public static List<TestBean> list(){ return Arrays.asList( new TestBean(1, "Richard") ,new TestBean(2, "Ben") ,new TestBean(3, "Jack") ,new TestBean(4, "Jet") ,new TestBean(5, "Dicky") ); }
- 输出
Richard Ben Jack Jet Dicky ============================= Ben Dicky Jack Jet Richard
用lambda实现函数式接口,代替匿名内部类
Comparator
接口是函数式接口@FunctionalInterface public interface Comparator<T> {}
- lambda实现函数式接口,作为参数传入
@Test public void testLambdaAndAnonymousClass2() { List<TestBean> list = TestBean.list(); //初始顺序(即加入list的顺序) list.forEach(o -> System.out.print(o.getName() + " ")); System.out.println("\n============================="); //根据名称排序,使用lambda Comparator<TestBean> sortByName = (o1,o2) -> o1.getName().compareTo(o2.getName()); list.sort(sortByName); //或者直接 list.sort((o1,o2) -> o1.getName().compareTo(o2.getName())); //操作后顺序 list.forEach(o -> System.out.print(o.getName() + " ")); }
函数式接口
原Java7的一些接口进化为函数式接口
比如:
- java.util.Comparator
- java.lang.Runnable
- java.util.concurrent.Callable
- java.io.FileFilter
- java.nio.file.PathMatcher
- java.lang.reflect.InvocationHandler
- java.beans.PropertyChangeListener
- java.security.PrivilegedAction
- ......
lambda实现Runnable
- 观察Runnable接口实现,无参数,比Consumer
还简单 new Runnable() { @Override public void run() { } };
- 简单代码
@Test public void testLambdaAndAnonymousClass3() { List<TestBean> list = TestBean.list(); Runnable runner = () -> list.forEach(System.out::println); //方法引用 new Thread(runner).start(); }
- lambda的基本语法和方法引用就不表了
Java8四大内置通用行为函数式接口
- Consumer
消费型, 接受一个T,不返回值 - 源码
@FunctionalInterface public interface Consumer<T> { void accept(T t); ... }
- 实例 in jdk8:Iterable的forEach方法
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }
- 源码
- Function<T, R> 函数型,接受一个T,返回一个R
- 源码
@FunctionalInterface public interface Function<T, R> { R apply(T t); ... }
- 实例 in jdk8:Optional的map方法
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } }
- 实现
@Test public void testLambdaAndFunctional() { TestBean testBean = new TestBean(1, "hhh"); Optional<TestBean> opt = Optional.ofNullable(testBean); Optional<String> mapName = opt.map(TestBean::getName); //t -> t.getName() System.out.println(mapName); //Optional[hhh] }
- 源码
- Predicate
断言型,接受一个T,返回boolean - 源码
@FunctionalInterface public interface Predicate<T> { boolean test(T t); ... }
- 实例 in jdk8:Stream的filter方法
Stream<T> filter(Predicate<? super T> predicate);
- 实现
@Test public void testLambdaAndPredicate() { List<TestBean> testBean = TestBean.list(); testBean.stream().filter(o -> o.getId()>2) .forEach(System.out::println); //参数一致,方法引用简写 }
- 源码
- Supplier
供给型,不接受参数,返回一个T - 源码
@FunctionalInterface public interface Supplier<T> { T get(); }
- 实例 in jdk8:Optional的orElseGet方法
public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
- 实现
@Test public void testLambdaAndSupplier() { TestBean testBean = (int)Math.floor(Math.random()*10)>5? new TestBean(1,"111") : null; System.out.println(Optional.ofNullable(testBean).orElseGet(TestBean::new));// () -> new TestBean() }
- 源码
- 以上各子接口 + 更细致灵活的接口
- BiFunction<T, U, R>
- DoubleConsumer
- ......