Read Sean

Read me, read Sean.
posts - 508, comments - 655, trackbacks - 9, articles - 4


今天发现,博客园cnblogs的各博客主页可以通过二级域名的方式访问了,如:

http://sean.cnblogs.com/

什么时候BlogJava也能提供该多好!

posted @ 2005-08-09 15:18 laogao 阅读(548) | 评论 (3)编辑 收藏

 

最近看到BlogJava上有人在讨论为什么Java范型不支持数组http://www.blogjava.net/myqiao/archive/2005/08/08/9580.html

 

我想这个问题的答案是:因为这样做会破坏类型安全。核心的问题在于Java范型和C#范型存在根本区别:Java的范型停留在编译这一层,到了运行时,这些范型的信息其实是被抹掉的;而C#的范型做到了MSIL这一层。Java的做法不必修改JVM,减少了潜在的大幅改动和随之而来的风险,也许同时也反映出Java Bytecode规范在设计之初的先天不足;C#则大刀阔斧,连CLR一起改以支持更彻底的范型,换句话说,在范型这一点上,感觉C#C++一点。

 

Java中,Object[]数组可以是任何数组的父类,或者说,任何一个数组都可以向上转型成它在定义时指定元素类型的父类的数组,这个时候如果我们往里面放不同于原始数据类型 但是满足后来使用的父类类型的话,编译不会有问题,但是在运行时会检查加入数组的对象的类型,于是会抛ArrayStoreException

 

String[] strArray = new String[20];

Object[] objArray = strArray;

objArray[0] = new Integer(1); // throws ArrayStoreException at runtime

 

因为Java的范型会在编译后将类型信息抹掉,这样如果Java允许我们使用类似

 

Map<Integer, String>[] mapArray = new Map<Integer, String>[20];

 

这样的语句的话,我们在随后的代码中可以把它转型为Object[]然后往里面放Map<Double, String>实例。这样做不但编译器不能发现类型错误,就连运行时的数组存储检查对它也无能为力,它能看到的是我们往里面放Map的对象,我们定义的<Integer, String>在这个时候已经被抹掉了,于是而对它而言,只要是Map,都是合法的。想想看,我们本来定义的是装Map<Integer, String>的数组,结果我们却可以往里面放任何Map,接下来如果有代码试图按原有的定义去取值,后果是什么不言自明。

 

所以,Java编译器不允许我们new范型数组。

 

 

posted @ 2005-08-09 09:36 laogao 阅读(5149) | 评论 (3)编辑 收藏

 

在前面的随笔中,我们一起过了一遍Jakarta Commons这个类库中非常重要的三个子项目:Commons LangCommons BeanUtilsCommons Collections,这些工具包在无数开源或商业框架中都可以找到,可以说应用范围非常广。

 

当然,Jakarta Commons提供的API远不止我们提到的这些,除了上述三个核心项目之外,还有读取和映射XML文档的Digester/Betwixt、处理命令行参数的CLI、提供常用编码算法的Codec、用于读取多种格式的配置文件的Configuration、发送电子邮件的Email、上传文件的FileUpload、模拟HTTP客户端的HttpClient、处理日志的Logging等等等等,实在是相当的丰富。

 

Jakarta Commons官网上可以找到完整的组件列表:

http://jakarta.apache.org/commons/

 

今后如果发现特别有价值需要跟大家分享的,我还会贴出来,只是不会像这样有条理和规律了。希望我的这一组笔记对大家了解和认识Jakarta Commons有所帮助,也希望这些优秀的类库及其源码能够给大家带来工作效率和编程功底上的提升。

 

我整理了一份清单,列出了所有这一系列随笔的链接,方便大家查找和阅读:

http://www.blogjava.net/sean/articles/Jakarta_Commons_Notes.html

 

 

posted @ 2005-08-06 12:56 laogao 阅读(1676) | 评论 (1)编辑 收藏

 

来看最后一组 – Iterator

 

LoopingIterator

ArrayListIterator

FilterIterator

UniqueFilterIterator

IteratorUtils

 

java.util.Iterator接口定义了标准的Collection遍历方法,但是如果不做改变的使用它,我们得到的是从头到尾一次性的遍历。假如我们需要循环遍历,假如我们需要遍历某一段,假如我们需要遍历满足某些条件的元素,等等等等,我们就不能完全依赖于这个Iterator的标准实现了。除非我们宁可在此基础上在调用的代码中多加一些判断,不过这样的话代码就会显得混乱,时间长了就容易变得难以维护。Commons Collections的这一组Iterator为我们带来了便利。

 

这些Iterator使用都很一目了然,直接看例子吧:

 

package sean.study.commons.collections;

 

import java.util.Arrays;

import java.util.Iterator;

import java.util.List;

 

import org.apache.commons.collections.Predicate;

import org.apache.commons.collections.iterators.ArrayListIterator;

import org.apache.commons.collections.iterators.FilterIterator;

import org.apache.commons.collections.iterators.LoopingIterator;

import org.apache.commons.lang.StringUtils;

 

public class IteratorUsage {

 

    public static void main(String[] args) {

        demoIteratorUsage();

    }

   

    public static void demoIteratorUsage() {

 

        System.out.println(StringUtils.center(" demoClosureUsage ", 40, "="));

       

        // data setup

        String[] weekDays = {

            "Monday", "Tuesday", "Wednesday",

            "Thursday", "Friday", "Saturday", "Sunday"

        };

        List weekDayList = Arrays.asList(weekDays);

       

        // workdays

        Iterator iter1 = new ArrayListIterator(weekDays, 0, 5);

        printColl("Partial:", iter1, 5);

       

        // loop

        Iterator iter2 = new LoopingIterator(weekDayList);

        printColl("Loop:", iter2, 10);

       

        // looping workdays

        Predicate notWeekendPredicate = new Predicate() {

            public boolean evaluate(Object obj) {

                String str = (String) obj;

                if ("Saturday".equalsIgnoreCase(str)) {

                    return false;

                }

                if ("Sunday".equalsIgnoreCase(str)) {

                    return false;

                }

                return true;

            }

        };

        Iterator iter3 = new FilterIterator(

            new LoopingIterator(weekDayList),

            notWeekendPredicate

        );

        printColl("No Weekends loop:", iter3, 12);

       

        System.out.println(StringUtils.repeat("=", 40));

 

    }

   

    public static void printColl(String label, Iterator iter, int maxCount) {

        if (StringUtils.isNotBlank(label)) {

            System.out.println(label);

        }

        int i = 0;

        while (iter.hasNext() && i < maxCount) {

            System.out.println("# " + iter.next() + " #");

            i++;

        }

    }

 

}

 

运行结果如下:

 

=========== demoClosureUsage ===========

Partial:

# Monday #

# Tuesday #

# Wednesday #

# Thursday #

# Friday #

Loop:

# Monday #

# Tuesday #

# Wednesday #

# Thursday #

# Friday #

# Saturday #

# Sunday #

# Monday #

# Tuesday #

# Wednesday #

No Weekends loop:

# Monday #

# Tuesday #

# Wednesday #

# Thursday #

# Friday #

# Monday #

# Tuesday #

# Wednesday #

# Thursday #

# Friday #

# Monday #

# Tuesday #

========================================

 

有了这些实用的Iterator类,我们就可以轻松的实现可配置的遍历行为了。

 

 

posted @ 2005-08-06 12:47 laogao 阅读(1844) | 评论 (0)编辑 收藏

 

接下来看Closure组。

 

Closure

ChainedClosure

IfClosure

WhileClosure

ClosureUtils

 

Closure这一组接口和类提供一个操作对象的execute方法,为我们在处理一系列对象时可以将处理逻辑分离出来。理论上讲,使用Transformer也可以达到类似的效果,只要输出对象和输入对象是同一个对象就好,但是Closure接口定义的execute方法返回void,并且从效果和功能区分上,Closure可以更好的诠释对象处理或执行的意思。而事实上,ClosureUtils中也提供了一个asClosure方法包装一个现成的Transformer

 

沿用前面的Emploee类,我们来给一组员工涨工资:

 

package sean.study.commons.collections;

 

import java.util.Arrays;

import java.util.Collection;

import java.util.Date;

import java.util.Iterator;

 

import org.apache.commons.collections.Closure;

import org.apache.commons.collections.CollectionUtils;

import org.apache.commons.lang.StringUtils;

 

public class ClosureUsage {

 

    public static void main(String[] args) {

        demoClosureUsage();

    }

   

    public static void demoClosureUsage() {

 

        System.out.println(StringUtils.center(" demoClosureUsage ", 40, "="));

       

        // data setup

        Employee[] employees = new Employee[] {

            new Employee("Tony", 26, new Date(), "E4", 2000),

            new Employee("Michelle", 24, new Date(), "E4", 2000),

            new Employee("Jack", 28, new Date(), "E5", 3000)

        };

        Collection empColl = Arrays.asList(employees);

        printColl("Before salary increase:", empColl);

       

        // closure setup

        Closure salaryIncreaseClosure = new Closure() {

            public void execute(Object obj) {

                Employee emp = (Employee) obj;

                emp.setSalary(emp.getSalary() * 1.20);

            }

        };

       

        // salary increase

        CollectionUtils.forAllDo(empColl, salaryIncreaseClosure);

        printColl("After salary increase:", empColl);

 

        System.out.println(StringUtils.repeat("=", 40));

    }

   

    public static void printColl(String label, Collection c) {

        if (StringUtils.isNotBlank(label)) {

            System.out.println(label);

        }

        Iterator iter = c.iterator();

        while (iter.hasNext()) {

            System.out.println(iter.next());

        }

    }

}

 

以下是运行结果:

 

=========== demoClosureUsage ===========

Before salary increase:

Employee[name=Tony,age=26,dateJoined=2005-08-05,grade=E4,salary=2000.0]

Employee[name=Michelle,age=24,dateJoined=2005-08-05,grade=E4,salary=2000.0]

Employee[name=Jack,age=28,dateJoined=2005-08-05,grade=E5,salary=3000.0]

After salary increase:

Employee[name=Tony,age=26,dateJoined=2005-08-05,grade=E4,salary=2400.0]

Employee[name=Michelle,age=24,dateJoined=2005-08-05,grade=E4,salary=2400.0]

Employee[name=Jack,age=28,dateJoined=2005-08-05,grade=E5,salary=3600.0]

========================================

 

我这里举的是一个相对简单的例子,在Closure这一组还有一些很方便的类,如ChainedClosure可以包装一组Closure作为整体执行;IfClosure在创建时需要提供给它一个Predicate和两个Closure,执行时先做Predicate判定再决定执行哪一个ClosureSwitchClosureSwitchTransformer类似,根据创建时传入的Predicate组和Closure组对应执行;WhileClosure则根据创建时传入的Predicate做判断,如果为true则执行Closure,直到Predicate返回false;等等。

 

具体用法请参考Javadoc

 

 

posted @ 2005-08-06 12:31 laogao 阅读(2134) | 评论 (1)编辑 收藏

     摘要:   接下来看Transformer组。   Transformer ChainedTransformer SwitchTransformer TransformerUtils   我们有时候需要将某个对象转换成另一个对象供另一组方法调用,而这两类对象的类型有可能并不是出于同一个继承体系的,或者说出了很基本的Object之外没有共同的父类,或者我们根本不...  阅读全文

posted @ 2005-08-06 10:40 laogao 阅读(2648) | 评论 (1)编辑 收藏

 

接下来看Predicate

 

Predicate

AndPredicate

OrPredicate

AllPredicate

OnePredicate

NonePredicate

PredicateUtils

 

PredicateCommons Collections中定义的一个接口,可以在org.apache.commons.collections包中找到。其中定义的方法签名如下:

 

public boolean evaluate(Object object)

 

它以一个Object对象为参数,处理后返回一个boolean值,检验某个对象是否满足某个条件。其实这个Predicate以及上一篇笔记提到的Comparator还有我们即将看到的TransformerClosure等都有些类似C/C++中的函数指针,它们都只是提供简单而明确定义的函数功能而已。

 

跟其他组类似,Commons Collections也提供了一组定义好的Predicate类供我们使用,这些类都放在org.apache.commons.collections.functors包中。当然,我们也可以自定义Predicate,只要实现这个Predicate接口即可。在Commons Collections中我们也可以很方便使用的一组预定义复合Predicate,我们提供2个或不定数量个Predicate,然后交给它,它可以帮我们处理额外的逻辑,如AndPredicate处理两个Predicate,只有当两者都返回true它才返回trueAnyPredicate处理多个Predicate,当其中一个满足就返回true,等等。

 

看看具体的代码中如何使用这些Predicate吧:

 

package sean.study.commons.collections;

 

import org.apache.commons.collections.Predicate;

import org.apache.commons.collections.PredicateUtils;

import org.apache.commons.collections.functors.InstanceofPredicate;

import org.apache.commons.collections.functors.NotNullPredicate;

import org.apache.commons.lang.BooleanUtils;

import org.apache.commons.lang.StringUtils;

 

public class PredicateUsage {

 

    public static void main(String[] args) {

        demoPredicates();

    }

   

    public static void demoPredicates() {

        System.out.println(StringUtils.center(" demoPredicates ", 40, "="));

        Predicate p1 = new InstanceofPredicate(String.class);

        Predicate p2 = NotNullPredicate.getInstance();

        Predicate p3 = new Predicate() {

            public boolean evaluate(Object obj) {

                String str = (String) obj;

                return StringUtils.isAlphanumeric(str)

                    && str.length() >= 6

                    && str.length() <= 10;

            }

        };

        Predicate p4 = PredicateUtils.allPredicate(new Predicate[]{p1, p2, p3});                String input = "ABCD1234";

        Object[] raw = new Object[] {

            "Is '",

            input,

            "' a valid input? ",

            BooleanUtils.toStringYesNo(p4.evaluate(input)),

            "."

        };

        System.out.println(StringUtils.join(raw));

        System.out.println(StringUtils.repeat("=", 40));

    }

 

}

 

输出结果如下:

 

============ demoPredicates ============

Is 'ABCD1234' a valid input? yes.

========================================

 

这里面我首先定义了3个简单的Predicatep1判断对象是否为String的实例,p2判断是否对象为nullp3是自定义的,判断是否为数字字母的组合,并且长度在6~10字符。然后我用AllPredicate将它们组合到一起,成为p4,当p1p2p3都满足时,p4evaluate方法才返回true。利用Predicate我们可以把判断truefalse的逻辑从特定的业务代码分离出来,以后我们重用也好,重新组装也好,都是很方便的。

 

posted @ 2005-08-06 08:43 laogao 阅读(3392) | 评论 (4)编辑 收藏

     摘要:   接下来我们会讲到辅助类,首先看Comparator组。   ReverseComparator ComparatorChain NullComparator FixedOrderComparator ComparatorUtils   其实Comparator这个概念并不是Commons Collections引入的,在标准的Java Colle...  阅读全文

posted @ 2005-08-06 08:40 laogao 阅读(2753) | 评论 (4)编辑 收藏

 

接下来看看Collection组。

 

TypedCollection

CollectionUtils

 

首先就是这个TypedCollection,它实际上的作用就是提供一个decorate方法,我们传进去一个Collection和需要的类型甄别信息java.lang.Class,它给我们创建一个全新的强类型的Collection。我们其实在bagbufferlistmapset这些子包中都可以找到分别对应BagBufferListMapSet接口的TypedXxxx版本。

 

方法签名:

public static Collection decorate(Collection coll, Class type)

 

当它执行时,它会判断coll是否为null,同时如果coll包含数据,它会对数据进行验证,看是否满足指定的type条件。最后它返回一个强类型的Collection,当我们对这个强类型的Collection进行add操作时,它会帮我们确保添加的是正确的类型。

 

而这个CollectionUtils可能大家都已经想到了,就是提供一组针对Collection操作的工具/静态方法。比较有意思的是对Collection的转型、合并、减等操作。

 

由于这两个类的功能和作用都比较清晰,我就不举例说明了,需要进一步了解的请看Javadoc

 

 

posted @ 2005-08-05 12:48 laogao 阅读(2150) | 评论 (0)编辑 收藏

 

接下来看Map组。

 

BidiMap

MultiMap

LazyMap

MapUtils

 

Commons Collectionsjava.util.Map的基础上扩展了很多接口和类,比较有代表性的是BidiMapMultiMapLazyMap。跟BagBuffer类似,Commons Collections也提供了一个MapUtils

 

所谓BidiMap,直译就是双向Map,可以通过key找到value,也可以通过value找到key,这在我们日常的代码-名称匹配的时候很方便:因为我们除了需要通过代码找到名称之外,往往也需要处理用户输入的名称,然后获取其代码。需要注意的是BidiMap当中不光key不能重复,value也不可以。

 

所谓MultiMap,就是说一个key不在是简单的指向一个对象,而是一组对象,add()remove()的时候跟普通的Map无异,只是在get()时返回一个Collection,利用MultiMap,我们就可以很方便的往一个key上放数量不定的对象,也就实现了一对多。

 

所谓LazyMap,意思就是这个Map中的键/值对一开始并不存在,当被调用到时才创建,这样的解释初听上去是不是有点不可思议?这样的LazyMap有用吗?我们这样来理解:我们需要一个Map,但是由于创建成员的方法很“重”(比如数据库访问),或者我们只有在调用get()时才知道如何创建,或者Map中出现的可能性很多很多,我们无法在get()之前添加所有可能出现的键/值对,或者任何其它解释得通的原因,我们觉得没有必要去初始化一个Map而又希望它可以在必要时自动处理数据生成的话,LazyMap就变得很有用了。

 

我们还是通过一个具体的例子来说明:

 

package sean.study.commons.collections;

 

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

 

import org.apache.commons.collections.BidiMap;

import org.apache.commons.collections.Factory;

import org.apache.commons.collections.MultiHashMap;

import org.apache.commons.collections.MultiMap;

import org.apache.commons.collections.bidimap.DualHashBidiMap;

import org.apache.commons.collections.map.LazyMap;

import org.apache.commons.lang.StringUtils;

 

public class MapUsage {

 

    public static void main(String[] args) {

        demoBidiMap();

        demoMultiMap();

        demoLazyMap();

    }

 

    public static void demoBidiMap() {

        System.out.println(StringUtils.center(" demoBidiMap ", 40, "="));

        BidiMap bidiMap = new DualHashBidiMap();

        bidiMap.put("BJ", "Beijing");

        bidiMap.put("SH", "Shanghai");

        bidiMap.put("GZ", "Guangzhou");

        bidiMap.put("CD", "Chengdu");

        System.out.println("Key-Value: BJ = " + bidiMap.get("BJ"));

        System.out.println("Value-Key: Chengdu = " + bidiMap.getKey("Chengdu"));

        System.out.println(StringUtils.repeat("=", 40));

    }

 

    public static void demoMultiMap() {

        System.out.println(StringUtils.center(" demoMultiMap ", 40, "="));

        MultiMap multiMap = new MultiHashMap();

        multiMap.put("Sean", "C/C++");

        multiMap.put("Sean", "OO");

        multiMap.put("Sean", "Java");

        multiMap.put("Sean", ".NET");

        multiMap.remove("Sean", "C/C++");

        System.out.println("Sean's skill set: " + multiMap.get("Sean"));

        System.out.println(StringUtils.repeat("=", 40));

    }

 

    public static void demoLazyMap() {

        System.out.println(StringUtils.center(" demoLazyMap ", 40, "="));

        // borrowed from Commons Collection's Javadoc

        Factory factory = new Factory() {

            public Object create() {

                return new Date();

            }

        };

        Map lazy = LazyMap.decorate(new HashMap(), factory);

        System.out.println(lazy.get("NOW"));

        System.out.println(StringUtils.repeat("=", 40));

    }

 

}

 

以下是运行结果:

 

============= demoBidiMap ==============

Key-Value: BJ = Beijing

Value-Key: Chengdu = CD

========================================

============= demoMultiMap =============

Sean's skill set: [OO, Java, .NET]

========================================

============= demoLazyMap ==============

Wed Aug 03 12:44:56 CST 2005

========================================

 

简单说一下这个Factory,它是定义在org.apache.commons.collections包下面的一个接口,用于自定义对象的创建过程。这个有点像是后面我们要讲的Transformer的简化版本,但是也更直接也很好用,至少Commons Collections通过它向开发人员开放了一个可以方便控制对象创建细节的接口。

 

 

posted @ 2005-08-05 12:23 laogao 阅读(4047) | 评论 (0)编辑 收藏

 

来看Buffer组。

 

Buffer

BlockingBuffer

BoundedFifoBuffer

PriorityBuffer

UnboundedFifoBuffer

BufferUtils

 

Buffer是定义在org.apache.commons.collections包下面的接口,用于表示按一定顺序除去成员对象的collection如队列等。具体的实现类在org.apache.commons.collections.buffer包下可以找到。

 

BufferUtils提供很多静态/工具方法装饰现有的Buffer实例,如将其装饰成BlockingBuffer、执行类型检查的TypedBuffer、或者不可改变的UnmodifiableBuffer等等。

 

最简单直接的Buffer实现类是UnboundedFifoBuffer,提供先进先出的大小可变的队列。而BoundedFifoBuffer则是对其大小进行了限制,是固定大小的先进先出队列。BlockingBuffer要在多线程的环境中才能体现出它的价值,尤其是当我们需要实现某种流水线时这个BlockingBuffer很有用:每个流水线上的组件从上游的BlockingBuffer获取数据,处理后放到下一个BlockingBuffer中依次传递。BlockingBuffer的核心特色通俗点说就是如果你向它要东西,而它暂时还没有的话,你可以一直等待直至拿到为止。PriorityBuffer则提供比一般的先进先出Buffer更强的控制力:我们可以自定义Comparator给它,告诉它怎么判定它的成员的先后顺序,优先级最高的最先走。

 

为了方便和清晰的需要,我在这里只举一个BoundedFifoBuffer,包装成TypedBuffer,看看在具体的代码中通常如何使用Buffer:(还是沿用上次的Book类)

 

package sean.study.commons.collections;

 

import java.util.Iterator;

 

import org.apache.commons.collections.Buffer;

import org.apache.commons.collections.BufferUtils;

import org.apache.commons.collections.buffer.BoundedFifoBuffer;

import org.apache.commons.lang.StringUtils;

 

public class BufferUsage {

 

    public static void main(String[] args) {

        demoBufferUsage();

    }

 

    public static void demoBufferUsage() {

 

        System.out.println(StringUtils.center(" demoBagUsage ", 40, "="));

 

        // data setup

        Book book1 = new Book("Refactoring Workbook", "7-5083-2208-8", 29.8);

        Book book2 = new Book("J2EE Design Patterns", "7-5083-3099-4", 45);

        Book book3 = new Book("Agile Software Development", "7-5083-1503-0", 59);

        Book book4 = new Book("Professional JSP", "7-5053-8005-2", 100);

 

        // create a Buffer

        Buffer buffer =

            BufferUtils.typedBuffer(new BoundedFifoBuffer(3), Book.class);

        buffer.add(book1);

        buffer.add(book2);

        buffer.add(book3);

        Book removed = (Book) buffer.remove();

        System.out.println("Removed:");

        System.out.println(removed);

        buffer.add(book4);

       

        // get items in buffer

        for (int i = 0; i < 3; i++) {

            System.out.println(buffer.get());

            buffer.remove();

        }

 

        System.out.println(StringUtils.repeat("=", 40));

 

    }

 

}

 

以下是运行结果:

 

============= demoBagUsage =============

Removed:

sean.study.commons.collections.Book@e09713[

  name=Refactoring Workbook

  ISBN=7-5083-2208-8

  retailPrice=29.8

]

Remaining:

sean.study.commons.collections.Book@e09713[

  name=J2EE Design Patterns

  ISBN=7-5083-3099-4

  retailPrice=45.0

]

sean.study.commons.collections.Book@47b480[

  name=Agile Software Development

  ISBN=7-5083-1503-0

  retailPrice=59.0

]

sean.study.commons.collections.Book@19b49e6[

  name=Professional JSP

  ISBN=7-5053-8005-2

  retailPrice=100.0

]

========================================

 

我们可以看到,Bufferaddremove方法分别添加新成员和删除最先加入的成员。由于我们的Buffer定义为只能装3Book类的实例,所以不论我们试图加入其他类型的对象,或者加入超过3个,操作都将失败。如果我们在遍历时使用get()而不调用remove(),那么我们将得到3个相同的拷贝,而这正是我们期望的FIFO队列的行为。假如你需要遍历并保留数据,可以使用标准的Iterator机制。

 

 

posted @ 2005-08-04 12:49 laogao 阅读(2047) | 评论 (0)编辑 收藏

 

首先来看Bag组。

 

Bag

HashBag

BagUtils

 

Bag是在org.apache.commons.collections包中定义的接口,它extends java.util.Collection,而它的实现类都被放在下面的bag包中。之所以有这样一组类型,是因为我们有时候需要在Collection中存放多个相同对象的拷贝,并且需要很方便的取得该对象拷贝的个数。需要注意的一点是它虽然extends Collection,但是如果真把它完全当作java.util.Collection来用会遇到语义上的问题,详细信息参考Javadoc

 

HashBagBag接口的一个标准实现。而BagUtils提供一组static的方法让调用者获取经过不同装饰后的Bag实例。

 

还是举例子来看:

 

/** Book.java */

 

package sean.study.commons.collections;

 

import org.apache.commons.lang.builder.ToStringBuilder;

import org.apache.commons.lang.builder.ToStringStyle;

 

public class Book {

   

    private String name;

    private String isbn;

    private double retailPrice;

   

    public Book() {

    }

   

    public Book(String name, String isbn, double retailPrice) {

        this.name = name;

        this.isbn = isbn;

        this.retailPrice = retailPrice;

    }

   

    public String toString() {

        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)

        .append("name", name)

        .append("ISBN", isbn)

        .append("retailPrice", retailPrice)

        .toString();

    }

 

    public String getIsbn() {

        return isbn;

    }

 

    public void setIsbn(String isbn) {

        this.isbn = isbn;

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public double getRetailPrice() {

        return retailPrice;

    }

 

    public void setRetailPrice(double retailPrice) {

        this.retailPrice = retailPrice;

    }

   

}

 

/** BagUsage.java */

 

package sean.study.commons.collections;

 

import org.apache.commons.collections.Bag;

import org.apache.commons.collections.BagUtils;

import org.apache.commons.collections.bag.HashBag;

import org.apache.commons.lang.StringUtils;

 

public class BagUsage {

 

    public static void main(String[] args) {

        demoBagUsage();

    }

 

    public static void demoBagUsage() {

 

        System.out.println(StringUtils.center(" demoBagUsage ", 40, "="));

 

        // data setup

        Book book1 = new Book("Refactoring Workbook", "7-5083-2208-8", 29.8);

        Book book2 = new Book("J2EE Design Patterns", "7-5083-3099-4", 45);

        Book book3 = new Book("Agile Software Development", "7-5083-1503-0", 59);

 

        // create a bag

        Bag myBag = BagUtils.typedBag(new HashBag(), Book.class);

        myBag.add(book1, 360);

        myBag.add(book2, 500);

        myBag.add(book3, 170);

 

        // calculations for a bag

        double price1 = book1.getRetailPrice();

        double price2 = book2.getRetailPrice();

        double price3 = book3.getRetailPrice();

        int book1Count = myBag.getCount(book1);

        int book2Count = myBag.getCount(book2);

        int book3Count = myBag.getCount(book3);

        double totalValue = (price1 * book1Count) + (price2 * book2Count)

                + (price3 * book3Count);

 

        // dispaly results

        System.out.println("There are " + book1Count + " copies of "

                + book1.getName() + ".");

        System.out.println("There are " + book2Count + " copies of "

                + book2.getName() + ".");

        System.out.println("There are " + book3Count + " copies of "

                + book3.getName() + ".");

        System.out.println("The total value of these books is: " + totalValue);

 

        System.out.println();

 

    }

 

}

 

以下是运行结果:

 

============= demoBagUsage =============

There are 360 copies of Refactoring Workbook.

There are 500 copies of J2EE Design Patterns.

There are 170 copies of Agile Software Development.

The total value of these books is: 43258.0

 

需要说明的是,以上的代码仅仅为了演示如何使用Bag,实际应用不建议像这样硬编码。

 

 

posted @ 2005-08-03 12:36 laogao 阅读(2598) | 评论 (2)编辑 收藏

 

Commons Collections,又是一个重量级的东西,为Java标准的Collections API提供了相当好的补充。我不知道其他人,就我自己而言,让我用java.util.Collection及其子类,加上java.util.Collections类提供的操作方法,处理一些简单的数据结构问题还可以,稍微复杂一点的就觉得有点头痛,很多细节的地方需要我插入这样那样的小逻辑,或者感觉它太死板,不够灵活,再或者确实有点晦涩吧。再说了,如果我只是处理一般的数据结构问题,为什么不自己用数组或者自定义的链表来做,再加上Jakarta CommonsLang提供的ArrayUtilsStringUtils等,已经基本够了,性能可以保证,那么还要这个Collections API干嘛。当然,说到这里有些偏激了,Collections当然有它存在的道理,能够把常用的数据结构归纳起来,以通用的方式去维护和访问,这应该说是一种进步,但是用起来似乎不够友好。这个时候我就会想,如果Java比现在做得更好用些,或者有一套第三方的API把我的这些需求抽象出来,实现了,该多好。Commons Collections就是这样一套API

 

在这里可以找到下载链接:(binarysrc都有)

http://jakarta.apache.org/site/downloads/downloads_commons-collections.cgi

 

目前Commons Collection发布的最新版本是3.1。建议下载这个3.1版本,页面上出现的2.1.1是针对2.1不兼容3.0而发布的升级维护版。

 

我们先来浏览一下它的包结构。一共是12个:

 

org.apache.commons.collections – Commons Collections自定义的一组公用的接口和工具类

org.apache.commons.collections.bag – 实现Bag接口的一组类

org.apache.commons.collections.bidimap – 实现BidiMap系列接口的一组类

org.apache.commons.collections.buffer – 实现Buffer接口的一组类

org.apache.commons.collections.collection – 实现java.util.Collection接口的一组类

org.apache.commons.collections.comparators – 实现java.util.Comparator接口的一组类

org.apache.commons.collections.functors – Commons Collections自定义的一组功能类

org.apache.commons.collections.iterators – 实现java.util.Iterator接口的一组类

org.apache.commons.collections.keyvalue – 实现集合和键/值映射相关的一组类

org.apache.commons.collections.list – 实现java.util.List接口的一组类

org.apache.commons.collections.map – 实现Map系列接口的一组类

org.apache.commons.collections.set – 实现Set系列接口的一组类

 

用过Java Collections API的朋友大概或多或少会同意我如下的划分:在JavaCollections API中,不狭义的区分语法上的接口和类,把它们都看作是类的话,大致我们可以发现三种主要的类别:

 

1- 容器类:如CollectionListMap等,用于存放对象和进行简单操作的;

2- 操作类:如CollectionsArrays等,用于对容器类的实例进行相对复杂操作如排序等;

3- 辅助类:如IteratorComparator等,用于辅助操作类以及外部调用代码实现对容器类的操作,所谓辅助,概括而通俗的来讲,就是这些类提供一种算法,你给它一个对象或者一组对象,或者仅仅是按一定的规则调用它,它给你一个运算后的答案,帮助你正确处理容器对象。比如Iterator会告诉你容器中下一个对象有没有、是什么,而Comparator将对象大小/先后次序的算法逻辑独立出来。

 

同样,Jakarta Commons Collections我们细细看来,也能够找出类似的划分:

 

1- 作为容器类的补充,我们可以找到BagBufferBidiMapOrderedMap等等;

2- 作为操作类的补充,我们可以找到CollectionUtilsIteratorUtilsListUtilsSetUtils等等;

3- 作为辅助类的补充,我们可以找到MapIteratorClosurePredicateTransformer等等;

 

对于这样的一个大包,当然不可能一个类一个类的讲了,找一些常用的和有用的当做接下来讨论的话题吧。大概列个清单:

 

Bag

HashBag

BagUtils

 

Buffer

BlockingBuffer

BoundedFifoBuffer

PriorityBuffer

BufferUtils

 

MultiMap

BidiMap

CaseInsensitiveMap

LazyMap

MapUtils

 

TypedCollection

CollectionUtils

 

ReverseComparator

ComparatorChain

NullComparator

FixedOrderComparator

ComparatorUtils

 

Predicate

AndPredicate

OrPredicate

AllPredicate

OnePredicate

NonePredicate

PredicateUtils

 

Transformer

ChainedTransformer

SwitchTransformer

TransformerUtils

 

Closure

ChainedClosure

IfClosure

WhileClosure

ClosureUtils

 

LoopingIterator

ArrayListIterator

FilterIterator

UniqueFilterIterator

IteratorUtils

 

总共9组,在接下来的笔记中我们一起慢慢的看。

 

 

posted @ 2005-08-03 09:07 laogao 阅读(3324) | 评论 (1)编辑 收藏

     摘要:   假定我们有如下两个标准的JavaBean:   /** Address.java */   package sean.study.commons.beanutils;   public class Address {       private String zipCode;  &nb...  阅读全文

posted @ 2005-08-02 17:57 laogao 阅读(3336) | 评论 (1)编辑 收藏

 

Jakarta Commons项目提供了相当丰富的API,我们之前了解到的Commons Lang只是众多API的比较核心的一小部分而已。Commons下面还有相当数量的子项目,用于解决各种各样不同方向的实际问题,BeanUtils就是其中的一个,用于处理JavaBeans。它利用Java的反射机制,从动态的生成对beangettersetter的调用代码,到模拟创建一个动态的bean,等等。这个包看似简单,却是很多开源项目的基石:如在著名的StrutsSpring Framework中,我们都能找到BeanUtils的影子。大家猜猜看,有哪位名人是BeanUtils的作者之一?没错,就是Struts的创始人Craig McClanahan

 

BeanUtils最核心的好处在于:我们在编码时,并不需要知道我们处理的JavaBeans具体是什么类型,有哪些属性,这些信息是可以动态获取的,甚至我们都可以不必去关心事实上是否存在这样一个具体的JavaBean类。我们只需要知道有一个JavaBean的实例,我们需要从中取得某个属性,设定某个属性的值,或者仅仅是需要一个属性表。要做到这些,依靠Sun提供的JavaBean规范似乎找不到一个很直接的方式,除非硬编码,将getXxxx()setXxxx()直接写进我们的程序。但是这样就大大增加了代码的复杂度、耦合性和维护成本。还好Commons BeanUtils对这个问题提供了一种优雅的解决方案。

 

我们有两种途径获取Commons BeanUtilsbinary

1- StrutsSpring或者任何依赖BeanUtils的开源产品的发行包中找到相应的jar文件;

2- http://www.apache.org/dist/jakarta/commons/beanutils/binaries/下载。

 

Commons BeanUtils的源码下载地址:

http://www.apache.org/dist/jakarta/commons/beanutils/source/

 

Commons BeanUtils一共包括如下5个包:

 

org.apache.commons.beanutils – 核心包,定义一组Utils类和需要用到的接口规范

org.apache.commons.beanutils.converters – 转换String到需要类型的类,实现Converter接口

org.apache.commons.beanutils.locale – beanutilslocale敏感版本

org.apache.commons.beanutils.locale.converters – converterslocale敏感版本

org.apache.commons.collections – beanutils使用到的Collection

 

其中需要我们特别关注的是这个org.apache.commons.beanutils包,其他包都是起辅助作用的。接下来我们就仔细看一看这个包都有些什么东东:

 

[4个接口]

 

Converter

该接口定义了如下方法:

public java.lang.Object convert(java.lang.Class type, java.lang.Object value);

只要实现了这个Converter接口并注册到ConvertUtils类即可被我们的BeanUtils包所使用,它的主要目的是提供将给定的Object实例转换为目标类型的算法。我们可以在beanutils.converters包中找到相当多的已经实现的转换器。

 

DynaBean

该接口定义的是一个动态的JavaBean,它的属性类型、名称和值都是可以动态改变的。

 

DynaClass

该接口定义的是针对实现了DynaBean接口的类的java.lang.Class对象,提供如getName()newInstance()等方法。

 

MutableDynaClass

该接口是对DynaClass的扩展,使得动态bean的属性可以动态增加或删除。

 

[24个类]

 

BasicDynaBean

DynaBean接口的最精简实现

 

BasicDynaClass

DynaClass接口的最精简实现

 

BeanUtils

提供通过反射机制填写JavaBeans属性的工具/静态方法

 

BeanUtilsBean

BeanUtils类的实例化实现,区别于BeanUtils的静态方法方式,使得自定义的配置得以保持

 

ConstructorUtils

MethodUtils类似,不过专注于构造方法

 

ContextClassLoaderLocal

针对每个classloader的唯一标识

 

ConvertingWrapDynaBean

包含了标准JavaBean实例的DynaBean实现,使得我们可以使用DynaBeanAPI来访问起属性,同时提供设定属性时的类型转换,继承自并区别于WrapDynaBean

 

ConvertUtils

提供工具/静态方法,用于将String对象及其数组转换为指定的类型的对象及其数组。

 

ConvertUtilsBean

ConvertUtils类的实例化实现,区别于ConvertUtils的静态方法方式,使得自定义的配置得以保持

 

DynaProperty

用于描述DynaBean的属性

 

JDBCDynaClass

DynaClassJDBC实现提供公用的逻辑

 

LazyDynaBean

懒载入DynaBean,自动往DynaClass添加属性并提供懒载入List和懒载入Map的功能

 

LazyDynaClass

实现MutableDynaClass接口的类

 

LazyDynaMap

Map实例提供一个轻量级的DynaBean包装

 

MappedPropertyDescriptor

用于描述映射的属性

 

MethodUtils

包含了针对一般意义上的方法而非特定属性的反射工具/静态方法

 

MethodUtils.MethodDescriptor

描述通过反射查找某个方法所使用的键值

 

PropertyUtils

提供利用Java反射API调用具体对象的gettersetter的工具/静态方法

 

PropertyUtilsBean

PropertyUtils类的实例化实现,区别于PropertyUtils的静态方法方式,使得自定义的配置得以保持

 

ResultSetDynaClass

包装java.sql.ResultSet中的java.sql.Row实例的DynaBean所对应的DynaClass实现

 

ResultSetIterator

针对ResultSetDynaClassjava.util.Iterator实现

 

RowSetDynaClass

DynaClass的一种实现,用于在内存中创建一组表示SQL查询结果的DynaBeans,区别于ResultSetDynaClass,它不需要保持ResultSet打开

 

WrapDynaBean

DynaBean的一种实现,包含一个标准的JavaBean实例,以便我们可以使用DynaBeanAPI去访问它的属性,区别于ConvertingWrapDynaBean,它不做专门的类型转换

 

WrapDynaClass

DynaClass的一种实现,针对那些包装标准JavaBean实例的DynaBeans

 

[3Exception]

 

(略)

 

看到这么多东西是不是有点头晕?不要慌,看几个例子就明白了。只要把握好BeanUtils本身要完成的事,就不难理解这些类存在的道理。我们不妨把BeanUtils的基础应用分解成:访问JavaBean的属性、设定JavaBean的属性、以及创建和使用DynaBeans。这样来看BeanUtils,你就会觉得简单清晰得多。

 

// 例子将在下一节单独放出。

 

 

posted @ 2005-08-02 12:40 laogao 阅读(5313) | 评论 (3)编辑 收藏

仅列出标题
共34页: First 上一页 24 25 26 27 28 29 30 31 32 下一页 Last