Java8学习笔记(一)-初步认识Lambda表达式

来源:互联网 发布:apache url重写 编辑:程序博客网 时间:2024/05/17 01:30
Lambda是什么?

  In programming languages such as Lisp,Pythson and Ruby Lambda is an operator used to denote anonymous function or closures,following the usage of lambda calculus

为什么要使用Lambda表达式?

  在java中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法

  在javascript中,函数参数是一个函数,返回值是另一个函数的情况是非常常见的,javascript是一门非常典型的函数式语言

Java匿名内部类案例带来的问题

 1 public class Test { 2     public static void main(String[] args) { 3         JFrame jframe = new JFrame("测试窗口"); 4         JButton jbtn   = new JButton("测试按钮"); 5         jbtn.addActionListener(new ActionListener() { 6             public void actionPerformed(ActionEvent arg0) { 7                 System.out.println("测试按钮被点击了"); 8             } 9         });10         jframe.add(jbtn);11         jframe.setVisible(true);12     }13 }

以上代码,关键部分就是执行按钮被点击后的核心操作,但是却使用了大量的冗余代码,那么使用Lambda表达式可以有效地简化以上代码

1 jbtn.addActionListener(event -> {2             System.out.println("按钮被点击了");3 });
event的数据类型是java7开始加入的类型推断机制,有些时候是推断不出来的,需要我们自己显示定义
1 jbtn.addActionListener((ActionEvent e) -> {2             System.out.println("按钮被点击了");3             System.out.println("不使用类型推断机制");4 });

 Lambda表达式的基本结构

(param1,param2,...)->{          statemnt;}

再看一个案例

 

 1 package cn.org.kingdom.jdk8; 2  3 import java.util.Arrays; 4 import java.util.List; 5 import java.util.function.Consumer; 6 7 public class Test2 { 8     public static void main(String[] args) { 9         List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);10         // 最早的遍历方式11         for (int i = 0; i < list.size(); i++) {12             System.out.println(list.get(i));13         }14         System.out.println("-------------------");15         // 增强的for循环的方式16         for (Integer i : list) {17             System.out.println(i);18         }19         System.out.println("*********************");20         list.forEach(new Consumer<Integer>() {21             @Override22             public void accept(Integer t) {23                 System.out.println(t);24             }25         });26 27     }28 }

下面咱们研究一下Consumer接口

 1 /** 2  * Represents an operation that accepts a single input argument and returns no 3  * result. Unlike most other functional interfaces, {@code Consumer} is expected 4  * to operate via side-effects. 5  * 6  * <p>This is a <a href="package-summary.html">functional interface</a> 7  * whose functional method is {@link #accept(Object)}. 8  * 9  * @param <T> the type of the input to the operation10  *11  * @since 1.812  */13 @FunctionalInterface14 public interface Consumer<T> {15 16     /**17      * Performs this operation on the given argument.18      *19      * @param t the input argument20      */21     void accept(T t);22 23     /**24      * Returns a composed {@code Consumer} that performs, in sequence, this25      * operation followed by the {@code after} operation. If performing either26      * operation throws an exception, it is relayed to the caller of the27      * composed operation.  If performing this operation throws an exception,28      * the {@code after} operation will not be performed.29      *30      * @param after the operation to perform after this operation31      * @return a composed {@code Consumer} that performs in sequence this32      * operation followed by the {@code after} operation33      * @throws NullPointerException if {@code after} is null34      */35     default Consumer<T> andThen(Consumer<? super T> after) {36         Objects.requireNonNull(after);37         return (T t) -> { accept(t); after.accept(t); };38     }39 }

对于Comsume接口上面有一个@FunctionalInterface-->函数式接口,那么什么是函数式接口呢?

咱们再来看一看FunctionalInterface的源码定义

 1 package java.lang; 2  3 import java.lang.annotation.*; 4  5 /** 6  * An informative annotation type used to indicate that an interface 7  * type declaration is intended to be a <i>functional interface</i> as 8  * defined by the Java Language Specification. 9  *10  * Conceptually, a functional interface has exactly one abstract11  * method.  Since {@linkplain java.lang.reflect.Method#isDefault()12  * default methods} have an implementation, they are not abstract.  If13  * an interface declares an abstract method overriding one of the14  * public methods of {@code java.lang.Object}, that also does15  * <em>not</em> count toward the interface's abstract method count16  * since any implementation of the interface will have an17  * implementation from {@code java.lang.Object} or elsewhere.18  *19  * <p>Note that instances of functional interfaces can be created with20  * lambda expressions, method references, or constructor references.21  *22  * <p>If a type is annotated with this annotation type, compilers are23  * required to generate an error message unless:24  *25  * <ul>26  * <li> The type is an interface type and not an annotation type, enum, or class.27  * <li> The annotated type satisfies the requirements of a functional interface.28  * </ul>29  *30  * <p>However, the compiler will treat any interface meeting the31  * definition of a functional interface as a functional interface32  * regardless of whether or not a {@code FunctionalInterface}33  * annotation is present on the interface declaration.34  *35  * @jls 4.3.2. The Class Object36  * @jls 9.8 Functional Interfaces37  * @jls 9.4.3 Interface Method Body38  * @since 1.839  */40 @Documented41 @Retention(RetentionPolicy.RUNTIME)42 @Target(ElementType.TYPE)43 public @interface FunctionalInterface {}
翻译如下:
  一个通知性的注解类型用于表示一个接口类型声明只在成为一个函数式接口(这个函数式接口是由java语言规范所定义的)
  从概率上来看,一个函数式接口只有一个精确的抽象方法,由于java.reflect.method的isDefault方法有一个默认的实现,因此他们不是抽象的,如果一个接口声明了一个抽象方法重写了Object类的方法,它们也不能增加函数式接口中抽象方法的数量,因为接口的任意实现都有来自于object类或者其他地方的任意实现
  注意一个函数式接口的实例可以通过lambda表达式、方法引用、构造引用来创建
  如果一个类型被这种类型所表示,那么编译器被要求强制生成一个错误信息:
  然而编译器对待任何一个接口,只要这个接口满足了函数式接口定义的要求,依然会将该接口当成一个函数式接口,而不管这个接口上是否加上了这么一个FunctionalInterface注解

总结:关于函数式接口

1.如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口

2.如果我们在某个接口上声明了FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口

3.如果某个接口只有一个抽象方法,但我们并没有给该接口声明Functional注解,那么编译器依旧会将该接口看做函数式接口