<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>5Dinfo</title>
<link>http://www.5dinfo.net/blog/</link>
<description>http://www.5dinfo.net/blog/</description>
<copyright>5Dinfo</copyright>
<generator>Ken Wu</generator>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<item>
<title>[转]JVM调优总结 -Xms -Xmx -Xmn -Xss</title>
<description><![CDATA[
收集一些关于虚拟机调优的知识,有些地方有待核实.<br /><br /><p>堆大小设置<br />JVM 中最大堆大小有三方面限制：相关操作系统的数据模型（32-bt还是64-bit）限制；系统的可用虚拟内存限制；系统的可用物理内存限制。32位系统下，一般限制在1.5G~2G；64为操作系统对内存无限制。我在Windows Server 2003 系统，3.5G物理内存，JDK5.0下测试，最大可设置为1478m。<br />典型设置： <br />java -Xmx3550m -Xms3550m -Xmn2g -Xss128k<br />-Xmx3550m：设置JVM最大可用内存为3550M。<br />-Xms3550m：设置JVM促使内存为3550m。此值可以设置与-Xmx相同，以避免每次垃圾回收完成后JVM重新分配内存。<br />-Xmn2g：设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m，所以增大年轻代后，将会减小年老代大小。此值对系统性能影响较大，Sun官方推荐配置为整个堆的3/8。<br />-Xss128k：设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M，以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下，减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的，不能无限生成，经验值在3000~5000左右。</p><p>java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0<br />-XX:NewRatio=4:设置年轻代（包括Eden和两个Survivor区）与年老代的比值（除去持久代）。设置为4，则年轻代与年老代所占比值为1：4，年轻代占整个堆栈的1/5<br />-XX:SurvivorRatio=4：设置年轻代中Eden区与Survivor区的大小比值。设置为4，则两个Survivor区与一个Eden区的比值为2:4，一个Survivor区占整个年轻代的1/6<br />-XX:MaxPermSize=16m:设置持久代大小为16m。<br />-XX:MaxTenuringThreshold=0：设置垃圾最大年龄。如果设置为0的话，则年轻代对象不经过Survivor区，直接进入年老代。对于年老代比较多的应用，可以提高效率。如果将此值设置为一个较大值，则年轻代对象会在Survivor区进行多次复制，这样可以增加对象再年轻代的存活时间，增加在年轻代即被回收的概论。<br />回收器选择<br />JVM给了三种选择：串行收集器、并行收集器、并发收集器，但是串行收集器只适用于小数据量的情况，所以这里的选择主要针对并行收集器和并发收集器。默认情况下，JDK5.0以前都是使用串行收集器，如果想使用其他收集器需要在启动时加入相应参数。JDK5.0以后，JVM会根据当前系统配置进行判断。 <br />吞吐量优先的并行收集器<br />如上文所述，并行收集器主要以到达一定的吞吐量为目标，适用于科学技术和后台处理等。<br />典型配置： <br />java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20<br />-XX:+UseParallelGC：选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下，年轻代使用并发收集，而年老代仍旧使用串行收集。<br />-XX:ParallelGCThreads=20：配置并行收集器的线程数，即：同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。</p><p>java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC<br />-XX:+UseParallelOldGC：配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。</p><p>java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100<br />-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间，如果无法满足此时间，JVM会自动调整年轻代大小，以满足此值。</p><p>java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy<br />-XX:+UseAdaptiveSizePolicy：设置此选项后，并行收集器会自动选择年轻代区大小和相应的Survivor区比例，以达到目标系统规定的最低相应时间或者收集频率等，此值建议使用并行收集器时，一直打开。</p><p>响应时间优先的并发收集器<br />如上文所述，并发收集器主要是保证系统的响应时间，减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等。<br />典型配置： <br />java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC<br />-XX:+UseConcMarkSweepGC：设置年老代为并发收集。测试中配置这个以后，-XX:NewRatio=4的配置失效了，原因不明。所以，此时年轻代大小最好用-Xmn设置。<br />-XX:+UseParNewGC:设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上，JVM会根据系统配置自行设置，所以无需再设置此值。 <br />java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection<br />-XX:CMSFullGCsBeforeCompaction：由于并发收集器不对内存空间进行压缩、整理，所以运行一段时间以后会产生&quot;碎片&quot;，使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。<br />-XX:+UseCMSCompactAtFullCollection：打开对年老代的压缩。可能会影响性能，但是可以消除碎片</p><p>辅助信息<br />JVM提供了大量命令行参数，打印信息，供调试使用。主要有以下一些： <br />-XX:+PrintGC<br />输出形式：[GC 118250K-&gt;113543K(130112K), 0.0094143 secs] <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Full GC 121376K-&gt;10414K(130112K), 0.0650971 secs]</p><p>-XX:+PrintGCDetails<br />输出形式：[GC [DefNew: 8614K-&gt;781K(9088K), 0.0123035 secs] 118250K-&gt;113543K(130112K), 0.0124633 secs] <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [GC [DefNew: 8614K-&gt;8614K(9088K), 0.0000665 secs][Tenured: 112761K-&gt;10414K(121024K), 0.0433488 secs] 121376K-&gt;10414K(130112K), 0.0436268 secs]</p><p>-XX:+PrintGCTimeStamps -XX:+PrintGC：PrintGCTimeStamps可与上面两个混合使用<br />输出形式：11.851: [GC 98328K-&gt;93620K(130112K), 0.0082960 secs]</p><p>-XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前，程序未中断的执行时间。可与上面混合使用<br />输出形式：Application time: 0.5291524 seconds</p><p>-XX:+PrintGCApplicationStoppedTime：打印垃圾回收期间程序暂停的时间。可与上面混合使用<br />输出形式：Total time for which application threads were stopped: 0.0468229 seconds</p><p>-XX:PrintHeapAtGC:打印GC前后的详细堆栈信息<br />输出形式：<br />34.702: [GC {Heap before gc invocations=7:<br />def new generation&nbsp;&nbsp; total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)<br />eden space 49152K, 99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)<br />from space 6144K, 55% used [0x221d0000, 0x22527e10, 0x227d0000)<br />to&nbsp;&nbsp; space 6144K,&nbsp;&nbsp; 0% used [0x21bd0000, 0x21bd0000, 0x221d0000)<br />tenured generation&nbsp;&nbsp; total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)<br />the space 69632K,&nbsp;&nbsp; 3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)<br />compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)<br />&nbsp;&nbsp; the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)<br />&nbsp;&nbsp;&nbsp; ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)<br />&nbsp;&nbsp;&nbsp; rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)<br />34.735: [DefNew: 52568K-&gt;3433K(55296K), 0.0072126 secs] 55264K-&gt;6615K(124928K)Heap after gc invocations=8:<br />def new generation&nbsp;&nbsp; total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)<br />eden space 49152K,&nbsp;&nbsp; 0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)<br />from space 6144K, 55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)<br />to&nbsp;&nbsp; space 6144K,&nbsp;&nbsp; 0% used [0x221d0000, 0x221d0000, 0x227d0000)<br />tenured generation&nbsp;&nbsp; total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)<br />the space 69632K,&nbsp;&nbsp; 4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)<br />compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)<br />&nbsp;&nbsp; the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)<br />&nbsp;&nbsp;&nbsp; ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)<br />&nbsp;&nbsp;&nbsp; rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)<br />}<br />, 0.0757599 secs]</p><p>-Xloggc:filename:与上面几个配合使用，把相关日志信息记录到文件以便分析。<br />常见配置汇总 <br />堆设置 <br />-Xms:初始堆大小 <br />-Xmx:最大堆大小 <br />-XX:NewSize=n:设置年轻代大小 <br />-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3，表示年轻代与年老代比值为1：3，年轻代占整个年轻代年老代和的1/4 <br />-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如：3，表示Eden：Survivor=3：2，一个Survivor区占整个年轻代的1/5 <br />-XX:MaxPermSize=n:设置持久代大小<br />收集器设置 <br />-XX:+UseSerialGC:设置串行收集器 <br />-XX:+UseParallelGC:设置并行收集器 <br />-XX:+UseParalledlOldGC:设置并行年老代收集器 <br />-XX:+UseConcMarkSweepGC:设置并发收集器<br />垃圾回收统计信息 <br />-XX:+PrintGC <br />-XX:+PrintGCDetails <br />-XX:+PrintGCTimeStamps <br />-Xloggc:filename<br />并行收集器设置 <br />-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。 <br />-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间 <br />-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)<br />并发收集器设置 <br />-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。 <br />-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时，使用的CPU数。并行收集线程数。</p><p>四、调优总结 <br />年轻代大小选择 <br />响应时间优先的应用：尽可能设大，直到接近系统的最低响应时间限制（根据实际情况选择）。在此种情况下，年轻代收集发生的频率也是最小的。同时，减少到达年老代的对象。 <br />吞吐量优先的应用：尽可能的设置大，可能到达Gbit的程度。因为对响应时间没有要求，垃圾收集可以并行进行，一般适合8CPU以上的应用。<br />年老代大小选择 <br />响应时间优先的应用：年老代使用并发收集器，所以其大小需要小心设置，一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了，可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式；如果堆大了，则需要较长的收集时间。最优化的方案，一般需要参考以下数据获得： <br />并发垃圾收集信息 <br />持久代并发收集次数 <br />传统GC信息 <br />花在年轻代和年老代回收上的时间比例<br />减少年轻代和年老代花费的时间，一般会提高应用的效率</p><p>吞吐量优先的应用：一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是，这样可以尽可能回收掉大部分短期对象，减少中期的对象，而年老代尽存放长期存活对象。<br />较小堆引起的碎片问题<br />因为年老代的并发收集器使用标记、清除算法，所以不会对堆进行压缩。当收集器回收时，他会把相邻的空间进行合并，这样可以分配给较大的对象。但是，当堆空间较小时，运行一段时间以后，就会出现&quot;碎片&quot;，如果并发收集器找不到足够的空间，那么并发收集器将会停止，然后使用传统的标记、清除方式进行回收。如果出现&quot;碎片&quot;，可能需要进行如下配置： <br />-XX:+UseCMSCompactAtFullCollection：使用并发收集器时，开启对年老代的压缩。 <br />-XX:CMSFullGCsBeforeCompaction=0：上面配置开启的情况下，这里设置多少次Full GC后，对年老代进行压缩<br />&nbsp;</p>
]]></description>
<link>http://www.5dinfo.net/blog/?2009/8/7/1</link>
<guid>http://www.5dinfo.net/blog/?2009/8/7/1</guid>
<category>JAVA</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Fri, 07 Aug 2009 17:39:10 +0800</pubDate>
</item>
<item>
<title>King Forever</title>
<description><![CDATA[
<p><a href="http://5dinfo.net/blog/media/http_imgload.jpg" target="_blank" onclick="return hs.expand(this)"><img src="http://5dinfo.net/blog/media/http_imgload.jpg" border="0" alt="MJJ" title="MJJ" width="480" height="480" /></a></p><p>怀念Michael Jackson.</p><br /><br />
]]></description>
<link>http://www.5dinfo.net/blog/?2009/6/28/1</link>
<guid>http://www.5dinfo.net/blog/?2009/6/28/1</guid>
<category>Diary</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Sun, 28 Jun 2009 14:32:34 +0800</pubDate>
</item>
<item>
<title>Java API Design Guidelines</title>
<description><![CDATA[
<p>&nbsp;<span>Java API Design Guidelines</span><br /><span>by Eamonn McManus</span><br /><span>December 28, 2005</span></p><blockquote><p><strong>Summary</strong></p><p>There are tons of books and articles about how to design and write good Java code, but surprisingly little about the specific topic of API design. Here's a summary of what I've learnt on the subject from various sources and my own experience. </p></blockquote><br /><br /><p>I recently attended an excellent talk at <a href="http://www.javapolis.com/confluence/display/JP05/Home">JavaPolis</a>, <a href="http://www.elharo.com/">Elliotte Rusty Harold's</a> <a href="http://www.cafeconleche.org/slides/javapolis/xom/index.html"><em>XOM Design Principles</em></a>. Although the talk is nominally about XOM (an API for XML documentation manipulation), in fact more than half of it is about API design principles in general. This is a curiously neglected subject. There are tons of books and articles about how to design and write good Java code, but surprisingly little about the specific topic of API design. Yet with the proliferation of new Java APIs, whether through JSRs or through Open Source projects, this is an increasingly important subject.</p><p>I've been closely involved with the evolution of the <a href="http://java.sun.com/jmx/">JMX API</a> for over five years and have learnt a great deal about what works and what doesn't during that time. During the talk, I had the odd experience of continually wanting to cheer as Elliotte made point after point that I hugely agreed with.</p><p>I'm going to try to summarize here what I see as being the key points from this talk, from my own experience, and from a couple of other sources:</p><ul><li>An excellent tutorial on netbeans.org, <a href="http://openide.netbeans.org/tutorial/api-design.html"><em>How to Design a (module) API</em></a>. </li><li>A related NetBeans BOF at JavaOne 2005 by <a href="http://weblogs.java.net/blog/timboudreau/">Tim Boudreau</a> and <a href="http://www.netbeans.org/community/articles/interviews/yarda_tulach.html">Jaroslav Tulach</a>, entitled <a href="http://treefs.netbeans.org/files/documents/39/676/apidesign.sxi"><em>How to write APIs that will stand the test of time</em></a>. </li><li>Of course, Josh Bloch's <a href="http://java.sun.com/docs/books/effective/"><em>Effective Java</em></a> book. </li></ul><p>[<strong>Update:</strong> Although I was unaware of it when writing this blog entry, the <a href="http://lcsd05.cs.tamu.edu/slides/keynote.pdf">slides</a> referenced by Josh Bloch in a comment here cover some of the same ground and add much of interest.]</p><h2>Design to evolve</h2><p>If your API is worth anything, it will evolve over time. You should plan for this from the outset. A key part of the planning is to decide what sort of compatibility you will guarantee between revisions.</p><p>The best approach is to say that <strong>once something is in the API it will stay there</strong> and it will continue to work. Tweaking the API incompatibly between revisions will result in user reactions ranging from annoyance to murderous rage. The problem is particularly severe if your API ends up being used by different modules that are part of the same application. If Module 1 uses Commons Banana 1.0 and Module 2 uses Commons Banana 2.0 then life will be a whole lot easier if 2.0 is completely compatible with 1.0. Otherwise your users risk wasting huge amounts of time tweaking classpaths in a futile endeavour to make things work. They might end up having to play <a href="http://weblogs.java.net/blog/emcmanus/archive/2005/07/dealing_with_mu.html">mind-destroying games with class-loaders</a>, which is a clear signal that you have failed.</p><p>For APIs that are part of <a href="http://java.sun.com/j2se/index.jsp">Java SE</a>, we have an extreme form of compatibility. The aim is that <em>no code whatsoever</em> should break when you update from one version to the next. This means that <strong>classes and methods are never removed</strong>. It also means that we try to avoid changes that might break code that was depending on certain implementation details, even if the code shouldn't have been doing that.</p><p>The no-code-breakage rule applies to already-compiled code (<a href="http://jscstage.sfbay.sun.com/docs/books/jls/third_edition/html/binaryComp.html"><em>binary compatibility</em></a>). In some rare circumstances we might make changes that mean some existing code no longer compiles (<em>source compatibility</em>). For example, adding an overloaded method or constructor can sometimes produce ambiguity errors from the compiler when a parameter is null. We do try to find a way to avoid changes that break source compatibility in this way, but sometimes the best approach does imply that some source code might stop compiling. As an example, in Java SE 6 the <a href="http://download.java.net/jdk6/doc/api/javax/management/StandardMBean.html#StandardMBean%28T,%20java.lang.Class%29">constructors for javax.management.StandardMBean</a> have been generified. Some existing source code might conceivably stop compiling because it does not respect the constraints that are expressed using generics here, but that code is easily fixed by adding a cast, and the rare cases where that happens are outweighed by cases where the constraints will catch programming errors at compile time.</p><p>In general, <strong>you can't know what users of your API will do with it</strong>. When contemplating a change that <em>might</em> break existing code, you have to reason conservatively. Only if you can honestly say that it is next to impossible that a change will break code can you reasonably make it. You should certainly rule out completely a <em>signature change</em>, which basically means removing or renaming a visible method or class or changing the parameters of a visible method. (But you can remove a method if it overrides a method in a parent class without changing the parent method's semantics.)</p><p>Since the very earliest versions of your API are sure to have many mistakes in them, and you don't want to freeze those mistakes for all time, it's a good idea to <strong>bring out one or more 0.x versions</strong> before the 1.0 version. Users of these versions know that the API is unstable and won't curse you if it changes. Once you've brought out 1.0 you're committing to compatibility. For APIs that are developed through the <a href="http://jcp.org/">JCP</a>, these 0.x versions correspond to the phases before the final release (Early Draft Review, Public Review, Proposed Final Draft). If possible, it's a good idea to make an implementation of the API available at the same time as these intermediate specifications.</p><p>If at some stage you decide that there's really too much accumulated cruft from previous versions and you want to start over, then <strong>create a new API with different package names</strong>. Then code that uses the old version and code that uses the new version can co-exist easily.</p><h2>API design goals</h2><p>What should the design goals of your API be? Apart from compatibility, the following goals from Elliotte's presentation seem like an excellent set:</p><ul><li>It must be <strong>absolutely correct</strong>. In the case of XOM, this meant that the API could never produce malformed XML documents no matter what the caller did. For the JMX API, for example, it means that you can never get the MBean Server into an inconsistent state by registering strange MBeans in it or using funny ObjectNames or performing several operations concurrently. </li><li>It must be <strong>easy to use</strong>. This is hard to quantify. A good way to get an idea is to write lots of example code. Are there groups of operations that you keep having to repeat? Do you have to keep looking up your own API because you forget what things are called? Are there cases where the API doesn't do what you might expect? </li><li>It must be <strong>easy to learn</strong>. This overlaps considerably with ease of use. But there are some obvious principles to make learning easier. The smaller the API, the less there is to learn. Documentation should include examples. Where appropriate, the API should look like familiar APIs. </li><li>It must be <strong>fast enough</strong>. Elliotte was careful to put this in the list <em>after</em> the above items. Make sure the API is simple and correct. <em>Then</em> think about performance. You might be inclined to make API changes because the original API could only be implemented in an inefficient way. By all means change it to allow a more efficient implementation, <em>provided</em> you don't compromise correctness or simplicity. Don't rely on your intuition to know what performs well. <em>Measure</em>. Then tweak the API if you've determined that it really matters. </li><li>It must be <strong>small enough</strong>. This covers the size of the compiled code and especially the amount of memory it needs as it runs. The same principles as for speed apply. Make it simple and correct first; measure; and only <em>then</em> think about tweaking the API. </li></ul><h2>Be minimalist</h2><p>Because of the compatibility requirement, <strong>it's much easier to put things in than to take them out</strong>. So don't add anything to the API that you're not sure you need.</p><p>There's an approach to API design which you see depressingly often. Think of everything a user could possibly want to do with the API and add a method for it. Toss in protected methods so users can subclass to tweak every aspect of your implementation. Why is this bad?</p><ul><li><p><strong>The more stuff there is in the API, the harder it is to learn</strong>. Which classes and methods are the important ones? Which of the five different ways to do what I need is the best?</p><p>The situation is exacerbated by the Javadoc tool, which dumps all the classes in a package, and all the methods in a class, in an undifferentiated lump. We can expect that <a href="http://jcp.org/en/jsr/detail?id=260">JSR 260</a> will update the Javadoc tool to allow you to produce &quot;views&quot; of the API, and in that case fatter APIs will not be so overwhelming.</p></li><li><p><strong>The bigger the API, the more things can go wrong</strong>. The implementation isn't going to be perfect, but the same investment in coding and testing will yield better results for a smaller API.</p></li><li><p>If your API has more methods than it needs, then it's <strong>taking up more space than it needs</strong>.</p></li></ul><p>The right approach is to <strong>base the API on example code</strong>. Think of problems a user might want to solve with the API. Add just enough classes and methods to solve those problems. <strong>Code the solutions</strong>. Remove anything from the API that your examples don't need. This allows you to check that the API is useful. As a happy side-effect, it gives you some basic tests. And you can (and should) share the examples with your users.</p><h2>Interfaces are overvalued</h2><p>There's a certain style of API design that's very popular in the Java world, where everything is expressed in terms of Java interfaces (as opposed to classes). Interfaces have their place, but it is basically never a good idea for an entire API to be expressed in terms of them. <strong>A type should only be an interface if you have a good reason for it to be.</strong> Here's why:</p><ul><li><p><strong>Interfaces can be implemented by anybody</strong>. Suppose <a href="http://download.java.net/jdk6/doc/api/java/lang/String.html">String</a> were an interface. Then you could never be sure that a String you got from somewhere obeyed the semantics you expect: it is immutable; its hashCode() is computed in a certain way; its length is never negative; and so on. Code that used String, whether user code or code from the rest of the J2SE platform, would have to go to enormous lengths to ensure it was robust in the face of String implementations that were accidentally incorrect. And to even further lengths to ensure that its security could not be compromised by deliberately evil String implementations.</p><p>In practice, implementations of APIs that are defined entirely in terms of interfaces often end up cheating and casting objects to the non-public implementation class. DOM typically does this for example. So you can't give your own implementation of the <a href="http://download.java.net/jdk6/doc/api/org/w3c/dom/DocumentType.html">DocumentType</a> interface as a parameter to <a href="http://download.java.net/jdk6/doc/api/org/w3c/dom/DOMImplementation.html#createDocument%28java.lang.String,%20java.lang.String,%20org.w3c.dom.DocumentType%29">DOMImplementation.createDocument</a> and expect it to work. Then what's the point in having interfaces?</p></li><li><p><strong>Interfaces cannot have constructors or static methods</strong>. If you need an instance of an interface, you either have to implement it yourself, or you have to ask some other object for it. If <a href="http://download.java.net/jdk6/doc/api/java/lang/Integer.html">Integer</a> were an interface, then to get the Integer for a given int you could no longer use the obvious new Integer(n) (or, less obvious but still documented inside Integer, Integer.valueOf(n)). You would have to use IntegerFactory.newInteger(n) or whatever. This makes your API harder to understand and use.</p></li><li><p><strong>Interfaces cannot evolve</strong>. Suppose you add a new method to an interface in version 2 of your API. Then user code that implemented the interface in version 1 will no longer compile because it doesn't implement the new method. You can still preserve binary compatibility by catching <a href="http://download.java.net/jdk6/doc/api/java/lang/AbstractMethodError.html">AbstractMethodError</a> around calls to the new method but that is clunky. If you use an abstract class instead of an interface you don't have this problem. If you tell users not to implement the interface then you don't have this problem either, but then why is it an interface?</p></li><li><p><strong>Interfaces cannot be serialized</strong>. Java serialization has its problems, but you can't always get away from it. The JMX API relies heavily on serialization, for example. For better or worse, the way serialization works is that the name of the <em>actual implementation class</em> is serialized, and an instance of that exact same class is reconstructed at deserialization. If the implementation class is not a public class in your API, then you won't interoperate with other implementations of your API, and it will be very hard for you to ensure that you even interoperate between different versions of your own implementation. If the implementation class <em>is</em> a public class in your API, then do you really need the interface as well?</p></li></ul><p>Of course, there are sometimes good reasons for a type to be interface. Here are some common ones:</p><ul><li><p><strong>Callbacks</strong>. If the interface is intended to be implemented by user code, then it is often more appropriate than an abstract class. See <a href="http://download.java.net/jdk6/doc/api/java/lang/Runnable.html">Runnable</a> for example. This is mostly true of interfaces with just one method. Once there start being several methods you often find that an implementation class only needs to do something in one of them, and it's annoying to have to implement all the others. Furthermore if an interface has three methods today then you might want it to have four tomorrow, which is not usually possible as we saw. An abstract class can avoid these problems.</p></li><li><p><strong>Multiple inheritance</strong>. It is <em>occasionally</em> useful to be able to implement an interface deep in the inheritance hierarchy. A good example is <a href="http://download.java.net/jdk6/doc/api/java/lang/Comparable.html">Comparable</a>, where for example Integer is Comparable but its parent class Number is not. However, there aren't many other good examples of this in the core Java classes. It is usually bad practice to implement some random interface in a class whose primary purpose is something else. Implementing the interface in a private inner class is usually cleaner, and then of course it could just as well be an abstract class.</p></li><li><p><strong>Dynamic proxies</strong>. The invaluable <a href="http://download.java.net/jdk6/doc/api/java/lang/reflect/Proxy.html">java.lang.reflect.Proxy</a> class allows you to make an implementation of any interface at runtime, where calling any of the interface's methods results in a call to a single <a href="http://download.java.net/jdk6/doc/api/java/lang/reflect/InvocationHandler.html#invoke%28java.lang.Object,%20java.lang.reflect.Method,%20java.lang.Object%5B%5D%29">invoke</a> method. There's no way to construct a dynamic proxy for an abstract class, so if you think it will be useful for users to make dynamic proxies that is one reason to favour an interface. (<a href="http://cglib.sourceforge.net/">cglib</a> can sometimes be used to achieve the same effect for abstract classes, but with several limitations, plus the documentation is <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=61979">really poor</a>.)</p></li></ul><h2>Be careful with packages</h2><p>The Java language has fairly limited ways of controlling the visibility of classes and methods. In particular, if a class or method is visible outside its package, then it is visible to all code in all packages. This means that if you define your API in several packages, you have to be careful to avoid being forced to make things public just so that code in other packages in the API can access them.</p><p>The simplest solution to avoid this is to <strong>put your whole API in one package</strong>. For an API with fewer than about 30 public classes this is usually the best approach.</p><p>If your API is too big for a single package to be appropriate, then you should plan to have <strong>private implementation packages</strong>. That is, some packages in your implementation are excluded from the Javadoc output and are not part of the public API, even though their contents are accessible. If you look at the JDK, for example, there are many sun.* and com.sun.* packages of this sort. Users who rely on the Javadoc output will not know of their existence. Users who browse the source code can see them, and can access the public classes and methods, but they are discouraged from doing so and warned that there is no guarantee that these classes will remain unchanged across revisions.</p><p>A good convention for private packages is to put internal in the name. So the Banana API might have public packages com.example.banana and com.example.banana.peel plus private packages com.example.banana.internal and com.example.banana.internal.peel.</p><p>Don't forget that the private packages are accessible. There may be security implications if arbitrary code can access these internals. Various techniques exist to address these. The NetBeans API tutorial <a href="http://openide.netbeans.org/tutorial/api-design.html#design.less.friend">describes one</a>. In the JMX API, we use another. There is a class <a href="http://download.java.net/jdk6/doc/api/javax/management/JMX.html">javax.management.JMX</a> which contains only static methods and has no public constructor. This means that user code can never have an instance of this class. So in the private com.sun.jmx packages, we sometimes add a parameter of type JMX to sensitive public methods. If a caller can supply a non-null instance of this class, it must be coming from the javax.management package.</p><h2>Other random tips</h2><p>Here are some other random tips based on our experience with the JMX API and on the sources I mentioned.</p><p><strong>Immutable classes are good</strong>. If a class can be immutable, then it should be. Rather than spelling out the reasons, I'll refer you to Item 13 in <a href="http://java.sun.com/docs/books/effective/"><em>Effective Java</em></a>. You wouldn't think of designing an API without having this book, right?</p><p><strong>The only visible fields should be static and final</strong>. Again this one is pretty banal and I mention it only because certain early APIs in the core platform violated it. Not an example to follow.</p><p><strong>Avoid eccentricity</strong>. There are many well-established conventions for Java code, with regard to identifier case, getters and setters, standard exception classes, and so on. Even if you think these conventions could have been better, don't replace them in your API. By doing so you force users to throw away what they already know and learn a new way of doing an old thing.</p><p>For instance, don't follow the bad example of <a href="http://download.java.net/jdk6/doc/api/java/nio/package-summary.html">java.nio</a> and <a href="http://download.java.net/jdk6/doc/api/java/lang/ProcessBuilder.html">java.lang.ProcessBuilder</a> where the time-honoured T&nbsp;getThing() and void&nbsp;setThing(T) methods are replaced by T&nbsp;thing() and ThisClass&nbsp;thing(T). Some people think this is neato-keen and others that it is an abomination, but either way it's not a well-known idiom so don't force your users to learn it.</p><p><strong>Don't implement Cloneable</strong>. It is usually less useful than you might think to create a copy of an object. If you do need this functionality, rather than having a clone() method it's generally a better idea to define a &quot;copy constructor&quot; or static factory method. So for example class Banana might have a constructor or factory method like this:</p><pre>      public Banana(Banana b) {      // copy constructor     	  this(b.colour, b.length);       }       // ...or...       public static Banana newInstance(Banana b) {     	  return new Banana(b.colour, b.length);       }     </pre><p>The advantage of the constructor is that it can be called from a subclass's constructor. The advantage of the static method is that it can return an instance of a subclass or an already-existent instance.</p><p>Item 10 of <em>Effective Java</em> covers clone() in excruciating detail.</p><p><strong>Exceptions should usually be unchecked</strong>. Item 41 of <em>Effective Java</em> gives an excellent summary here. Use a checked exception &quot;if the exceptional condition cannot be prevented by proper use of the API <em>and</em> the programmer using the API can take some useful action once confronted with the exception.&quot; In practice this usually means that a checked exception reflects a problem in interaction with the outside world, such as the network, filesystem, or windowing system. If the exception signals that parameters are incorrect or than an object is in the wrong state for the operation you're trying to do, then an unchecked exception (subclass of <a href="http://download.java.net/jdk6/doc/api/java/lang/RuntimeException.html">RuntimeException</a>) is appropriate.</p><p><strong>Design for inheritance or don't allow it</strong>. Item 15 of <em>Effective Java</em> tells you all you might want to know about this. The summary is that every method should be final by default (perhaps by virtue of being in a final class). Only if you can clearly document what happens if you override the method should it be possible to do so. And you should only do that if you have coded useful examples that do override the method.</p><h2>Summary</h2><ul><li>Design to evolve. </li><li>Correctness, then simplicity, then efficiency. </li><li>Interfaces are overvalued. </li><li>Be careful with packages. </li><li>Read <em>Effective Java</em>. </li></ul><p><a href="http://www.artima.com/weblogs/viewpost.jsp?thread=142428" target="_blank">http://www.artima.com/weblogs/viewpost.jsp?thread=142428</a> </p>
]]></description>
<link>http://www.5dinfo.net/blog/?2008/11/8/1</link>
<guid>http://www.5dinfo.net/blog/?2008/11/8/1</guid>
<category>Software Design</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Sat, 08 Nov 2008 02:02:33 +0800</pubDate>
</item>
<item>
<title>IndexReader被缓存与未被缓存的搜索性能测试对比</title>
<description><![CDATA[
<p>索引个数: 10<br />索引大小: 59.6G,未作optimize.<br />索引总记录数: 17412072 (一千七百万)</p><p>未缓存,<br />第一次查询耗时: 80266毫秒<br />第二次查询耗时: 17141毫秒<br />第三次查询耗时: 17438毫秒<br />第四次查询耗时: 17875毫秒<br />第五次查询耗时: 16406毫秒<br />第六次查询耗时: 16953毫秒</p><p>缓存后,<br />第一次查询耗时: 1分58秒875毫秒<br />第二次查询耗时: 4秒437毫秒<br />第三次查询耗时: 3秒15毫秒<br />第四次查询耗时: 2秒906毫秒<br />第五次查询耗时: 2秒890毫秒</p><br /><br />
]]></description>
<link>http://www.5dinfo.net/blog/?2008/10/30/1</link>
<guid>http://www.5dinfo.net/blog/?2008/10/30/1</guid>
<category>JAVA</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Thu, 30 Oct 2008 10:11:57 +0800</pubDate>
</item>
<item>
<title>祝福</title>
<description><![CDATA[
<p><img src="http://5dinfo.net/MyPhoto/photo/5dinfo_2008100420575884343.jpg" border="0" width="196" height="223" /></p><p>祝新婚愉快.</p><br /><br />
]]></description>
<link>http://www.5dinfo.net/blog/?2008/10/4/1</link>
<guid>http://www.5dinfo.net/blog/?2008/10/4/1</guid>
<category>Diary</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Sat, 04 Oct 2008 21:00:29 +0800</pubDate>
</item>
<item>
<title>Nokia E66</title>
<description><![CDATA[
<p><a href="http://5dinfo.net/MyPhoto/photo/5dinfo_2008092015030043820.jpg" target="_blank" onclick="return hs.expand(this)"><img src="http://5dinfo.net/MyPhoto/PreviewImage/2008-09/pre5dinfo_2008092015030043820.jpg" border="0" alt="E66" title="E66" width="180" height="101" /></a></p><p>&nbsp;多了个玩具.</p><br /><br />
]]></description>
<link>http://www.5dinfo.net/blog/?2008/9/20/1</link>
<guid>http://www.5dinfo.net/blog/?2008/9/20/1</guid>
<category>Diary</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Sat, 20 Sep 2008 23:37:00 +0800</pubDate>
</item>
<item>
<title>十年</title>
<description><![CDATA[
<p>1998-2008</p><p>十年后我们相聚北京. </p><br /><br />
]]></description>
<link>http://www.5dinfo.net/blog/?2008/9/1/1</link>
<guid>http://www.5dinfo.net/blog/?2008/9/1/1</guid>
<category>Diary</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Mon, 01 Sep 2008 10:59:47 +0800</pubDate>
</item>
<item>
<title>万物皆规律,有法天下和 -- 怎样做研究</title>
<description><![CDATA[
<p><strong><a href="http://blog.sina.com.cn/s/blog_4cbec5e9010007pm.html" target="_blank">怎样做研究（一）</a></strong></p><p><strong><a href="http://blog.sina.com.cn/s/blog_4cbec5e9010007pl.html" target="_blank">怎样做研究（二）</a></strong></p><br /><br />
]]></description>
<link>http://www.5dinfo.net/blog/?2008/8/18/1</link>
<guid>http://www.5dinfo.net/blog/?2008/8/18/1</guid>
<category>Programming Life</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Mon, 18 Aug 2008 00:19:26 +0800</pubDate>
</item>
<item>
<title>又迟到了</title>
<description><![CDATA[
MD, 又迟到了,我起来的那会, 姚明正在天安门前传递圣火. 他咋起得这么早咧?<br /><br />
]]></description>
<link>http://www.5dinfo.net/blog/?2008/8/6/1</link>
<guid>http://www.5dinfo.net/blog/?2008/8/6/1</guid>
<category>Diary</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Wed, 06 Aug 2008 11:05:29 +0800</pubDate>
</item>
<item>
<title>Christian The Lion</title>
<description><![CDATA[
<p>Love knows no limits and Boolean.TRUE friendship last a lifetime.</p><p>Get back in touch with some one today.</p><br /><br /><div><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="425" height="344"><param name="width" value="425" /><param name="height" value="344" /><param name="allowfullscreen" value="true" /><param name="src" value="http://www.youtube.com/v/oiGKWoJi5qM&amp;hl=en&amp;fs=1" /><embed type="application/x-shockwave-flash" width="425" height="344" allowfullscreen="true" src="http://www.youtube.com/v/oiGKWoJi5qM&amp;hl=en&amp;fs=1"></embed></object></div>
]]></description>
<link>http://www.5dinfo.net/blog/?2008/7/28/1</link>
<guid>http://www.5dinfo.net/blog/?2008/7/28/1</guid>
<category>Diary</category>
<author>吴迪 &lt;admin@5dinfo.net&gt;</author>
<pubDate>Mon, 28 Jul 2008 21:55:20 +0800</pubDate>
</item>
</channel>
</rss>
