有一道题,是关于 List.remove( int ) 和 List.remove (Object ) 两个方法的,在 List 的元素类型为 Integer 的时候,究竟调用的哪个 API,即:删除对应的整数,或者是删除对应下标的元素 ?
下边来看 List 接口出现的 API:
remove
E remove(int index)
- 移除列表中指定位置的元素(可选操作)。将所有的后续元素向左移动(将其索引减 1)。返回从列表中移除的元素。
-
-
- 参数:
index – 要移除的元素的索引
- 返回:
- 以前在指定位置的元素
- 抛出:
UnsupportedOperationException – 如果列表不支持 remove 操作
IndexOutOfBoundsException – 如果索引超出范围 (index < 0 || index >= size())
remove
boolean remove(Object o)
- 从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。如果列表不包含元素,则不更改列表。更确切地讲,移除满足 (o==null ? get(i)==null : o.equals(get(i))) 的最低索引 i 的元素(如果存在这样的元素)。如果此列表已包含指定元素(或者此列表由于调用而发生更改),则返回 true。
-
- 指定者:
- 接口
Collection<E> 中的 remove
-
- 参数:
o – 要从该列表中移除的元素,如果存在的话
- 返回:
- 如果列表包含指定的元素,则返回 true
- 抛出:
ClassCastException – 如果指定元素的类型和此列表不兼容(可选)
NullPointerException – 如果指定的元素是 null,并且此列表不允许 null 元素(可选)
UnsupportedOperationException – 如果列表不支持 remove 操作
好吧,问题如下:
Read more…
由于线程的本质特性,不能捕获从线程中抛出的异常,一但异常跳出run方法,就会直接输出到控制台。在Java5中,可以用Executor来解决这个问题。
Thread.UncaughtExceptionHandler接口允许在每个Thread对象上附着一个异常处理器,它的uncaughtException方法会在线程因未捕获的异常而临近死亡时被调用。我们可以创建一个ThreadFactory,它将在每个新创建的Thread对象上附着Thread.UncaughtExceptionHanlder。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
class ExceptionThread2 implements Runnable{
public void run() {
Thread t = Thread.currentThread();
System.out.println("run() by "+t);
System.out.println("eh = "+t.getUncaughtExceptionHandler());
throw new RuntimeException();
}
}
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
public void uncaughtException(Thread t, Throwable e) {
System.out.println("caught "+e);
}
}
class HandlerThreadFactory implements ThreadFactory{
public Thread newThread(Runnable r) {
System.out.println(this + " creating new Thread");
Thread t = new Thread(r);
System.out.println("Created :"+t);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
System.out.println("eh = "+t.getUncaughtExceptionHandler());
return t;
}
}
public class CaptureUncaughtException {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
exec.execute(new ExceptionThread2());
exec.shutdown();
}
}
Read more…
Java.io包是用术语流(stream)来定义的,流是有序的数据序列,它有一个源(输入流)或一个目的地(输出流) ,它代表任何有能力产生数据的数据源对象或者有能力接收数据的接收端对象,它屏蔽了实际I/O设备中处理数据的细节。
Java.nio包是用术语Channel 和buffer来定义I/O的。缓冲区是可以从中读取或写入的数据存储(类似于数组),通道表示的是能够执行I/O操作的实体的连接,这些实体包括缓冲区,文件和套接字。NIO和OIO的区别主要在于Channel允许不阻塞的I/O操作和可中断的阻塞操作,这对于高吞吐量的服务器应用是至关重要的。
Java.net包是基于对套接字的使用,用一种基于流,或者基于通道的模型提供了对网络I/O的特殊支持。
Java.io中的字符流,字符是指16位的UTF-16字符。
关闭流可以释放该流可能使用过的资源(如文件描述符),这些资源在不再使用时尽快回收;而如果某个流未被显式地关闭,则继续持有这些资源。流类可以定义finalize方法,但是通常在完成流的操作以后,就应该将其关闭。如果流已经被关闭,之后在其上操作会触发IOException,而关闭一个已经被关闭了的流则不会有任何的影响。(即流可以重复关闭,但不能在关闭之后继续使用)
所有的字节流都具有相同的同步策略和并发行为。
下面主要说明一些特别要注意的方法:
InputStream
public abstract int read() throws IOException
这个是唯一需要重写的方法,用以读取数据的一个单个字节,并返回0~255之间的整数,如果已经达到流的末尾,则将返回-1。注意,这个方法将发生阻塞直到可获取输入,到达流的末尾,或者抛出异常。这个方法返回的是一个int而不是byte值,因为它需要返回所的有效的字节值加上一个表示末尾的标志值,这就要求标志值要超出byte的范围,所以就采用了更大的int。注意 System.in就是InputStream类型的。
OutputStream
public abstract void write(int b) throws IOException
将b作为一个字节写入,由于是int类型,只有此整数的最低8位会被写入,此方法将阻塞直至字节写入完成。
InputStream和OuputStream分别只要求子类实现其read和write方法,因为其它read,write方法都是在此基础上定义的,大多数流都可以通过覆盖read或write方法来提高性能,而OutputStream中的flush和close方法的默认实现通常都需要在特定的流中进行恰当的覆盖,尤其是被缓冲的流,可能需要在关闭的时候进行刷新。
设计Reader和Writer类继承层次主要是为了国际化,因为16位的Unicode用于字符国际化,所以添加这两个类层次就是为了在所有的I/O操作中支持Unicode,此外,新类库的设计使得它的操作比旧类库要快。在应用中,最明智的做法应该是:尽量尝试使用Reader和Writer,一旦程序代码无法成功编译,才使用面向字节的类库。例如,java.util.zip就是只面向字节的。
Read more…
- 静态AOP:通过修改应用程序实际的字节码来完成织入过程,从而根据需求修改和扩展代码,由于最终结果就是普通的Java字节码,因此性能较高。但是注意其缺点是,如果想作任何的修改,即使只是加入一个新的JointPoint,都必须重新编译整个程序。
- 动态AOP:织入过程是在运行时动态进行的。具体的实现有若干种,在Spring中是为所有目标对象创建代理(但不能为final类生成代理),以便Advice可以按需要被使用。虽然其性能比不上静态的AOP,但是对应用的修改不必重新编译主程序的代码。
- 建议首选Spring AOP,只在功能达不到需求的时候,或者在程序性能调优时发现性能较差时才改用AspectJ。在Spring AOP中,第一部份是AOP core,它提供了完全解耦的,纯编程式的AOP功能;第二部份则是为让我们能在程序中更简便地使用AOP而给出的一组框架服务。Spring AOP仅是所有AOP特性的一个子集,但涵盖了最常用的90%的功能。
- Jointpoint:一个程序执行过程中的特定点。可以是方法的调用,方法执行过程本身,类的初始化,对象的实例化等。
- Advice:在某一特定的jointpoint运行的代码。可以分为before advice, after advice等。
- Pointcut:用来定义某一个advice应该何时执行的一组jointpoint。比如一个典型的pointcut就是对某一个类的所有方法调用的集合,通常我们会组建复杂的pointcut来控制advice什么时候执行。
- Aspect: advice和pointcut的组合。这个组合定义了一段程序中应该包括的逻辑以及何时应该执行该逻辑。
- Weaving:将aspect真正加入程序代码的过程。这里可以分为编译时织入和运行时织入。
- Target: 如果一个对象的执行过程受到某个AOP操作的修改,那么它就是一个目标对象。
- Introduction:通过引入,我们可以在一个对象中加入新的方法或字段,以改变它的结构,你可以使用引入来让任何对象实现一个特定的接口,而不需要对这个对象的类型显式地实现这个接口。
- Spring内部有两种实现代理的方法:JDK动态代理和CGLIB代理,且CGLIB代理的性能较优。Spring AOP只支持方法级别的jointPoint。
- 接口Advisor代表一个Aspect,但这个接口不建议直接使用,而是使用其子接口,来创建各种不同的aspect。
- ProxyFactory的addAddvice方法,这个方法内部会将提供的advice包装在一个DefaultPointCutAdvisor对象里面,它也是PointCutAdvisor的标准实现,将其配置为包含所有默认方法调用的pointcut。如果想对创建的Advisor有更多的控制,或者要向代理中添加一个introduction,那么可以自行创建Advisor并调用addAdvisor方法。同时,ProxyFactory也提供了removeAdvice,removeAdvisor等方法来删除之前加入的advisor。
- 前置advice是最有用的advice之一,它可以修改传递给目标方法的参数,也可以抛出一个异常来阻止目标方法的执行。
- 后置advice是在方法调用完成后才执行的。我们没有办法改变已经执行的方法的参数,只能读取而不能修改目标方法的执行路径或阻止目标方法的执行,更重要的是也无法修改目标方法的返回值。不过,还是可以抛出一个异常让调用者看到的是异常而不是返回值。
- 包围通知在功能上综合了前置通知和后置通知,并且可以修改方法的返回值,或者阻止方法的执行。即将目标方法的实现完全更换成新的代码。Spring的很多功能,如远程代理支持和事务管理,都是由拦截器完成的。同时,拦截器也是剖析程序运行的好办法。
- 抛出通知和后置通知一样,是在jointPoint之后运行的,不过抛出通知只在方法抛出一个异常时才执行。此外,抛出通知对程序运行本身不能做任何改变。我们可以做的只是改变抛出异常的类型,比如需要使用一个API时,它的异常设计非常糟糕,那就可以抛出通知来通知该API中所有的类,这样就能重新设计异常继承的结构,从而使之更易管理并且具备自描述性。同时,也可以用抛出通知来提供一个集中的错误日志,以此减少散布在程序各处的记录错误日志代码的数量。
要注意的是 ThrowsAdvice只是一个标志接口,里面的方法是通过反射来调用 的,其实现类必须以下面的形式来实现方法:
void afterThrowing([Method,args,target,] ThrowableSubclass);
其中前三个参数是可选的。特别地,对于抛出的每一个异常,Spring会选择签名与抛 出的异常最匹配的一个方法,如果抛出的的Advice定义了两个afterThrowing方法, 而且它们的异常类型一样,但分别有1个和4个参数,那Spring会运行含有4个参数 的afterThorwing方法。
注意,如果一个throws-advice方法本身抛出一个exception,它会覆盖原始的异常, 即改变抛出给用户的异常,改写后的一般是一个RuntimeException,因为这与任何方 法签名都是兼容的。然而,如果一个throws-advice方法抛出一个checked Exception, 那么它必须匹配目标方法抛出的异常,所以这在一定程度上与目标方法的签名是耦合 的。永远不要抛出一个非声明的与目标方法签名不兼容的checked exception。
Zipf定律是文献计量学的重要定律之一,它和罗特卡定律、布拉德福定律一起被并称为文献计量学的三大定律。
对于CDN的内容管理,也近似符合Zipf 定律,就是大家常说对于内容的访问遵循80/20原则,也就是20%的内容,会占有80%的访问量。

zipf law
这里 r 表示一个单词的出现频率的排名,P(r)表示排名为r的单词的出现频率.
(单词频率分布中 C约等于0.1, a约等于1)
后人将这个分布称为zipf distribution,中文名称为齐普夫分布或Zeta 分布。这是一个离散事件分布,广泛应用于语言学,保险学,网络模拟,以及对稀疏事件的建模中。
它表明在英语单词中,只有极少数的词被经常使用,而绝大多数词很少被使用。实际上,包括汉语在内的许多国家的语言都有这种特点。这个定律后来在很多领域得到了同样的验证,包括网站的访问者数量、城镇的大小和每个国家公司的数量。。这个定理也在很多分布里面得到了验证,比如人们的收入,互联网的网站数量和访问比例,互联网内容和访问比例(其他分布两个常数有所不同,a越大,分布越密集,对于VOD来说某些时候符合双zipf分布)。
比起枯燥的公式,图表更具有说服力,下面是用三百个严格符合zipf 分布的数据点描绘成的图,其中横轴表示排名,纵轴表示访问的频率,分别使用线性坐标和对数坐标表示:

zipf distribution
可以看到对数坐标下是一条完美的直线。
Read more…
评论