JDK 6 更新内容

2018/10/29

1.6版本新增加,队列新增Deque接口和naviagble集合类。

Deque

双端队列,两端队头队尾都可以操作,具有队列和栈性质的数据类型。双端队列中的元素可以从两端弹出,插入和删除。操作提供两种形式,一种是只要操作失败就抛出异常,另一种是操作是否会返回特定值。Deque继承Queue接口,所以也支持FIFO模式操作,同时也支持LIFO基于栈的模式。

ArrayDeque

// 也是基于数组结构存储元素
private transient E[] elements;

// 队头队尾下标
private transient int head;

private transient int tail;

public ArrayDeque() {
	elements = (E[]) new Object[16];	// 默认创建容量为16的数组
}

public ArrayDeque(int numElements) {
	allocateElements(numElements);	// 也可以指定数组容量
}

private void allocateElements(int numElements) {
	int initialCapacity = MIN_INITIAL_CAPACITY;	// 默认大小8
	// Find the best power of two to hold elements.
	// Tests "<=" because arrays aren't kept full.
	if (numElements >= initialCapacity) {	// 容量大小必须是2的整数倍
		initialCapacity = numElements;
		initialCapacity |= (initialCapacity >>>  1);
		initialCapacity |= (initialCapacity >>>  2);
		initialCapacity |= (initialCapacity >>>  4);
		initialCapacity |= (initialCapacity >>>  8);
		initialCapacity |= (initialCapacity >>> 16);
		initialCapacity++;

		if (initialCapacity < 0)   // Too many elements, must back off
			initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
	}
	elements = (E[]) new Object[initialCapacity];
}

// 添加到队列头
public void addFirst(E e) {
	if (e == null)	// 元素不允许为null,因为ArrayDeque是根据null来判断// 对应下标位置是否被有元素存在
		throw new NullPointerException();
	elements[head = (head - 1) & (elements.length - 1)] = e;
	if (head == tail)
		doubleCapacity();	// 扩容
}

// 每次双倍扩容
private void doubleCapacity() {
	assert head == tail;	// 数组满了才扩容
	int p = head;
	int n = elements.length;
	int r = n - p; // number of elements to the right of p
	int newCapacity = n << 1;
	if (newCapacity < 0)
		throw new IllegalStateException("Sorry, deque too big");
	Object[] a = new Object[newCapacity];
	System.arraycopy(elements, p, a, 0, r);	// 复制到新数组
	System.arraycopy(elements, 0, a, r, p);
	elements = (E[])a;
	head = 0;
	tail = n;
}

// 删除指定位置的元素
private boolean delete(int i) {
	checkInvariants();
	final E[] elements = this.elements;
	final int mask = elements.length - 1;
	final int h = head;
	final int t = tail;
	final int front = (i - h) & mask;
	final int back  = (t - i) & mask;

	// Invariant: head <= i < tail mod circularity
	if (front >= ((t - h) & mask))
		throw new ConcurrentModificationException();

	// Optimize for least element motion
	if (front < back) {
		if (h <= i) {
		System.arraycopy(elements, h, elements, h + 1, front);
		} else { // Wrap around
		System.arraycopy(elements, 0, elements, 1, i);
		elements[0] = elements[mask];
		System.arraycopy(elements, h, elements, h + 1, mask - h);
		}
		elements[h] = null;
		head = (h + 1) & mask;
		return false;
	} else {
		if (i < t) { // Copy the null tail as well
		System.arraycopy(elements, i + 1, elements, i, back);
		tail = t - 1;
		} else { // Wrap around
		System.arraycopy(elements, i + 1, elements, i, mask - i);
		elements[mask] = elements[0];
		System.arraycopy(elements, 1, elements, 0, t);
		tail = (t - 1) & mask;
		}
		return true;
	}
}

BlockingDeque

Deque添加阻塞操作,主要的方法有:

  1. offerFirst(E e) 将元素添加到队列头
  2. offerLast(E e) 将元素添加到队列尾
  3. offerFirst(E e, long timeout, TimeUnit unit) 将元素添加到队列头,如果在指定时间内未添加成功则抛出异常
  4. offerFirst(E e, long timeout, TimeUnit unit) 将元素添加到队列尾,如果在指定时间内未添加成功则抛出异常
  5. takeFirst() 队头元素出队
  6. takeLast() 队尾元素出队
  7. pollFirst(long timeout, TimeUnit unit) 队头元素出队,如果队列为空则一直等待直到超过指定时间
  8. pollLast(long timeout, TimeUnit unit) 队尾元素出队,如果队列为空则一直等待直到超过指定时间

LinkedBlockingDeque

基于双向链表实现,可指定容量大小。

等待指定时间,都是通过Condition.awaitNanos方法来实现等待。

ConcurrentSkipListMap

Java Compiler API

Java编程语言编译器可以用javac命令读取以Java编程语言编写的源文件,并将它们编译为字节码class文件。编译器也可以使用注解找到源文件和类文件并使用comiler API进行编译。编译器是一个命令行工具,但也可以使用Java compiler API调用。

我们可以用JDK6的Compiler API(JSR 199)去动态编译Java源文件,Compiler API结合反射功能就可以实现动态的产生Java代码并编译执行这些代码,有点动态语言的特征。这个特性对于某些需要用到动态编译的应用程序相当有用,比如JSP Web Server,当我们手动修改JSP后,是不希望需要重启Web Server才可以看到效果的,这时候我们就可以用Compiler API来实现动态编译JSP文件,当然,现在的JSP Web Server也是支持JSP热部署的,现在的JSP Web Server通过在运行期间通过Runtime.exec或ProcessBuilder来调用javac来编译代码,这种方式需要我们产生另一个进程去做编译工作,不够优雅而且容易使代码依赖与特定的操作系统;Compiler API通过一套易用的标准的API提供了更加丰富的方式去做动态编译,而且是跨平台的。

Post Directory