博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java SE 8: Lambda Quick Start Part.I
阅读量:6878 次
发布时间:2019-06-26

本文共 4155 字,大约阅读时间需要 13 分钟。

hot3.png

背景

匿名内部类

在Java中, 名内部类提供了一种实现class的方式,这个class在应用中可能只会出现一次. 比如, 在Swing或JavaFX应用中,键盘和鼠标事件需要编写大量的事件处理器.与其为每一个事件编写一个独立的事件处理器class,采用下面的写法更常见:

JButton testButton = new JButton("Test Button");  testButton.addActionListener(new ActionListener(){    @Override public void actionPerformed(ActionEvent ae){      System.out.println("Click Detected by Anon Class");    }  });

此外, 每个事件都需要一个实现ActionListener的单独类. 每当需要时就创建一个class, 这样的代码更易读. 但它们并不优雅, 因为相当多的代码只为了定义一个方法.

函数式接口

定义ActionListener接口的代码如下:

package java.awt.event;  import java.util.EventListener;  public interface ActionListener extends EventListener {  public void actionPerformed(ActionEvent e);  }

ActionListener示例是只有一个方法的接口. 对于Java SE 8, 遵循此模式的接口称为"函数式接口".

> Note: 这种类型的接口, 以前称为单抽象方法类型(SAM).

在Java中使用带有匿名内部类的功能接口是一种常见模式. 除了EventListener类, 类似Runnable和Comparator的接口也以类似的方式使用. 因此, 函数接口可以用于lambda表达式.

Lambda表达式语法

lambda表达式通过将五行代码转换为单个语句来解决匿名内部类的庞大性. 这个简单的水平解决方案解决了内部类提出的"垂直问题".<br> lambda表达式由三部分组成:

参数列表 箭头符 主体
(int x, int y) -> x + y

主体可以是单个表达式或语句块. 在表达式形式中, 简单地对主体进行求值和返回; 在语句块形式中, 主体的计算方法类似于方法体, return语句将控制权返回给匿名方法的调用者. break和continue关键字在顶层是非法的, 但在循环中是允许的. 如果主体产生一个结果, 每个控制路径必须返回一些东西或抛出异常.<br> 看看这些例子:

(int x, int y) -> x + y() -> 42(String s) -> { System.out.println(s); }

第一个表达式接受两个整数参数, 命名为x和y, 并使用表现形式返回X + Y;<br> 第二个表达式不带参数, 并使用表达式形式返回整数42;<br> 第三个表达式接受一个字符串, 并使用语句块形式将字符串打印到控制台, 并不返回任何内容.

有了语法的基础知识, 让我们看一些例子.

Lambda 示例

Runnable Lambda

这里是如何使用lambdas写一个Runnable:

public class RunnableTest {  public static void main(String[] args) {    System.out.println("=== RunnableTest ===");    // Anonymous Runnable    Runnable r1 = new Runnable(){      @Override      public void run(){        System.out.println("Hello world one!");      }    };    // Lambda Runnable    Runnable r2 = () -> System.out.println("Hello world two!");    // Run em!    r1.run();    r2.run();  }}

在这两种情况下, 请注意没有传递参数并返回. Runnable lambda使用语句块形式讲5行代码转换为一个语句.

Comparator Lambda

在Java中, Comparator类用于排序集合. 在以下示例中, 由Person对象组成的ArrayList基于surName进行排序. 以下是Person类中包含的字段.

public class Person {  private String givenName;  private String surName;  private int age;  private Gender gender;  private String eMail;  private String phone;  private String address;}

以下代码通过使用一个匿名内部类和几个lambda表达式实现一个Comparator.

public class ComparatorTest {  public static void main(String[] args) {    List
personList = Person.createShortList(); // Sort with Inner Class Collections.sort(personList, new Comparator
() { public int compare(Person p1, Person p2) { return p1.getSurName().compareTo(p2.getSurName()); } }); System.out.println("=== Sorted Asc SurName ==="); for (Person p : personList) { p.printName(); } // Use Lambda instead // Print Asc System.out.println("=== Sorted Asc SurName ==="); Collections.sort(personList, (Person p1, Person p2) -> p1.getSurName().compareTo(p2.getSurName())); for (Person p : personList) { p.printName(); } // Print Desc System.out.println("=== Sorted Desc SurName ==="); Collections.sort(personList, (p1, p2) -> p2.getSurName().compareTo(p1.getSurName())); for (Person p : personList) { p.printName(); } }}

第5-9行很容易被第19行的lambda表达式替换. 请注意, 第一个lambda表达式显示声明了传递给表达式的参数类型. 但是, 从第二个表达式可以看出, 这是可选的. Lambda支持"目标类型", 它从使用它的上下文中推断对象类型. 因为我们将结果分配给用泛型定义的比较器, 所以编译器可以推断这两个参数都是Person类型.

Listener Lambda

最后, 让我们重温一下ActionListener的例子.

public class ListenerTest {  public static void main(String[] args) {    JButton testButton = new JButton("Test Button");    testButton.addActionListener(new ActionListener() {      @Override      public void actionPerformed(ActionEvent ae) {        System.out.println("Click Detected by Anon Class");      }    });    testButton.addActionListener(e -> System.out.println("Click Detected by Lambda Listner"));    // Swing stuff    JFrame frame = new JFrame("Listener Test");    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    frame.add(testButton, BorderLayout.CENTER);    frame.pack();    frame.setVisible(true);  }}

请注意, lambda表达式作为参数传递. 目标类型在许多上下文中使用,包括以下:

* 变量声明 * 分配 * 返回语句 * 数组初始化 * 方法或构造函数参数 * Lambda表达式主体 * 条件表达式 ?: * 强制转型

转载于:https://my.oschina.net/CasparLi/blog/799484

你可能感兴趣的文章
iOS中如何对具有复杂依赖的SDK在真机上进行单元测试
查看>>
Mobile Web中URL设计问题
查看>>
core Animation之CAAnimationGroup(动画群组)
查看>>
重构实践:体验interface的威力(一)
查看>>
UILabel混合显示动画效果
查看>>
Java内存泄露
查看>>
窥探Swift编程之强大的Switch
查看>>
R语言学习路线图-转帖
查看>>
【导入导出】sqlldr 导入含有内嵌换行符的数据
查看>>
Linux中常用命令
查看>>
RDS最佳实践(四)—如何处理Mysql的子查询
查看>>
最大流:Dinic模板
查看>>
安卓开发中个人能力的进阶进程
查看>>
人工智能10年将有颠覆性改变
查看>>
探秘AOP实现原理
查看>>
单点登录(SSO)简介
查看>>
2018最新大数据学习路线分享
查看>>
利用SVG制作不规矩背景的链接导航
查看>>
Linux - 一次运行多个命令
查看>>
10.C# -- 函数参数,参数数组,值传递函数,引用传递函数,输出函数,无参函数...
查看>>