《Jakarta Commons cookbook读书笔记》系列文章
3.5 Iterator的扩展
3.5.1 循环迭代器LoopingIterator
import org.apache.commons.collections.iterators.LoopingIterator; List books=new ArrayList(); books.add("EnglishBook"); books.add("Commons Cookbook"); books.add("Who Moved My Cheese"); //当迭代到最后的元素后,再返回第一个元素重新循环,直至达到迭代次数为止 LoopingIterator iterator=new LoopingIterator(books); for(int i=0;i<5;i++){ String book=(String)iterator.next(); System.out.print(book+";"); } ->EnglishBook;Commons Cookbook;Who Moved My Cheese;EnglishBook;Commons Cookbook;
3.5.2 ArrayList迭代器ArrayListIterator
可以自定义范围地遍历
import org.apache.commons.collections.iterators.ArrayListIterator; String[] arrays=new String[]{"a","b","c","d","f"}; //遍历下标为1到4的元素 Iterator iterator=new ArrayListIterator(arrays,1,4); while(iterator.hasNext()){ System.out.print(iterator.next()+"; "); } ->b; c; d;
3.5.3 筛选迭代器FilterIterator
使用Predicate筛选,关于Predicate的介绍,请看我的这系列的上一篇文章Jakarta Commons Cookbook读书笔记--Commons Collections(函子篇)
import org.apache.commons.collections.iterators.FilterIterator; import org.apache.commons.collections.Predicate; List list=new ArrayList(Arrays.asList(new Integer[]{7,9,35,67,88})); //过滤出大于30的元素 Predicate predicate=new Predicate(){ public boolean evaluate(Object object){ int num=((Integer)object).intValue(); return num>30; } }; Iterator iterator=new FilterIterator(list.iterator(),predicate); while(iterator.hasNext()){ System.out.print(iterator.next()+"; "); } ->35; 67; 88;
3.5.4 过滤重复的元素UniqueFilterIterator
List list=new ArrayList(Arrays.asList(new String[]{"a","b","c","b","a"})); Iterator iterator=new UniqueFilterIterator(list.iterator()); while(iterator.hasNext()){ System.out.print(iterator.next()+"; "); } ->a; b; c;
3.6 使用Bag
Bag是这样的一种容器,它能够存储多个逻辑相等(即equals()为true,而且hash()相等)的元素,并可以统计它们的个数。
3.6.1 高性能的HashBag
import org.apache.commons.collections.bag.HashBag; Bag bag1=new HashBag(); bag1.add("book1",10); bag1.add("book2",20); Bag bag2=new HashBag(); bag2.add("book2",5); bag2.add("book3",10); bag1.add("book1"); bag1.remove("book1",2); //减去bag2内相应元素的数量 bag1.removeAll(bag2); System.out.println("book1: "+bag1.getCount("book1")); System.out.println("book2: "+bag1.getCount("book2")+"\n"); //bag1保留bag2内的元素,简单来说就是求交集 bag1.retainAll(bag2); System.out.println("book1: "+bag1.getCount("book1")); System.out.println("book2: "+bag1.getCount("book2")); System.out.println("book3: "+bag1.getCount("book3")); -> book1: 9 book2: 15 book1: 0 book2: 5 book3: 0
3.6.2 TreeBag可以保存加入元素的顺序
import org.apache.commons.collections.bag.TreeBag; Bag bag1=new TreeBag(); bag1.add("book1",2); bag1.add("book2",1); bag1.add("book3",2); bag1.add("book4",1); bag1.add("book5",1); Iterator iterator=bag1.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } -> book1 book1 book2 book3 book3 book4 book5
HashBag内部原理是使用一个HashMap当作内部容器,key为加入的对象,对应的value是对象的次数。同理TreeBag使用TreeMap作为内部容器。
需要注意的是虽然Bag继承了Collection,但是它的removeAll(),containsAll(),add(),remove()和retainAll()方法并不严格遵循Collection接口的规范。例如removeAll方法根据规范是移除所有的元素,而Bag的removeAll是带参数的,只移除参数包含的元素。
3.7 用于临时数据转移的Buffer
Buffer类似于java5.0中的Queue,是个先进先出(First-in First-out)的数据容器。
3.7.1 无尺寸缓冲区UnboundFifoBuffer和有尺寸缓冲区BoundedFifoBuffer
import org.apache.commons.collections.buffer.BoundedFifoBuffer; Buffer bBuffer=new BoundedFifoBuffer(2); bBuffer.add("book1"); bBuffer.add("book2"); try{ bBuffer.add("book3"); }catch(BufferOverflowException e){ System.out.println("Buffer is over flow"); } //移除第一个加入的元素 bBuffer.remove(); Iterator iterator=bBuffer.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } -> Buffer is over flow book2
import org.apache.commons.collections.buffer.UnboundedFifoBuffer; Buffer bBuffer=new UnboundedFifoBuffer(2); bBuffer.add("book1"); bBuffer.add("book2"); try{ bBuffer.add("book3"); }catch(BufferOverflowException e){ System.out.println("Buffer is over flow"); } //移除第一个加入的元素 bBuffer.remove(); Iterator iterator=bBuffer.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } -> book2 book3
3.7.2 带优先级的缓冲区PriorityBuffer
按照数值从小到大排列
import org.apache.commons.collections.buffer.PriorityBuffer; Buffer pBuffer=new PriorityBuffer(); pBuffer.add(new Long(2)); pBuffer.add(new Long(20)); pBuffer.add(new Long(12)); pBuffer.add(new Long(4)); Iterator iterator=pBuffer.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } -> 2 4 12 20
PriorityBuffer允许使用Comparator来排列优先顺序,关于Comparator,请看我的这系列的上一篇文章Jakarta Commons Cookbook读书笔记--Commons Collections(函子篇)
//按照销售数量从大到小排列
import java.util.Comparator; public class RecommandComparator implements Comparator { public int compare(Object o1, Object o2) { int result=-1; if(o1 instanceof Book && o2 instanceof Book){ Book book1=(Book)o1; Book book2=(Book)o2; result=book1.getSalsNum().compareTo(book2.getSalsNum()); } return result; } }
import org.apache.commons.collections.comparators.ReverseComparator; import org.apache.commons.collections.buffer.PriorityBuffer; Buffer pBuffer=new PriorityBuffer(new ReverseComparator(new RecommandComparator())); pBuffer.add(new Book("book1",Long.valueOf(200))); pBuffer.add(new Book("book2",Long.valueOf(7200))); pBuffer.add(new Book("book3",Long.valueOf(163))); pBuffer.add(new Book("book4",Long.valueOf(569))); Iterator iterator=pBuffer.iterator(); while(iterator.hasNext()){ Book book=(Book)iterator.next(); System.out.println(book.getName()+":"+book.getSalsNum()); } -> book2:7200 book4:569 book3:163 book1:200
3.7.3 使用阻塞式缓冲区BlockingBuffer
BlokingBuffer装饰一个Buffer实例,并使其处于阻塞状态,只要有对象加入则马上处理。当一个进程调用以BlockingBuffer的get()和remove()方法时,将不返回任何值,直到它有一个对象返回。
import org.apache.commons.collections.Buffer; public class BufferListener implements Runnable{ private Buffer buffer; public BufferListener(Buffer buffer){ this.buffer=buffer; } public void run() { while(true){ String msg=(String)buffer.remove(); System.out.println(msg); } } }
import org.apache.commons.collections.buffer.BlockingBuffer; Buffer buffer=BlockingBuffer.decorate(new UnboundedFifoBuffer()); BufferListener listener=new BufferListener(buffer); Thread listenerThread=new Thread(listener); listenerThread.start(); buffer.add("book1"); buffer.add("book2"); -> book1 book2
3.8 Map的扩展
3.8.1 使用MultiMap实现一键存储多个值
MultiValueMap会使用一个ArrayList来保存同一个键的所有值
import org.apache.commons.collections.MultiMap; import org.apache.commons.collections.map.MultiValueMap; MultiMap map=new MultiValueMap(); map.put("key", "value1"); map.put("key", "value2"); map.put("key", "value2"); System.out.println((Collection)map.get("key")); ->[value1, value2, value2]
3.8.2 使用BidiMap实现根据值检索键
DualHashBidiMap使用两个HashMap来保存键值对,其中一个正常保存键值对,另一个反过来保
存值对应的键。
import org.apache.commons.collections.BidiMap; import org.apache.commons.collections.bidimap.DualHashBidiMap; BidiMap map=new DualHashBidiMap(); map.put("key1", "value"); System.out.println(map.get("key1")); System.out.println(map.inverseBidiMap().get("value")); -> value key1
DualTreeBidiMap是可以记住加入顺序的BidiMap,其内部使用TreeMap来保存键值对。
3.8.3 大小写不敏感的CaseInsensitiveMap
import org.apache.commons.collections.map.CaseInsensitiveMap; CaseInsensitiveMap map=new CaseInsensitiveMap(); map.put("KEY", "value");. map.put("key", "value2"); System.out.println(map.get("key")); ->value2
3.8.4 指定键和值类型(JDK1.4或以下版本)
如果你使用JDK1.4或以下的版本,你如果需要指定键或值的类型,可以使用TypeMap来装饰。
import org.apache.commons.collections.map.TypedMap; Map map=TypedMap.decorate(new HashMap(), String.class, String.class); map.put("key", "value"); //加入非指定的类型会抛出IllegalArgumentException,程序会停止运行 map.put("key2", new Integer(12));
3.8.5 限制加入Map的键或值
import org.apache.commons.collections.map.PredicatedMap; //只允许实例类型是String Predicate stringOnly=new InstanceofPredicate(String.class); Map map=PredicatedMap.decorate(new HashMap(), stringOnly, stringOnly); //如果加入的键或值不符合条件,会抛出IllegalArgumentException,程序会 停止运行 map.put("key2", new Integer(12));
3.8.6 根据键自动生成值的Map
import org.apache.commons.collections.map.LazyMap; Transformer upperFirstLetter=new Transformer(){ public Object transform(Object object){ String name=(String)object; String result=name; if(name!=null&&!"".equals(name)){ result=name.substring(0,1).toUpperCase() +name.substring(1); } return result; } }; Map map=LazyMap.decorate(new HashMap(), upperFirstLetter); System.out.println(map.get("heis")); ->Heis