Lambda表达式和函数式接口
刚进公司时,公司正处于由JDK7换用JDK8的时间短,之所以更换JDK版本,听说是公司业务中需要用到JDK8的一些新特性。鉴于我现在也无事可做,姑且来学习总结一下JDK8的一些特性吧。水平有限,这篇勉强算是对他人博客上零散内容的一个总结。
1. Lambda表达式
Lambda表达式 匿名函数,当需要一个函数而又不想给他一个命名时,在java中,对于那些只使用一次的方法使用这种方式,能够减少命名上的负担。
允许将行为传入函数,取代匿名类。很经典的就是一个实现Runnable接口的例子,之前很长一段时间用的是匿名内部类,现在有了lambda表达式来使用。
//使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("The old runable now is using!");
}
}).start();
//使用lambda表达式
new Thread(() -> System.out.println("It's a lambda function!")).start();
减少了很多代码量,也使得代码结构更加清晰。
允许使用函数式风格编程,将函数当成参数传递给某个方法,或者把代码本身当作数据处理
结构写法上,lambda表达式由三部分组成: (参数列表),符号 -> ,函数体(多个语句时加上{})。可以访问类的成员变量和局部变量,但是会转为final。
具体的一些匿名函数的使用,由于不太能用到所以不过多说明,仅举部分例子来作为使用时写法的参考,以集合类的遍历为例,虽然用之前的写法也不复杂。之所以选择集合类就是因为很熟悉,不用写原先的遍历方法出来,也能很好的对比两种写法的差异。
//List的遍历
List<String> list = new ArrayList<>();
list.add("aaa");
...
...
list.forEach(x -> System.out.println(x));
//Map的遍历
LinkedHashMap<Integer,Integer> lhm = new LinkedHashMap<>();
lhm.put(1, 4);
...
...
lhm.forEach((k,v) -> System.out.println("key:" + k + " value:" + v));
2. 函数式接口
函数式接口是SAM(Single Abstract Method )类型的接口,是为了让现有功能能和Lambda表达式能够良好兼容所想出的方法。
定义了这种类型的接口,使得以其为参数的方法,可以在调用时,使用一个lambda表达式作为参数。换个角度说就是,当我们调用一个方法,可以传入lambda表达式作为参数,那么这个方法的参数类型,必定是一个函数式的接口。
就是指只有一个函数的接口,这样的接口可以被隐式转换为Lambda表达式。例如,java.lang.Runnable
和 java.util.concurrent.Callable
等。
但是函数接口代码层面十分脆弱,只要这个接口中有其他的函数就会编译失败,为了解决函数接口在实际使用过程中的脆弱性。采用显式说明的方式,jdk8提供了一个@FunctionalInterface
这个注解来进行声明。
不过默认方法和静态方法不会破环函数式接口的定义。
举上面提到的两个jdk中代码的例子:
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
上面两个都是函数式接口的写法,然后我们来对比一下使用lambda和不使用lambda表达式的写法差别:
//不使用Lambda表达式时
Runnable runnable1=new Runnable(){
@Override
public void run(){
System.out.println("RunningwithoutLambda");
}
};
//使用Lambda表达式的写法
Runnable runnable2=()->{
System.out.println("RunningfromLambda");
};
3. 其他
其他什么predicate,stream之类的以后有机会有时间再来补充讨论。