标签:
前不久听一大神讲课,期间提到Iterator,别看它方法简单,可是组装起来就像“数据加工厂”一样!
next()获得序列中的下一个元素。
hasNext()检查序列中是否还有元素。
remove()将迭代器新返回的元素删除。
数据加工厂主要用到的是next()和hasNext()这两个方法,拿下面这个问题来说
<问题>
linux下有很多对文本进行操作的命令,比如cat filename 可以将文件的所有内容输出到控制台上。
grep keyword filename可以将文件内容中包含keyword的行内容输出到控制台上。
wc -l filename可以统计filename文件中的行数。
|是代表管道的意思,管道左边命令的结果作为管道右边命令的输入,比如cat filename | grep exception | wc -l,可以用来统计一个文件中exception出现的行数。
请实现一个功能,可以解析一个linux命令(只包含上面三个命令和上面提到的参数以及和管道一起完成的组合,其它情况不考虑),比如下面这几个例子:
cat xx.txt
cat xx.txt | grep xml
wc -l xx.txt
cat xx.txt | grep xml | wc --l
</问题>
上面这个问题是要对一个数据源进行几种不同的处理,
第一种思路大致如下:
首先把输入的命令分割成单个的命令,然后根据命令的功能编写处理数据的功能模块,遍历命令列表,对数据处理,将结果记录,作为下一个命令的传入参数,直到所有命令执行完毕。
优点:灵活性不错,各种命令可以很方便地组合成不同的功能,扩展性也很好,需要增加新的命令的时候只需要编写新的功能模块就行了,执行的主流程几乎不用修改。
缺点:需要留存中间结果,也就是说当数据源过大的时候就无能为力了,另外,如果处理数据的中途出现意外,那么即使你已经完成绝大部分工作,到最后还是什么结果也不会得到。
第二种思路:流水线工厂,使用Iterator的特点来实现:(hasNext()判断是否有下一条数据,next()取出下一条数据,下面提到的每个Iterator都将反复用到这两个方法)
首先,将数据源(上面的问题里是文件)构造成Iterator;1
然后对每个命令编写各自的迭代器构造函数,各自实现hasNext和next,传入参数为Iterator,返回为Iterator;2
接着,根据输入的命令来拼接每个Iterator,得到最终的结果result(同样是Iterator);3
最后,输出result。4
上面的操作步骤中,123都没有对数据源进行任何操作,只是构造出了一套处理逻辑,最后的第4步看似是输出结果,其实在这一步里面数据才被加工。
优点:包含第一种思路的所有优点,而且第一种思路的缺点也得到解决,数据源任意大(因为内存里面永远只有当前正在处理的一行),而且即使中途出现问题,出现问题之前的正常数据也会得到正常的处理并且输出。
缺点:需要一直占用数据源的read句柄,其实占用的时间虽然比上一种方法长,也长不了多少
第一种方法占用的时间为:数据长度*(一次io时间 + 做一次处理的时间)
第二种方法占用的时间为:数据长度*(一次io时间 + 做多次处理的时间)
一般来说io时间是远大于处理时间的,因此占用时间其实是长不了多少的。
下面看第二种方法的代码:
主流程,根据命令构造一套处理逻辑
//result用于记录最后一个迭代器 Iterator<String> result = null; for (String command : commands) { List<String> args = splitter.omitEmptyStrings().splitToList(command); if (result == null) { //第一次执行的时候,result为空,需要对源文件进行处理得到源文件的迭代器 result = new FileIterator(new File(args.get(args.size() - 1))); } //根据命令名对相应的迭代器进行初始化 result = commandMap.getObject(args.get(0)).init(args, result); } return result; //构造文件迭代器FileIterator private BufferedReader reader; private String line = null; public FileIterator(File file) throws FileNotFoundException { reader = Files.newReader(file, Charsets.UTF_8); } @Override public boolean hasNext() { try { line = (line == null) ? reader.readLine() : line; } catch (IOException e) { LOGGER.error("readLine() error", e); } if (line == null) { IOHandler.closeIgnoreException(reader); } return line != null; } @Override public String next() { try { String temp = (line == null) ? reader.readLine() : line; line = null; if(temp == null){ IOHandler.closeIgnoreException(reader); } return temp; } catch (IOException e) { LOGGER.error("readLine() error", e); } return null; } //Grep命令的迭代器(其他的差不多,就不贴了) private String filter; private String line = null; private void getLine() { String temp; while (line == null) { if (!parent.hasNext()) { break; } temp = parent.next(); if (temp.contains(filter)) { line = temp; break; } } } @Override public boolean hasNext() { getLine(); return line != null; } @Override public String next() { getLine(); String result = line; line = null; return result; } @Override public Iterator<String> init(List<String> args, Iterator<String> parent) { this.parent = parent; filter = args.get(1); return this; }
注:上面的代码都只是一部分,只是方便参看的,想照贴的就算了吧。
标签:
原文地址:http://www.cnblogs.com/just84/p/4805386.html