一: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表达式也可以是包含多个参数的方法;
BinaryOperator<Long> add = (x, y) -> x + y;
BinaryOperator<Long> 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> T boolean 这张唱片已经发行了吗
* Consumer<T> T void 输出一个值
* Function<T,R> T R 获得 Artist 对象的名字
* Supplier<T> None T 工厂方法
* UnaryOperator<T> T T 逻辑非( !)
* BinaryOperator<T> (T, T) T 求两个数的乘积( *)
*
* 2.5类型推断
* Predicate 用来判断真假的函数接口
*/
public static void 类型推断() {
Predicate<Integer> atLeast5 = x -> x > 5;
}
//Predicate 接口的源码, 接受一个对象, 返回一个布尔值
public interface Predicate<T> {
boolean test(T t);
}
//略显复杂的类型推断 :类型推断系统相当智能, 但若信息不够, 类型推断系统也无能为力。 类型系统不会漫无边
//际地瞎猜, 而会中止操作并报告编译错误, 寻求帮助 ,如去掉Long,代码不会通过编译
BinaryOperator<Long> 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<T, R> {
R apply(T t);
}
a. 请画出该函数接口的图示。
b. 若要编写一个计算器程序, 你会使用该接口表示什么样的 Lambda 表达式?
c. 下列哪些 Lambda 表达式有效实现了 Function<Long,Long> ?
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(Predicate<Integer> predicate);
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 ThreadLocal<DateFormatter> formatter = ThreadLocal.withInitial(() -> new DateFormatter(new SimpleDateFormat("dd-MMM-yyyy")));
//Anonymous Inner Class -byzhangdi
public final static ThreadLocal<DateFormatter> formatter2 = ThreadLocal.withInitial( new Supplier<DateFormatter>(){
@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<DateFormatter> 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);
}
}