剖析Java8的lamda表达式02

《剖析Java8的lamda表达式02》

 

在《剖析Java8的lamda表达式01》中,相信大家已经对lamda表达式有了一定的认识和明确基本语法和用法。那么接下来本章我们再继续了解和学习lamda表达式。

 

来看看上一章中的一个例子:

Runnable t1 = () -> System.out.println(Thread.currentThread().getId());

上述程序示例中,由lamda表达式生成了Runnable接口的实例,那么大家思考一下,编译器在编译时是如何做到自动类型推断的呢?也就是说,编译器是如何知道lamda表达式对应的目标类型。不知大家是否还记得,函数式接口只允许定义1个抽象接口(函数描述符),那么上述代码在编译的时候,编译器会根据lamda的上下文进行自动推断目标类型是什么样的。

并且lamda的参数列表除了可以显式的声明参数类型外,编译器仍然也可以自动对类型进行推断,如下所示:

@FunctionalInterface
public interface Compare {
 public boolean compare(String str1, String str2);
}
/* 自动类型推断 */
Compare compare = (str1, str2) -> str1.equals(str2);
compare.compare("a", "b");

其实说到底,编译器在编译的时候就是匹配方法签名和lamda表达式签名来实现自动类型推断

lamda表达式主体除了可以使用参数列表中的参数外,还可以使用局部变量,当然这里大家需要注意,局部变量必须是final,当然Java8中并不需要显示的将匿名类中对外层作用域中定义的变量显式声明为final,但实际上局部变量仍然是final,只是它是隐式的而已:

/* 隐式定义的fina常量 */
String str = "id:";
/* lamda用法 */
new Thread(() -> {
 System.out.println(str + Thread.currentThread().getId());
}).start();

 接下来,我们再来看看如何使用方法引用来简化lamda表达式,是的,更加简洁的操作,何乐而不为。简单来说,方法引用可以被看作仅仅调用特定方法的lamda表达式的一种快捷写法。如果一个lamda代表的是“直接调用这个方法”,那并不需要去描述如何调用它,而是用名称来调用它:

List<String> list = Arrays.asList("a", "b", "c");
/* 使用lamda表达式进行迭代 */
list.forEach((str) -> System.out.println(str));
/* 使用方法引用进行迭代 */
list.forEach(System.out::println);
/* 使用lamda表达式获取字符串长度 */
Consumer<String> com = (str) -> str.length();
/* 使用方法引用获取字符串长度 */
com = String::length;

 和方法引用类似,对于构造函数而言,我们可以利用类型名称和关键字new(className::new)来创建一个对象引用:

public class Main {
 public static void main(String[] args) {
  /* 使用lamda表达式 */
  Function<String, Integer> function = (str) -> new Integer(str);
  function.apply("123");
  /* 使用lamda表达式 */
  function = Integer::new;
  function.apply("321");
  /* 使用lamda表达式 */
  FunctionaTest<String, String, String, Test> fTest = (str1, str2, str3) -> new Test(str1, str2, str3);
  fTest.get("a", "b", "c");
  /* 使用lamda表达式 */
  fTest = Test::new;
  fTest.get("d", "e", "f");
 }
}
/* 带多个参数的构造函数 */
class Test<T, U, V> {
 Test(T t, U u, V v) {
 }
}
@FunctionalInterface
interface FunctionaTest<T, U, V, R> {
 public R get(T t, U u, V v);
}

上述程序示例中,笔者演示了如何通过构造函数引用来创建对象引用。在此大家需要注意,如果构造函数带参数,无论参数个数有多少,构造函数引用的语法始终是className::new那么构造函数引用的签名一定要与函数式接口的方法签名相互匹配

猜你喜欢

转载自gao-xianglong.iteye.com/blog/2399458