前言:作者本人无函数式编程经验,看了函数式编程后,有些粗浅的认识,记录下,避免遗忘。
1 函数式编程解决了什么问题?
函数式编程解决了,java中丑陋的内部类代码。很多人提到函数式编程,都是list.foreach举例,我要用大家熟悉的runnable举例,“hello word”走起,异步打印最简单的例子
a 常规写法
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello world");
}
});
t.start();
t.join();
}
b lambda 函数式编程写法
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->System.out.println("hello world"));
t.start();
t.join();
}
可以看到,函数写法,短短3行代码,解决问题。
c lambda 写法2
public static void main(String[] args) throws InterruptedException {
Runnable run = ()->System.out.println("hello world");
Thread t = new Thread(run);
t.start();
t.join();
}
这样应该更好理解,()->System.out.println("hello world")就是接口(Runnable)的一个实现。
d Thread有多个构造函数,函数式编程时,编译器怎么知道是哪个?元芳,怎么看
元芳:大人,此事必有蹊跷。连Eclipse都能分析到,编译器肯定可以搞定。
首先,Thread的构造函数中,接受一个形式参数的,就一个,所以构造函数肯定是Thread(Runnable target),其次如果有2个构造函数,这2个构造函数都接受一个形式参数,如果只有Runnable是函数式接口,编译器也找得到,不会报错。这里要说说函数式接口。
2 函数式接口
Runnable上面增加了一个注解,表明Runnable是一个函数式接口。Java 库中的所有相关接口都已经带有这个注解了。
就像正方形也是矩形一样,函数式接口,也是一个接口(interface),要求接口里面只有一个方法,是个特殊的接口,就如正方形是特殊的矩形。而Runnable接口里面只有一个Run方法,满足函数式接口的要求,自然是一个函数式接口了。
到这里就不难理解,编译器是如何工作的了,因为函数式接口,只有一个方法,那么()->System.out.println("hello world")就是实现了这唯一的一个方法了。函数式编程原来如此简单。
由于Runnable.run()没有形式参数,所以函数式编程()->System.out.println("hello world")也是没有形式参数的。
3 补充
举个接受一个参数的例子
Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
forEach是Collection集合类新增的方法,看看ArrayList的forEach实现
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
写了很多,大部分都是防止在遍历的时候,修改list,防止多线程出错,我把多线程去掉,代码如下
public void forEach(Consumer<? super E> action) {
final int size = this.size;
for (int i=0; i < size; i++) {
action.accept(elementData[i]);
}
}
不用多说了,这个简单吧,forEach完全可以用传统的内部类实现,我要复辟下。
Consumer<Integer> action = new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.println(t);
}
};
list.forEach(action);
还有很多要补充的,例如:凡事都有例外,前面说了函数式接口,是只有一个方法的接口,但可以有静态方法和默认方法。静态方法和默认方法请参考http://blog.csdn.net/u014470581/article/details/54944384
这篇文章写得很深刻
http://blog.csdn.net/hnulwt/article/details/44338637
这篇文章写得很全面
http://blog.csdn.net/u014470581/article/details/54944384