Looking for code review, optimizations and best practices.public class FindMiddleStack<T> {    private Node<T> top;    private Node<T> middle;    private int size = 0;    private static class Node<T> {        Node<T> left;        T item;        Node<T> right;        Node(Node<T> left, T item, Node<T> next) {            this.left =  left;            this.item = item;            this.right = next;        }    }    public void push(T item) {        final Node<T> node = new Node<T>(null, item, top);        if (top == null) {            top = node;            middle = node;        } else {            top.left = node;            top = node;        }        size++;        if (size % 2 == 0) {            middle = middle.left;        }    }    public T pop() {        if (top == null) {            throw new EmptyStackException();        }        T item = top.item;        top = top.right;        // important, to not leak references.        if (top != null) {            top.left = null;        }        if (top == null) {            middle = null;        }        if (size % 2 == 0) {            middle = middle.right;        }        size--;        return item;    }    public T peek() {        if (top == null) {            throw new EmptyStackException();        }        return top.item;    }    public T getMiddle() {        if (top == null) {            throw new EmptyStackException();        }        return middle.item;    }    public void deleteMiddle() {        if (top == null) {            throw new EmptyStackException();        }        if (middle.left != null) {            middle.left.right = middle.right;        }        if (middle.right != null) {            middle.right.left = middle.left;        }        if (size % 2 == 1) {            // deleted middle.            middle = middle.left;        } else {            middle = middle.right;        }        if (middle == null) {            top = null;        }        size--;    }    public int size() {        return size;    }    public boolean isEmpty() {        return size == 0;    }}public class FindMiddleStackTest {    @Test    public void testPushPop() {        FindMiddleStack<Integer> fm = new FindMiddleStack<Integer>();        fm.push(10);        fm.push(20);        fm.push(30);        fm.push(40);        fm.push(50);        fm.push(60);        fm.push(70);        int[] expected1 = {70, 60, 50, 40, 30, 20, 10};        int[] actual1 = new int[7];        int i1 = 0;        while (!fm.isEmpty()) {            actual1[i1++] = fm.pop();        }        assertTrue(Arrays.equals(expected1, actual1));    }    @Test    public void testPopAndMiddle( ) {        FindMiddleStack<Integer> fm = new FindMiddleStack<Integer>();        fm.push(10);        fm.push(20);        fm.push(30);        fm.push(40);        fm.push(50);        fm.push(60);        fm.push(70);        int[] expected2 = {40, 40, 30, 30, 20, 20, 10};        int[] actual2 = new int[7];        int i2 = 0;        while (!fm.isEmpty()) {            actual2[i2++] = fm.getMiddle();            fm.pop();        }        assertTrue(Arrays.equals(expected2, actual2));    }    @Test    public void testDeleteMiddleAndMiddle() {        FindMiddleStack<Integer> fm = new FindMiddleStack<Integer>();        fm.push(10);        fm.push(20);        fm.push(30);        fm.push(40);        fm.push(50);        fm.push(60);        fm.push(70);        int[] expected3 = {40, 50, 30, 60, 20, 70, 10};        int[] actual3 = new int[7];        int i3 = 0;        while (!fm.isEmpty()) {            actual3[i3++] =  fm.getMiddle();            fm.deleteMiddle();        }        assertTrue(Arrays.equals(expected3, actual3));    }}
Stack with getMiddle and deleteMiddle operation
java;algorithm;stack