鲜活的java 8 --- java 8 进化之路(二)

2014-11-23 22:14:57 · 作者: · 浏览: 2
3); k.add(8); k.add(11); k.add(20); k.add(50); Optional max = k.stream().max((a,b) -> {return a-b;}); System.out.println(max); }

想变成并发操作这样写:

// 求一个链表中的最大值
public static void main(String[] args) {
		
		List
    
      k = new ArrayList
     
      (); k.add(1); k.add(2); k.add(3); k.add(8); k.add(11); k.add(20); k.add(50); Optional
      
        max = k.parallelStream().max((a,b) -> {return a-b;}); System.out.println(max); }
      
     
    


很简单吧。就是将k.stream() 改成 k.parallelStream()


而这个之所以简单是基于这样几点。

1. 编写ThreadSafe的函数或者lamda表达式, 本身就很容易变为多线程操作。

2. Stream方式处理数据。

3. 传入的参数数据只关系上一步的结果,而不关系其他数据在本步所做操作产生的中间数据。

4. Fork-Join提供了很好的多线程框架


这里八卦一下Java8 为什么做了除了lamda表达式之外的一些事情。

1. interface中的default function接口。 原因是lamda表达式是为了并发做的。那么并发包concurrent中已经有了很多接口,希望和过去的版本兼容,减少迁移的工作量。如果interface中新增了接口,那么使用jdk8以前的代码就会有编译错误。要解决这个编译错误,要么抽象出一个abstract class实现接口,并加入缺省的实现。要么在以前的所有的实现中都加入这个接口。所以听听就觉得这次迁移是个大的工作量。那default function就诞生了。为了不写abstract class, 并且使用jdk5,jdk6,jdk7的代码可以方便迁移到jdk8中。default function 这样使用:

public class TestF {
	public  interface TestDefault {
		default void print(){
			System.out.println("ew2we");
			
		}
	}
	public static void main(String[] args) {
		// 写个匿名类
		new TestDefault(){}.print();
	}
}


另外值得注意的一点就是:如果有两个interface实现了同名的default function. 那编译会报错。


2. SAM (single abstract method) 也就是这个Annotation @FunctionalInterface. 如果带上这个Annotation,那么这个接口仅且只有一个未实现的方法。当然可以有多个已经实现的default 方法。这个是为了lamda表达式做的。lamda表达式是形如: (param list)-> {code statements;} ,基本上可以看作是一个函数。所以要求仅且只有一个函数方法没有实现就是为了代码好看。@FunctionalInterface 写法如下:

@FunctionalInterface
public interface DefaultInterface {
    default void hello() {
        System.out.println("hello");
    }
    default void zzz() {
        System.out.println("zzz");
    }
    void z(); // 只有一个未实现的函数
}



3. Stream 是为了更好的使用Fork-Join框架。Stream就是pipeline. 对于只关心输入和输出的API来说。编写Stream方式的代码非常容易实现并发。其实就是把一组相似的数据丢到一个池中,然后线程池针对这些数据开始做事情。在执行完毕之前,需要join所有的线程,将最终结果放入到最终返回的池中并返回。而流式的操作最简单的就是调用方便。可以理解为以前所说的链式调用。但是对于这种编写代码的Style,还是尽量将每次调用写在不同的行中,这样会方便调试。下面是Stream的例子:

public static void main(String[] args) {
		
		List
    
      k = new ArrayList
     
      (); k.add(1); k.add(2); k.add(3); k.add(8); k.add(11); k.add(20); k.add(50); // 找到list中大于2的三个数,不要求顺序,最后打印出来 k.parallelStream().filter((a)->{return a>2;}).unordered().limit(3).forEach((a) -> {System.out.println(a);}); // 获取大于1的list元素中的最大值。如果list中的元素都不大于1,那么返回Optional.empty Optional
      
        max = k.parallelStream().filter((a)->{return a>1;}).max((a,b) -> {return a-b;}); System.out.println(max); }
      
     
    


这里简单介绍一下lamda表达式中语法。 这个lamda表达式就是实现了一个抽象方法。所以需要注意那个抽象方法到底是不是void返回,这关系到你的表达式中是否有return.lamda的语法是前面是参数列表,0个参数或者多于一个参数时必须使用圆括号括起。如果只有一个参数,那么可以省略圆括号。然后是一个箭头->。 再后面是函数体。函数体需要使用花括号括起,如果只有一条语句,可以省略花括号。下面的lamda表达式都是对的。

a -> return a+1;
(a) -> return a+1;
(a) -> {return a+1;}
(a,b) -> {int c = a+b; return c>>1;}
()->System.out.println("empty");


另外注意一下final 变量和this指针。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class TestLamba {
	
	public static class Score {
		int score;
		public List
    
      findLarger(List
     
       scores) { List
      
        tmp = new ArrayList
       
        (); //注意这里的this是 Score Object的this scores.stream().filter((a) -> {return a > this.score;}).forEach((a)->{tmp.add(a);}); return tmp; } public static List
        
          findLarger(List
         
           scores, Sc