Jakarta Commons 笔记,Part II
Chapter #05: Collections
java.util.*部分的UML类图:![]()
关于遍历。LoopingIterator, ArrayListIterator, ResettableIterator。对于数组(非collections),有 ArrayIterator,ObjectArrayIterator。
关于遍历collection时有条件的筛选。FilterIterator+Predicate:
Iterator it = new FilterIterator(sampleCollection.iterator, new XxxPredicate());
while (it.hasNext()) { …… }
基于上述条件对collections进行操作:
CollectionUtils.filter(sampleCollection, new XxxPredicate())
这会改变sampleCollection的内容
相关的一些方法有:CollectionUtils.select, CollectionUtils.selectRejected
遍历时跳过重复,使用:UniqueFilterIterator
commons-collection 提供了 Bag 的概念。它着重于 有多少个 某件这一概念。
interface org.apache.commons.collections.Bag 继续了 java.util.Collection,本身有 HashBag 和 TreeBag 的实现。但是它的 removeAll, containsAll, add, remove, retainAll 方法不严格遵循 Collection 的约定。
关于 org.apache.commons.collections.Buffer,已在 Java5 里由 java.util.Queue 基本取代
但是我没发现有 BoundedFifoBuffer 的类似实现
创建优先队列,PriortyBuffer/PriorityQueue,两者都是带上一个 Comparator 。
“阻塞式”是一个比较有意思的概念,作用是有活了马上开始干。见代码:
public class Blocking implements Runnable { // Queue queue = new LinkedBlockingDeque(); Buffer queue = BlockingBuffer.decorate(new BoundedFifoBuffer()); @SuppressWarnings({ "static-access", "unchecked" }) public static void main(String[] args) throws InterruptedException { Blocking ths = new Blocking(); Thread t = new Thread(ths); t.start(); ths.queue.add("Hello"); t.sleep(500); ths.queue.add("Black Lee"); } public void run() { while (true) { try { String msg = (String) queue.remove(); System.out.println(msg); } catch (Exception e) { } } } }
中间注释掉的那行,也是可以使用的。
MultiMap,同一个键存多个值,不觉得这有神马用途。。我会把这多个值放在List里面去,再塞进Map。
BidiMap,比较有意思。可以通过键访问值,也可通过值访问键:DualHashBidiMap, DualTreeBidiMap, TreeBidiMap。(书上说只有这三个实现,我一看JavaDoc,有10来个实现。。)
CaseInsensitiveMap可以让用String作为键的Map不关心大小写。
书中介绍的特定类型的Collection可以不看,Java5的泛型已搞定。
限制Map的值:Map map = PredicatedMap.decorate(new HashMap(), keyPredicate, valuePredicate).
限制List的值:List list = PredicatedList.decorate(new ArrayList(), objectPredicate);
类似的限制:PredicatedCollection, PredicatedSet…
转换Collection里面的所有元素:
CollectionUtils.transform(sampleCollection, new org.apache.commons.collections.Transformer());复杂点的话,用ChainedTransformer完成。
LRU缓存(Least Recently Used)最近最少使用:Map map = new LRUMap(5);
LazyMap是个很强大的工具:Map map = LazyMap.decorate(sampleMap, new Transformer()),在取值时,若key不存在,Transformer会根据key去取值,然后再返回。
统计Collection中对象的出现次数
CollectionUtils.countMatches(sampleCollection, new Predicate()),它用Predicate去统计。
集合间操作
CollectionUtils.union(a, b):A+B
CollectionUtils.intersecion(a, b):A且B
CollectionUtils.disjunction(a, b):(A+B)-(A且B)
CollectionUtils.subtraction(a, b):A-B
MapUtils中的autobox:
Map map = new HashMap(); int j = MapUtils.getIntValue(map, "a"); System.out.println(j); int i = map.get("a"); System.out.println(i);
结果:j=0,取i时抛空指针异常
Chapter #06 XML
这一章不想看太多,只想把简单的XML读和写搞定就了事,毕竟这仅仅是个工具而已。
读取用disgest封装到对象:
xml文件内容:
<users> <user id="1"> <name>Black Lee</name> </user> <user id="2"> <name>Master</name> </user> </users>
对方的Java类:
public class User { private int id; private String name; public User() {} public User(int i, String s) { id = i; name = s; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString() { return "User#" + id + ", Name:" + name; } }
再整一个描述文件:
<digester -rules> <pattern value="users/user"> <object -create-rule classname="xml.User"/> <set -next-rule methodname="add" paramtype="java.lang.Object"/> <set -properties-rule/> <bean -property-setter-rule pattern="name"/> </pattern> </digester>
最后是Java读取类:
public static void main(String[] args) throws IOException, SAXException { List users = new ArrayList(); DigesterDemo demo = new DigesterDemo(); URL rule = demo.getClass().getResource("./rule.xml"); Digester digester = DigesterLoader.createDigester(rule); digester.push(users); InputStream xml = demo.getClass().getResourceAsStream("./users.xml"); Object root = digester.parse(xml); System.out.println(root); System.out.println(users.get(0)); }
运行结果:
[User#1, Name:Black Lee, User#2, Name:Master]
User#1, Name:Black Lee
至于书里还介绍的,怎么处理命名空间的那些,就不操练了。
写回去,用的是commons-betwixt。
给User.java旁边加一个文件,user.betwixt:
<info primitiveType="attribute"> <element name="user"> <attribute name="id" property="id"/> <adddefaults /> </element> </info>
写回去的Java代码:
public static void main(String[] args) throws IOException, SAXException, IntrospectionException { User u1 = new User(1, "Black Lee"); User u2 = new User(2, "Master"); BeanWriter writer = new BeanWriter(); writer.enablePrettyPrint(); BindingConfiguration cfg = new BindingConfiguration(); cfg.setMapIDs(false); writer.setBindingConfiguration(cfg); List users = new ArrayList(); users.add(u1); users.add(u2); writer.write("users", users); // 指定root node的名称 writer.flush(); System.out.println(writer.toString()); }
控制台输出:
<users>
<user id="1">
<name>Black Lee</name>
</user>
<user id="2">
<name>Master</name>
</user>
</users>
org.apache.commons.betwixt.io.BeanWriter@1430b5cChapter#07 应用程序基础设施
- 处理命令行输入,用 Commons CLI(Command Line Interface),主要用CommandLineParser。
- 处理配置文件,用Commons Configuration,晕,现在这一块好像都交给Spring做了,自己已经很少写了,略过。
- 处理日志都交给Log4j,也不用管太多了,log4j.properties基本是一份通用,只不过有时候需要指定不同的输出而已,而且现在也是多用文件来存储,JDBCAppender似乎极少使用。
Chapter#08 Math
这一章讲的,多是数学计算类的,通读了一遍,感觉平常会用到的非常少,大致的记在脑子里就是了。
不过这个《估计程序的剩余处理时间》还是比较有趣的。用的是org.apache.commons.lang.time.StopMatch+org.apache.commons.math.stat.multivariate.SimpleRegression联合处理。
Chapter#08 模板
其实主要是介绍Velocity和FreeMarker的,这两个的应用场景大多是代替JSP成为视图层的解决方案。
VM我没用过,FM倒是用了相当一段时间,不过书里也没介绍得很深入,毕竟那需要更多的章节。略过。
Chapter#09 I/O与网络
大概是看到后面,想记录的东西就越来越少了。
- 关于从Input到Output的操作,用CopyUtils.copy方法。或者用FileUtils.copyFile(src, dest),及FileUtils.xxxxxxToFile()方法。
- 关于各个对象的close操作,用IOUtils.closeQuietly方法,只是觉得这个方法挺怪的,它接收InputStream/OutputStream/Reader/Writer四个类型的对象作为参数,直接把参数换成Closeable不是更好?这个方法要是换成closeAllQuietly(Closeable…tobeClosed)的话,还能多行变一行,更简洁。
- FileUtils.byteCountToDisplaySize方法有点类似于linux下的“ls -lh”,不过没那个强大,不会输出小数点。
- 删除目录:FileUtils.deleteDirectory,清除目录:FileUtils.clearDirectory,目录大小:FileUtils.sizeOfDirectory
- 文件touch操作(没用过),FileUtils.touch(File f)
- 选择文件:File.listFiles方法接收FileFilter和FilenameFilter,commons-io提供了这几个Filter:SuffixFileFilter,PrefixFileFilter,NameFileFilter,DirectoryFileFilter,还可以用(And/Or/Not)FileFilter来组合前述的各个Filter。这些Filter都是org.apache.commons.io.filefilter.IOFileFilter的实现,这个类实现了java.io.FileFilter和java.io.FilenameFilter这两个接口。
- 计算流量:Counting(Input/Output)Stream提供的getCount方法。
- 用new TeeOutputStream(output1, output2).write(xxx)来实现同时输出两份。
- 更牛逼的FileFilenameFilter:new GlobFilenameFilter(“*.xml”),new Perl5FilenameFilter(“regex”)。
- 网络相关的:FTPClient,SMTPClient,POP3Client。
Chapter#11 HTTP和WebDAV
HttpClient平常用得很多,几个点过一遍,没什么好记的。
整了一个Google登录的代码,有点儿小奇怪,在注释掉的setFollowRedirects(true)那里,不注释的话会抛异常。。
public static void googleLogin(HttpClient client, NameValuePair[] nvps) throws IOException, HttpException { String uri = "https://www.google.com/accounts/ServiceLoginAuth"; HttpMethod method = new PostMethod(uri); for (int i = 0; i < nvps.length; i++) { NameValuePair nvp = nvps[i]; if (nvp.getName().equalsIgnoreCase("email")) nvp.setValue("xxxxxx@gmail.com"); if (nvp.getName().equalsIgnoreCase("passwd")) nvp.setValue("xxxxxx"); } method.setQueryString(nvps); // method.setFollowRedirects(true);// 应该是Post请求不能直接进行重定向 int status = client.executeMethod(method); System.out.println(status); if (status == 302) { Header loc = method.getResponseHeader("location"); System.out.println(loc); method.releaseConnection(); method = new GetMethod(loc.getValue()); method.setFollowRedirects(true); status = client.executeMethod(method); System.out.println("Goto: " + loc.getValue() + ", Get:" + status); System.out.println(method.getResponseBodyAsString()); } if (status == 200) System.out.println(method.getResponseBodyAsString()); } public static NameValuePair[] googleGetLoginPage(HttpClient client) throws IOException, HttpException, Exception { String uri = "https://www.google.com/accounts/ServiceLoginAuth"; HttpMethod method = new GetMethod(uri); int status = client.executeMethod(method); System.out.println(status); HttpState state = client.getState(); Cookie[] cookies = state.getCookies(); for (Cookie cookie : cookies) { System.out.println("Set-Cookie: " + cookie.getName() + "\t" + cookie.getValue()); } Header[] headers = method.getResponseHeaders(); for (Header header : headers) { System.out.println("Header: " + header.getName() + "\t" + header.getValue()); } HtmlCleaner cleaner = new HtmlCleaner(); TagNode html = cleaner.clean(method.getResponseBodyAsStream()); TagNode form = (TagNode) (html.evaluateXPath("//form[@id='gaia_loginform']")[0]); Object[] objs = form.evaluateXPath("//input"); NameValuePair[] nvps = new NameValuePair[objs.length]; for (int i = 0; i < objs.length; i++) { TagNode node = (TagNode) objs[i]; nvps[i] = new NameValuePair(node.getAttributeByName("name"), node.getAttributeByName("value")); } return nvps; }
日志打印出来,后续其实有两次重定向:
[DEBUG] header - >> "POST /accounts/ServiceLoginAuth?dsh=7609767927588628425&GALX=ldpKR85s3P0&Email=xxxxxx%40gmail.com&Passwd=xxxxx&PersistentCookie=yes&rmShown=1&signIn=Sign+in&asts= HTTP/1.1[\r][\n]" [DEBUG] header - >> "User-Agent: Jakarta Commons-HttpClient/3.1[\r][\n]" [DEBUG] header - >> "Host: www.google.com[\r][\n]" [DEBUG] header - >> "Cookie: $Version=0; GALX=ldpKR85s3P0; $Path=/accounts[\r][\n]" [DEBUG] header - >> "Content-Length: 0[\r][\n]" [DEBUG] header - >> "[\r][\n]" [DEBUG] header - << "HTTP/1.1 302 Moved Temporarily[\r][\n]" [DEBUG] header - << "HTTP/1.1 302 Moved Temporarily[\r][\n]" [DEBUG] header - << "Content-Type: text/html; charset=UTF-8[\r][\n]"
具体的路径是
1), POST /accounts/ServiceLoginAuth,这个是首次登录提交时POST的用户名密码等
2), GET /accounts/CheckCookie?chtml=LoginDoneHtml
3), GET m/accounts/ManageAccount
想了想,错误会发生,应该是POST请求不能直接重定向。
WebDAV没用过,书上介绍的也太过简陋,略过。。。
Chapter#12 搜索和筛选
用JXPath筛选Collection里的Java对象,这个蛮新鲜,不过有XPath的基础,表象看起来挺简单的:
String xpath = "someObject/sampleList[name='wtf']";
跟取xml的xpath没什么两样。
这本书看完了。
| anyShare分享到: | |
| |