首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

关于LISt Process.

2012-08-22 
关于LISt Process...前2天听了熊老师的一个Session,关于List Process的,差点忘了总结,现记录如下:从一个St

关于LISt Process...
   前2天听了熊老师的一个Session,关于List Process的,差点忘了总结,现记录如下:

从一个Story开始,现需求如下:(注:List中的每个元素都是都是整数)
(1)、给定一个List,把List中的每个元素+1,返回新的List;
(2)、给定一个List,把List中的每个元素*2,返回新的List;
(3)、给定一个List,取出其中的偶数,返回新的List;

以TDD的思维开发,先写Testcase

public class ListProcessTest {    @Test    public void test_every_element_in_list_add_one() throws Exception {        List<Integer> inputList = Arrays.asList(1, 2, 3, 4);        assertThat(ListProcess.addOne(inputList), is(Arrays.asList(2, 3, 4, 5)));    }    @Test    public void test_every_element_in_list_multiply_two() throws Exception {        List<Integer> inputList = Arrays.asList(1, 2, 3, 4);        assertThat(ListProcess.multiplyTwo(inputList), is(Arrays.asList(2, 4, 6, 8)));    }    @Test    public void test_get_even_from_input_list() throws Exception {        List<Integer> inputList = Arrays.asList(1, 2, 3, 4);        assertThat(ListProcess.getEvenList(inputList), is(Arrays.asList(2, 4)));    }}


第一次大家对addOne,multiplyTwo,getEvenList实现如下
public class ListProcess {    public static List<Integer> addOne(List<Integer> inputList) {        List<Integer> result = new ArrayList<Integer>();        for (int input : inputList) {            result.add(input + 1);        }        return result;    }    public static List<Integer> multiplyTwo(List<Integer> inputList) {        List<Integer> result = new ArrayList<Integer>();        for (int input : inputList) {            result.add(input * 2);        }        return result;    }    public static List<Integer> getEvenList(List<Integer> inputList) {        List<Integer> result = new ArrayList<Integer>();        for (int input : inputList) {            if (input % 2 == 0) {                result.add(input);            }        }        return result;    }}
功能完成,测试通过之后,马上就回发现这段代码的Bad Smell,一共才5,6行的函数,居然和其他函数有4句代码是重复的,然后熊老师就开始给我们讲这个Session的主要目的。
   对于List的处理,我们通常可以分为3类
第一类:对List中的每个元素,做同样的处理,得到一个新的集合,即遍历列表,针对每个elment做一元函数Func(x)的映射,因为一一对应,因此可简称为Map操作;
第二类:判断List中的的每个元素是否满足某个条件,对满足条件的元素进行相应的逻辑处理得到新的List。比方说filter,select,reduce等等操作。
第三类:求取集合中所有元素的总值,比方说求和操作,这类操作对于每个元素来说都是一个2元操作,func(init_value,x),即把当前element的值加初始值上。可以简称为Accumulation操作。


   在Google的collections包中就根据这样的思想提供了相应的工具类,改造过后的代码
public class ListProcess {    public static List<Integer> addOne(List<Integer> inputList) {        return Lists.transform(inputList, new Function<Integer, Integer>() {            @Override            public Integer apply(@Nullable Integer integer) {                return ++integer;            }        });    }    public static List<Integer> multiplyTwo(List<Integer> inputList) {        return Lists.transform(inputList, new Function<Integer, Integer>() {            @Override            public Integer apply(@Nullable Integer integer) {                return integer * 2;            }        });    }    public static List<Integer> getEvenList(List<Integer> inputList) {        //注:不知为何,Google Collections没有把Filter也做在Lists里面,而是放到Collections2里面,返回一个Collection<E>,我们不得不自己转成List        List<Integer> result = new ArrayList<Integer>();        result.addAll(                Collections2.filter(inputList, new Predicate<Integer>() {                    @Override                    public boolean apply(@Nullable Integer integer) {                        return integer % 2 == 0;                    }                }));        return result;    }}
这样改完之后有什么好处呢?
第一:代码更直观,我们关注的只是function,predicate中的内容,也就是我们的核心业务逻辑。
第二:可以分布式处理,因为循环的时候CPU需要记录当前处理的元素下标之类的信号量,整个循环的处理过程会绑定在一个CPU上处理,就只能发挥一个CPU的计算能力,多核时代多浪费。如果使用Google的这种方式,就可以把一个很大的List拆分成一个个小的任务,然后并发执行之后再合并回来,也就是Map-Reduce的思想。

最后,熊老师推荐了一本经典书籍<Structure and Interpretation of Computer Programs>(计算机程序的构造和解释),说是看完之后,编程基本功会大大提高。刚加入清单,还没开始读,等读完之后再来写篇读后感。



补:关于为什么不把Filter的功能做到Lists类的原因参见:http://code.google.com/p/guava-libraries/wiki/IdeaGraveyard

热点排行