My own Queue Implementation in Java
@Override
public String toString() {
    if(size == 0) {
        return "[]";
    }

    StringBuilder sb = new StringBuilder();
    QueueNode&lt;T&gt; cur = first;
    sb.append(cur.getValue() + "&lt;-");

    while(cur.getNext() != null &amp;&amp; !cur.equals(last)) {
        sb.append(cur.getNext().getValue() + "&lt;-");
        cur = cur.getNext();
    }

    return sb.append("null").toString();
}


Empty stack prints "[]", stack with one element prints 1&lt;-null. Where are the surrounding brackets? Also, you can use a do-while loop here to prevent needing to specify how to print twice:

@Override
public String toString() {
    if(size == 0) {
        return "[]";
    }

    StringBuilder sb = new StringBuilder();
    QueueNode&lt;T&gt; cur = first;

    do {
        sb.append(cur.getValue() + "&lt;-");
        cur = cur.getNext();
    } while(cur != null);

    return sb.append("null").toString();
}


It also vastly simplifies the iteration.



public void offer(T val) {
    QueueNode&lt;T&gt; cur = new QueueNode(val);
    if(size == 0) {
        cur.setNext(first);
        first = cur;
        last = cur;
        size++;
        return;
    }

    last.setNext(cur);
    last = cur;
    size++;
}


This could be simplified to reduce duplication - step 1, making the else case explicit...

public void offer(T val) {
    QueueNode&lt;T&gt; cur = new QueueNode(val);
    if(size == 0) {
        cur.setNext(first);
        first = cur;
        last = cur;
        size++;
    } else {
        last.setNext(cur);
        last = cur;
        size++;
    }
}


Step two, moving similar instructions into the shared area.

public void offer(T val) {
    QueueNode&lt;T&gt; cur = new QueueNode(val);
    if(size == 0) {
        cur.setNext(first);
        first = cur;
    } else {
        last.setNext(cur);
    }
    last = cur;
    size++;
}


Additionally, you can make use of isEmpty() here for increased clarity.



public QueueNode&lt;T&gt; poll() {
    if(isEmpty()) {
        return null;
    }

    QueueNode&lt;T&gt; cur = first;
    first = first.getNext();
    size--;
    return cur;
}


poll() is returning internal nodes. You want to return the value instead. Don't expose your internal nodes. Use exceptions for indicating pulling from an empty queue.