本文共 5661 字,大约阅读时间需要 18 分钟。
一:Learning
package testLambda;import java.awt.Button;import java.awt.event.ActionEvent;import java.util.EventListener;import java.util.function.BinaryOperator;import org.junit.Test;/** * @author zhangdi * @description Lambda */public class LambdaChapter1and2 { public static void main(String[] args) { } /** * 2.1 辨别Lambda表达式 */ @SuppressWarnings("unused") @Test public static void recognizeLambda() { // 1.不包含参数,使用()表示,没有参数,该Lamdba表达式实现了Runnable接口,该接口也只有一个run方法,没有参数,返回类型为void Runnable NoArguments = () -> System.out.println("hello world"); // 2.该Lamdba表达式包含且只包含一个参数可省略参数的括号 ActionListener oneArgument = (event) -> System.out.println("button clicked"); ActionListener oneArgument2 = event -> System.out.println("button clicked"); // 3.可以使用{}将lamdba表达式的主体括起来;只有一行代码的lambda的表达式也可以使用大括号;用来明确表达式的开始与结束 Runnable multistatement = () -> { System.out.println("hello"); System.out.println("world"); }; // 4.lambda表达式也可以是包含多个参数的方法; BinaryOperatoradd = (x, y) -> x + y; BinaryOperator addExplicit = (Long x, Long y) -> x + y; } /** * 2.2 函数接口是只有一个抽象方法的接口,用作lambda表达式的类型 */ public static void 函数接口() { } /** * 2.3 引用值,而不是变量 * 既成事实上的 final 是指只能给该变量赋值一次。 换句话说, Lambda 表达式引用的是值,而不是变量 * Lambda 表达式中引用既成事实上的 final 变量 -->Lambda 表达式都是静态类型 */ public static void valueReference() { Button button = new Button(); String name = getUserName(); button.addActionListener(event -> System.out.println("hi " + name)); } private static String getUserName() { // TODO Auto-generated method stub return "test"; } /** * 2.4 ActionListener 接口: 接受 ActionEvent 类型的参数, 返回空 * * ActionListener 只有一个抽象方法: actionPerformed, 被用来表示行为: 接受一个参数, 返回空。 * 记住, 由于 actionPerformed 定义在一个接口里, 因此 abstract 关键字不是必需 的。 * 该接口也继承自一个不具有任何方法的父接口: EventListener。 */ public interface ActionListener extends EventListener { public void actionPerformed(ActionEvent event); } /** *java中重要的函数接口 * 接口 参数 返回类型 示例 * Predicate T boolean 这张唱片已经发行了吗 * Consumer T void 输出一个值 * Function T R 获得 Artist 对象的名字 * Supplier None T 工厂方法 * UnaryOperator T T 逻辑非( !) * BinaryOperator (T, T) T 求两个数的乘积( *) * * 2.5类型推断 * Predicate 用来判断真假的函数接口 */ public static void 类型推断() { Predicate atLeast5 = x -> x > 5; } //Predicate 接口的源码, 接受一个对象, 返回一个布尔值 public interface Predicate { boolean test(T t); } //略显复杂的类型推断 :类型推断系统相当智能, 但若信息不够, 类型推断系统也无能为力。 类型系统不会漫无边 //际地瞎猜, 而会中止操作并报告编译错误, 寻求帮助 ,如去掉Long,代码不会通过编译 BinaryOperator addLongs = (x, y) -> x + y; //没有泛型, 代码则通不过编译}
java中重要的函数接口:
总结: * Lambda 表达式是一个匿名方法, 将行为像数据一样进行传递。 * Lambda 表达式的常见结构: BinaryOperator add = (x, y) → x + y。 * Lambda表达式里引用的到的变量是final的,本质是值,不是变量。 * Lambda表达式的类型是个函数接口,即仅有一个抽象方法的接口。( 函数接口指仅具有单个抽象方法的接口, 用来表示 Lambda 表达式的类型。)二: 练习
1. 请看例 2-15 中的 Function 函数接口并回答下列问题。 例 2-15 Function 函数接口public interface Function{ R apply(T t); }
a. 请画出该函数接口的图示。b. 若要编写一个计算器程序, 你会使用该接口表示什么样的 Lambda 表达式?c. 下列哪些 Lambda 表达式有效实现了 Function?
x -> x + 1; (x, y) -> x + 1; x -> x == 1;
2. ThreadLocal Lambda 表达式。 Java 有一个 ThreadLocal 类, 作为容器保存了当前线程里局部变量的值。 Java 8 为该类新加了一个工厂方法, 接受一个 Lambda 表达式, 并产生一个新的 ThreadLocal 对象, 而不用使用继承, 语法上更加简洁。a. 在 Javadoc 或集成开发环境( IDE) 里找出该方法。b. DateFormatter 类是非线程安全的。 使用构造函数创建一个线程安全的 DateFormatter对象, 并输出日期, 如“ 01-Jan-1970”。3. 类型推断规则。 下面是将 Lambda 表达式作为参数传递给函数的一些例子。 javac 能正确推断出 Lambda 表达式中参数的类型吗? 换句话说, 程序能编译吗?a. Runnable helloWorld = () -> System.out.println("hello world");b. 使用 Lambda 表达式实现 ActionListener 接口:
JButton button = new JButton(); button.addActionListener(event -> System.out.println(event.getActionCommand()));
c. 以如下方式重载 check 方法后, 还能正确推断出 check(x -> x > 5) 的类型吗?
interface IntPred { boolean test(Integer value); } boolean check(Predicatepredicate); boolean check(IntPred predicate);
练习答案:
public class Chapter1And2_practice { public static class Question1 { //x -> x + 1; } public static class Question3 { //a.yes //b.yes //c.no } /** * @author NSNP736 * @description Question2 */ public static class Question2 { //lamada-by richard public final static ThreadLocalformatter = ThreadLocal.withInitial(() -> new DateFormatter(new SimpleDateFormat("dd-MMM-yyyy"))); //Anonymous Inner Class -byzhangdi public final static ThreadLocal formatter2 = ThreadLocal.withInitial( new Supplier (){ @Override public DateFormatter get() { DateFormatter dateFormatter = new DateFormatter(new SimpleDateFormat("dd-MMM-yyyy")); return dateFormatter; }}); } @Test public void exampleInB() { Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, 1970); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); //formatter String format1 = Question2.formatter.get().getFormat().format(cal.getTime()); //formatter2 ThreadLocal formatter = Question2.formatter; DateFormatter dateFormatter = formatter.get(); Format format = dateFormatter.getFormat(); String format2 = format.format(cal.getTime()); assertEquals("01-一月-1970", format1); assertEquals("01-一月-1970", format2); }}