Lambda 表达式

·  阅读 169
Lambda 表达式

Lambda

Lambda 是一个匿名函数,可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使 Java 的语言表达能力得到了提升。

  • Lambda 表达式的语法显然比匿名内部类更简洁:
// 匿名内部类
new Thread (new Runnable() {
	@Override
 	public void run() {
	    System.out.println("One man's constant is another man's variable.");
	}
});

// Lambda 表达式
new Thread(()-> System.out.println("One man's constant is another man's variable.")).start();
复制代码

Lambda 表达式的其他形式:

  • Lambda 需要一个参数,但无返回值
// 接口需要一个形参
Consumer<String> consumer = (String s)  -> {
	System.out.println(s);
};

consumer.accept("One man's constant is another man's variable.");
复制代码
  • 类型推断,可省略形参的数据类型
// 省略参数类型声明 - String
Consumer<String> consumer = (s) -> {
	System.out.println(s);
};

consumer.accept("One man's constant is another man's variable.");
复制代码
  • 若 Lambda 表达式只需一个参数且仅有一条语句时(){}return(若有返回值) 可省略
// 接口仅需一个参数,可省略小括号
Consumer<String> consumer = s -> System.out.println(s);

consumer.accept("One man's constant is another man's variable.");
复制代码

函数式编程接口

函数式接口:只包含一个抽象方法的接口。

简单的说,Lambda 表达式就是一个函数式接口的实例。

我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

Java 内置四大核心函数式接口

函数式接口参数类型返回类型用途
消费型接口:ConsumerTvoid对类型为 T 的对象应用操作,包含方法:
void accept(T t)
供给型接口:SupplierT返回类型为 T 的对象,包含方法:
T get()
函数型接口:Function<T, R>TR对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:
R apply(T t)
断定型接口:PredicateTboolean确定类型为T的对象是否满足某约束,并返回 boolean 值。包含方法:
boolean test(T t)

测试用例:

@Test
public void demo() {
	List<String> list = Arrays.asList("北京", "南京", "天津");
	
	List<String> filtered = filterString(list, s -> s.contains("京"));
	System.out.println(filtered);
}

public List<String> filterString(List<String> list, Predicate<String> pre) {
	// 过滤后的集合
	ArrayList<String> filteredList = new ArrayList<>();
	for (String s : list) {
		if (pre.test(s)) {
			filteredList.add(s);
	    }
	}
	return filterList;
}
复制代码

方法引用

方法引用可以看做是 Lambda 表达式深层次的表达。

换句话说,方法引用就是 Lambda 表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是 Lambda 表达式的一个语法糖

如果 函数式接口的实现恰好仅通过一个方法实现,则可以使用方法引用替换函数式接口。

主要分为以下三种情况

  • 对象 :: 实例方法
@Test
public void demo() {
    Assassin w = new Assassin("伍六柒", 16);
    // 调用 Assassin 对象 w 的 getName() 方法
    Supplier<String> sup = w::getName;
    System.out.println(sup.get());
}
复制代码
  • 类 :: 静态方法
@Test
public void demo() {
    // 调用 Math 的 round() 方法
    Function<Double, Long> func2 = Math::round;
    System.out.println(func2.apply(12.6));
}
复制代码
  • 类 :: 实例方法
@Test
public void demo() {
    BiPredicate<String, String> pre = String::equals;
    // 调用 String 的 equals() 方法
    System.out.println(pre.test("and", "or"));
}
复制代码

注意:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!

构造器引用

格式: ClassName::new

// Lambda 表达式
Function<Integer, MyClass> lambda = (n)->new MyClass(n);

// 构造器引用
Function<Integer, MyClass> constructor = MyClass::new;
复制代码

数组引用

格式: type[] :: new

// Lambda 表达式
Function<Integer, Integer[]> lambda = (n)->new Integer[n];

// 数组引用
Function<Integer, Integer[]> arr = (n)->Integer[]::new;
复制代码

null-pointer

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改