我正在编写一个LinkedList实现,其中包括一个先前的函数,该函数返回在作为输入参数传递的位置之前的位置。它应该检查输入的位置是否是第一个位置,并在这种情况下抛出异常:
@Override
public Position<T> previous (Position<T> p) throws PositionException {
if (this.first(p)) {
throw new PositionException();
}
return this.convert(p).prev;
}
但是,以下测试失败了,因为它没有引发尝试在数组的第一个位置上使用上一个函数的预期异常:
@Test (expected=PositionException.class)
public void gettingPreviousAtFront() {
Position<String> one = list.insertFront("One");
Position<String> two = list.insertFront("Two");
assertTrue(list.first(two));
Position<String> beforeTwo = list.previous(two);
}
有1个失败:1) GettingPreviousAtFront(hw6.test.LinkedListTest) java.lang.AssertionError:预期的异常: 位于的exceptions.PositionException org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:32)
甚至通过测试第301行的断言,“两个”是第一个。那么,上一个函数怎么可能没有引发异常呢?
这是完整的链表代码:
package hw6;
import exceptions.EmptyException;
import exceptions.PositionException;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class LinkedList<T> implements List<T> {
private static final class Node<T> implements Position<T> {
// The usual doubly-linked list stuff.
Node<T> next; // reference to the Node after this
Node<T> prev; // reference to the Node before this
T data;
// List that created this node, to validate positions.
List<T> owner;
@Override
public T get() {
return this.data;
}
@Override
public void put(T t) {
this.data = t;
}
}
/** This iterator can be used to create either a forward
iterator, or a backwards one.
*/
private final class ListIterator implements Iterator<T> {
Node<T> current;
boolean forward;
ListIterator(boolean f) {
this.forward = f;
if (this.forward) {
this.current = LinkedList.this.sentinelHead.next;
} else {
this.current = LinkedList.this.sentinelTail.prev;
}
}
@Override
public T next() throws NoSuchElementException {
if (!this.hasNext()) {
throw new NoSuchElementException();
}
T t = this.current.get();
if (this.forward) {
this.current = this.current.next;
} else {
this.current = this.current.prev;
}
return t;
}
@Override
public boolean hasNext() {
if (this.forward) {
return this.current != LinkedList.this.sentinelTail;
}
else {
return this.current != LinkedList.this.sentinelHead;
}
}
}
/* ** LinkedList instance variables are declared here! ** */
private Node<T> sentinelHead;
private Node<T> sentinelTail;
private int length; // how many nodes in the list
/**
* Create an empty list.
*/
public LinkedList() {
this.sentinelHead = new Node<>();
this.sentinelTail = new Node<>();
this.sentinelHead.owner = this;
this.sentinelTail.owner = this;
this.sentinelTail.prev = this.sentinelHead;
this.sentinelHead.next = this.sentinelTail;
this.length = 0;
}
// Convert a position back into a node. Guards against null positions,
// positions from other data structures, and positions that belong to
// other LinkedList objects. That about covers it?
private Node<T> convert(Position<T> p) throws PositionException {
try {
Node<T> n = (Node<T>) p;
if (n.owner != this) {
throw new PositionException();
}
return n;
} catch (NullPointerException | ClassCastException e) {
throw new PositionException();
}
}
@Override
public boolean empty() {
return this.length == 0;
}
@Override
public int length() {
return this.length;
}
@Override
public boolean first(Position<T> p) throws PositionException {
Node<T> n = this.convert(p);
return this.sentinelHead.next == n;
}
@Override
public boolean last(Position<T> p) throws PositionException {
Node<T> n = this.convert(p);
return this.sentinelTail.prev == n;
}
@Override
public Position<T> front() throws EmptyException {
if (this.length == 0) {
throw new EmptyException();
}
return this.sentinelHead.next;
}
@Override
public Position<T> back() throws EmptyException {
if (this.empty()) {
throw new EmptyException();
}
return this.sentinelTail.prev;
}
@Override
public Position<T> next(Position<T> p) throws PositionException {
if (this.last(p)) {
throw new PositionException();
}
return this.convert(p).next;
}
@Override
public Position<T> previous(Position<T> p) throws PositionException {
if (this.first(p)) {
throw new PositionException();
}
return this.convert(p).prev;
}
@Override
public Position<T> insertFront(T t) {
return this.insertAfter(this.sentinelHead, t);
}
@Override
public Position<T> insertBack(T t) {
return this.insertBefore(this.sentinelTail, t);
}
@Override
public void removeFront() throws EmptyException {
this.remove(this.front());
}
@Override
public void removeBack() throws EmptyException {
this.remove(this.back());
}
@Override
public void remove(Position<T> p) throws PositionException {
Node<T> n = this.convert(p);
n.owner = null;
n.prev.next = n.next;
n.next.prev = n.prev;
this.length--;
}
@Override
public Position<T> insertBefore(Position<T> p, T t)
throws PositionException {
Node<T> current = this.convert(p);
Node<T> n = new Node<T>();
n.owner = this;
n.data = t;
n.prev = current.prev;
current.prev.next = n;
n.next = current;
current.prev = n;
this.length++;
return n;
}
@Override
public Position<T> insertAfter(Position<T> p, T t)
throws PositionException {
Node<T> current = this.convert(p);
Node<T> n = new Node<T>();
n.owner = this;
n.data = t;
n.next = current.next;
current.next.prev = n;
n.prev = current;
current.next = n;
this.length++;
return n;
}
@Override
public Iterator<T> forward() {
return new ListIterator(true);
}
@Override
public Iterator<T> backward() {
return new ListIterator(false);
}
@Override
public Iterator<T> iterator() {
return this.forward();
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("[");
for (Node<T> n = this.sentinelHead.next; n != this.sentinelTail; n = n.next) {
s.append(n.data);
if (n.next != this.sentinelTail) {
s.append(", ");
}
}
s.append("]");
return s.toString();
}
}