Second version of Dequeue implementation as the first one contained bugs.

package pl.bedkowski.code.amazing;

import java.util.Iterator;

public class Dequeue<E> implements Iterable<E> {
	private Entry tail, head;
	private int size;
	
	public boolean push(E item) {
		tail = new TailEntry(item, tail);
		if (head == null) {
			head = tail;
		}
		++size;
		return true;
	}
	
	public E pop() {
		return cut(false);
	}
	
	private E cutTail() {
		E ret = tail.value;
		tail = tail.prev;
		return ret;
	}
	
	public boolean unshift(E item) {
		head = new HeadEntry(item, head);
		if (tail == null) {
			tail = head;
		}
		++size;
		return true;
	}
	
	public E shift() {
		return cut(true);
	}
	
	private E cutHead() {
		E ret = head.value;
		head = head.next;
		return ret;
	}
	
	private E cut(boolean headHead) {
		if (isSizeZero()) {
			return null;
		}
		E ret = headHead ? cutHead() : cutTail();
		--size;
		if (isSizeZero()) {
			tail = null;
			head = null;
		}
		return ret;
	}
	
	public int size() {
		return size;
	}

	/**
	 * Checks if both size and tail/head properties for null
	 * 
	 * @return true size is zero and both tail/head are null
	 */
	public boolean isEmpty() {
		return isSizeZero() && tail == null && head == null;
	}
	
	
	private boolean isSizeZero() {
		return size == 0;
	}
	
	@Override
	public Iterator<E> iterator() {
		return new Iterator<E>() {
			
			private Entry entry = head;

			@Override
			public boolean hasNext() {
				return entry != null;
			}

			@Override
			public E next() {
				if (entry != null) {
					E ret = entry.value;
					entry = entry.next;
					return ret;
				} else {
					return null;
				}
			}

			@Override
			public void remove() {
				throw new RuntimeException();
			}
		};
	}
	
	public Iterator<E> reverseIterator() {
		return new Iterator<E>() {
			
			private Entry entry = tail;

			@Override
			public boolean hasNext() {
				return entry != null;
			}

			@Override
			public E next() {
				if (entry != null) {
					E ret = entry.value;
					entry = entry.prev;
					return ret;
				} else {
					return null;
				}
			}

			@Override
			public void remove() {
				throw new RuntimeException();
			}
		};
	}
	
	private abstract class Entry {
		private Entry prev,next;
		private E value;
		
		private Entry(E value, Entry next, Entry prev) {
			this.value = value;
			this.next = next;
			this.prev = prev;
		}
		
		@Override
		public String toString() {
			return value.toString();
		}
	}
	
	private class TailEntry extends Entry {
		private TailEntry(E value, Entry prev) {
			super(value, null, prev);
			if (prev != null) {
				prev.next = this;
			}
		}
	}
	
	private class HeadEntry extends Entry {
		private HeadEntry(E value, Entry next) {
			super(value, next, null);
			if (next != null) {
				next.prev = this;
			}
		}
	}
}