java/java

[Java] 제어문

danuri 2021. 6. 29. 20:04

https://github.com/whiteship/live-study

 

whiteship/live-study

온라인 스터디. Contribute to whiteship/live-study development by creating an account on GitHub.

github.com

백기선님 자바 기초 스터디 4주차

 

목표

자바가 제공하는 제어문을 학습하세요.

학습할 것

선택문
반복문

과제 0 ~ 5

 

선택문


선택문, 일명 조건문은 조건식과 문장을 포함하는 블럭{ }으로 구성되어 있으며, 조건식의 연산결과에 따라 실행할 문장이 달라져서 프로그램의 실행흐름을 변경할 수 있다. 조건문은 if문과 switch문, 두 가지가 있으며 if문이 많이 사용된다.

if문

if (조건식) {
	//조건식이 참(true)일 때, 수행될 문장들을 적는다.
}

조건식은 일반적으로 비교연산자와 논리연산자로 구성된다.

 

ex)

if (score > 60) {
    System.out.println("합격입니다.");
}

 이처럼 블럭 내의 문장이 하나뿐인 경우 괄호{ }를 생략할 수 있지만 가능하면 구분을 위해 생략하지 않고 사용하는 것이 바람직하다.

if (score > 60) 
	System.out.println("합격입니다.");

if-else문

if (조건식) {
	//조건식이 참(true)일 때, 수행될 문장들을 적는다.
} else {
	//조건식이 거짓(false)일 때, 수행될 문장들을 적는다.
}

 

ex)

if (score > 60) {
    System.out.println("합격입니다.");
} else {
    System.out.println("불합격입니다.");
}

if-else if문

ex)

if (score >= 90) {
    System.out.println("A");
} else if (score >= 80) {
    System.out.println("B");
} else if (score >= 70) {
    System.out.println("C");
} else {
    System.out.println("F");
} 

중첩 if문

ex)

if (score >= 60) {
    if (score != 60) {
        System.out.println("합격입니다.");
    }
} else {
    System.out.println("불합격입니다.");
}

 

중첩 if문에서는 괄호{ } 생략에 더욱 조심해야 한다. 바깥쪽 if문과 안쪽의 if문이 서로 엉켜서 if문과 else블럭의 관계가 이도한 바와 다르게 형성될 수도 있기 때문이다.

if (score >= 60) 
    if (score != 60) 
        System.out.println("합격입니다.");
    
 else
    System.out.println("불합격입니다.");

위 코드는 언뜻 보기에 else블럭이 바깥쪽의 if문에 속한 것처럼 보이지만, 괄호가 생략되었을 때 else블럭은 가까운 if문에 속한 것으로 간주되기 때문에 실제로는 아래와 같이 안쪽 if문의 else블럭이 되버린다.

if (score >= 60) {
    if (score != 60) {
        System.out.println("합격입니다.");
    } else {
        System.out.println("불합격입니다.");
    }
}

이는 맨 처음 코드에서 의도한 바와 완전히 다른 코드가 되기 때문에 중첩 if문에서는 괄호{ }를 확실히 해주는 것이 중요하다.

switch문

조건식의 결과가 참, 거짓 두 가지 밖에 없는 if문과 달리 switch문은 단 하나의 조건식으로 많은 경우의 수를 처리할 수 있다.

 

switch문 처리 과정

  1. 조건식을 계산한다.
  2. 조건식의 결과와 일치하는 case문으로 이동한다.
  3. 이후의 문장들을 수행한다.
  4. break문이나 switch문의 끝을 만나면 switch문 전체를 빠져나간다.

ex)

switch (month) {
    case 3:
    case 4:
    case 5:
        System.out.println("봄");
        break;
    case 6:
    case 7:
    case 8:
        System.out.println("여름");
        break;
    case 9:
    case 10:
    case 11:
        System.out.println("가을");
    default: //나머지
        System.out.println("겨울");
}

month의 값과 일치하는 case문으로 이동해 문장을 수행하고 break문을 만나면 switch문을 빠져나간다.

만약 case 5에서 break가 없다면 "봄"과 "여름" 모두 출력하게 되니 break를 적절한 위치에 꼭 사용하도록 하자.

 

switch문은 편리하고 직관적으로 보이지만 다음 제약조건이 따른다.

  1. switch문의 조건식 결과는 정수 또는 문자열이어야 한다.
  2. case문의 값은 정수, 상수만 가능하며, 중복되지 않아야 한다.

따라서 조건을 정수 혹은 문자열로 표현할 수 있는 경우 switch를 사용해도 좋지만 일반적으로 유연하게 조건을 설정할 수 있는 if문을 사용한다.

 

게다가 switch-case문은 매번 break, case를 장황하게 적어줘야 하는 것도 번거롭다.

그래서 자바12 이후에 switch 연산자를 제공하여 보다 편리하게 switch를 사용할 수 있게 되었다.

switch 연산자는 다음 글을 참고

https://gksdudrb922.tistory.com/135

 

[Java] 연산자

https://github.com/whiteship/live-study whiteship/live-study 온라인 스터디. Contribute to whiteship/live-study development by creating an account on GitHub. github.com 백기선님 자바 기초 스터디 3주..

gksdudrb922.tistory.com

 

반복문


반복문은 어떤 작업이 반복적으로 수행되도록 할 때 사용되며, 반복문의 종류로는 for문과 while문, 그리고 while문의 변형인 do-while문이 있다.

for문

for문은 아래와 같이 '초기화', '조건식', '증감식', '블럭{ }', 모두 4부분으로 이루어져 있으며, 조건식이 참인 동안 블럭 { } 내의 문장들을 반복하다 거짓이 되면 반복문을 벗어난다.

for (초기화;조건식;증감식) {
	//조건식이 참일 때 수행될 문장들을 적는다.
}

제일 먼저 초기화(1)가 수행되고, 그 이후버트는 조건식이 참인 동안 조건식(2) -> 수행될 문장(3) -> 증감식(4) 순서로 계속 반복된다. 그러다가 조건식이 거짓이 되면, for문 전체를 빠져나가게 된다.

 

ex)

for (int i = 1; i <= 5; i++) {
    System.out.println(i);
}

결과

1
2
3
4
5

향상된 for문

자바5부터 배열과 컬렉션에 저장된 요소에 접근할 때 기존보다 편리한 방법으로 처리할 수 있도록 for문의 새로운 문법이 추가되었다.

for ( 타입 변수명 : 배열 또는 컬렉션) {
	//반복할 문장
}

 

ex)

int[] arr = { 10, 20, 30, 40, 50 }

for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}

-> 향상된 for문

for (int tmp : arr) {
    System.out.println(tmp);
}

두 for문은 동등하며, 향상된 for문이 더 간결하다는 것을 알 수 있다. 그러나 향상된 for문은 일반적인 for문과 달리 배열이나 컬렉션에 저장된 요소를 읽어오는 용도로만 사용할 수 있다는 제약이 있다.

while문

while (조건식) {
	//조건식의 연산결과가 참(true)인 동안, 반복될 문장들을 적는다.
}

<for문과의 비교>

for (int i = 1; i <= 5; i++) {
    System.out.println(i);
}
int i = 1;
while (i <= 5) {
    System.out.println(i);
    i++;
}

while문의 경우 이처럼 초기화(1)와 증감식(4)을 따로 설정해줘야 한다.

do-while문

do-while문은 while문의 변형으로 기본적인 구조는 while문과 같으나 조건식과 블럭{ }의 순서를 바꿔놓은 것이다. 그래서 while문과 반대로 블럭{ }을 먼저 수행한 후에 조건식을 평가한다.

while문은 조건식의 결과에따라 블럭{ }이 한 번도 수행되지 않을 수 있지만, do-while문은 최소한 한번은 수행될 것을 보장하낟.

do {
	//조건식의 연산결과가 참일 때 수행될 문장들을 적는다.
} while (조건식); <- 끝에 ';'을 잊지 않도록 주의



ex)

do {
    System.out.println(i);
    i++;
} while (i <= 5);

break문

앞서 switch문에서 break문에 대해 배웠던 것을 기억할 것이다. 반복문에서도 break문을 사용할 수 있는데, switch문에서 그랬던 것처럼, break문은 자신이 가장 가까운 반복문을 벗어난다. 주로 if문과 함께 사용되어 특정 조건을 만족하면 반복문을 벗어 나도록 한다.

int i = 1;
while (true) {
    if (i >= 5) {
        break;
    }
    System.out.println(i);
    i++;
}

결과

1
2
3
4

무한 loop, while(true)를 통해 i를 1부터 출력하면서 i가 5 이상이 되면 반복을 그만한다.

continue문

continue문은 반복문 내에서만 사용될 수 있으며, 반복이 진행되는 도중에 continue문을 만나면 다음 반복으로 넘어간다.

for문의 경우 증감식으로 이동하며, while문의 경우 조건식으로 이동한다.

전체 반복 중에 특정 조건을 만족하는 경우를 제외하고자 할 때 유용하다.

for (int i = 1; i <= 10; i++) {
    if (i % 3 == 0) {
        continue;
    }
    System.out.println(i);
}

결과

1
2
4
5
7
8
10

1과 10사이의 숫자를 출력하되 그 중에서 3의 배수인 것은 제외하도록 하였다.

이름 붙은 반복문

break문은 근접한 단 하나의 반복문만 벗어날 수 있기 때문에, 여러 개의 반복문이 중첩된 경우에는 break문으로 중첩 반복문을 완전히 벗어날 수 없다. 이 때는 중첩 반복문 앞에 이름을 붙이고 break문에 이름을 지정해 줌으로써 하나 이상의 반복문을 벗어날 수 있다.

 

다음 구구단 예시를 보자.

for (int i = 2; i <= 9; i++) {
    for (int j = 1; j <= 9; j++) {
        System.out.println(i + "*" + j + "=" + i * j);
    }
    System.out.println();
}

결과

2*1=2
2*2=4
2*3=6
...
2*9=18

3*1=3
3*2=6
3*3=9
...
3*9=27

...

9*1=9
9*2=18
9*3=27
...
9*9=81

일반적인 구구단 코드이다.

 

여기에 특정 break 조건을 더해보겠다.

for (int i = 2; i <= 9; i++) {
    for (int j = 1; j <= 9; j++) {
        if (j == 5) {
            break;
        }
        System.out.println(i + "*" + j + "=" + i * j);
    }
    System.out.println();
}

결과

2*1=2
2*2=4
2*3=6
2*4=8

3*1=3
3*2=6
3*3=9
3*4=12

...

9*1=9
9*2=18
9*3=27
9*4=36

j가 5일 때 가장 가까운 반복문 j loop를 탈출하기 때문에 위와 같은 결과가 나온다. 

그렇다면 j가 5일 때 상위 반복문인 i loop를 탈출하고 싶다면 어떻게 해야할까? 이 때, 반복문에 이름을 붙이면 된다.

Loop1: for (int i = 2; i <= 9; i++) {
    for (int j = 1; j <= 9; j++) {
        if (j == 5) {
	    break Loop1;
        }
        System.out.println(i + "*" + j + "=" + i * j);
    }
    System.out.println();
}

결과

2*1=2
2*2=4
2*3=6
2*4=8

이처럼 i loopLoop1이라는 이름을 붙이고 break문에서 이름을 지정해주면 해당 이름의 반복문을 탈출할 수 있게 된다.

+) continue문에도 마찬가지로 이름 붙인 반복문을 사용할 수 있다.

 

과제 0. JUnit5를 학습하세요.


JUnit은 자바 프로그래밍 언어용 유닛 테스트 프레임워크이다.

 

JUnit5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

  • JUnit Platform: JVM에서 테스트 프레임워크를 실행할 수 있도록 한다.
  • JUnit Jupiter: 테스트를 하기 위한 여러 도구들을 갖고 있다.
  • JUnit Vintage: JUnit3 또는 JUnit4 기반 테스트를 실행할 수 있도록 도와준다.

여기서는 IntelliJ Gradle 프로젝트의 JUnit5를 학습할 것이다.

JUnit5 시작

Intellij에서 Gradle 프로젝트를 생성한다면, 자동으로 JUnit5가 dependencies에 등록된다.

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}

test {
    useJUnitPlatform()
}

만약 위 코드가 없다면 직접 의존성을 추가해주면 된다.

 

아래 useJUnitPlatform()은 말 그대로 JUnit Platform을 사용하여 테스트를 실행하도록 한다.

 

만약 JUnit5 이전 버전을 사용하고자 한다면 아래 의존성을 추가하면 된다.

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
    testCompileOnly 'junit:junit:4.13'
    testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'
}

 

Intellij는 src/test/java 아래에서 JUnit5 테스트를 진행할 수 있다.

혹은 특정 클래스에 command + shift + t를 입력하면 테스트를 만들 수 있다. (윈도우 ctrl + shift + t)

테스트는 기본적으로 단위 테스트 별로 @Test 애노테이션을 지정하면 된다.

@Test
public void test1() {

}

@Test
public void test2() {

}

+) 참고로 라이브 템플릿을 통해 단위 테스트 템플릿을 만들면 편리하다. 다음 글을 참고하자.

https://gksdudrb922.tistory.com/28?category=959621 

 

IntelliJ에서 jUnit Live Template 추가하기

jUnit을 활용한 테스트 진행 시 매 테스트마다 비슷한 구조를 계속 입력해야 한다. 이를 아얘 나만의 템플릿으로 만들어 사용하면 보다 편리하게 테스트를 진행할 수 있다. 인텔리제이 Settings(윈

gksdudrb922.tistory.com

JUnit5에서 자주 사용하는 API

JUnit5는 여러 상황들에 대해 테스트할 수 있는 도구인 Assertions 클래스를 제공한다.

본 포스팅에서는 Assertions가 제공하고 자주 사용하는 API들을 소개한다.

나머지 API들에 대해서는 상황, 필요에 따라 직접 찾아가며 테스트를 진행하는 것이 훨씬 효율적이다.

 

assertEquals

@Test
public void test1() {
    int num = 1;
    Assertions.assertEquals(1, num);
}

두 인자 간에 동일성 검사('==')를 한다.

 

assertAll

@Test
public void test1() {
    List<Integer> numbers = List.of(1, 2, 3);
    Assertions.assertAll(
            () -> Assertions.assertEquals(1, numbers.get(0)),
            () -> Assertions.assertEquals(2, numbers.get(1)),
            () -> Assertions.assertEquals(3, numbers.get(2))
    );
}

여러 Assertions들을 한 데로 묶을 수 있다.

 

assertThrows

@Test
    public void test1() {
        List<Integer> numbers = List.of(1, 2, 3);
        Assertions.assertThrows(ArrayIndexOutOfBoundsException.class,
                () -> numbers.get(3));
    }

Exception이 나올만한 상황에 대해 해당 Exception을 검사할 수 있다.

 

과제 1. live-study 대시 보드를 만드는 코드를 작성하세요


깃허브

 

과제 2. LinkedList를 구현하세요.


LinkedList란?

각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식의 자료구조이다.

데이터를 담고 있는 노드들이 연결되어 있고, 노드의 포인터가 이전 노드와의 연결을 담당한다.

출처: https://coding-factory.tistory.com/552

 

<ListNode>

public class ListNode {

    private int data;
    private ListNode next;

    public ListNode() {
    }

    public ListNode(int data) {
        this.data = data;
    }

    public int getData() {
        return data;
    }

    public ListNode getNext() { 
        return next; 
    }

    public void setNext(ListNode next) { 
        this.next = next; 
    }
}

 

<LinkedList>

public class LinkedList {

    public static ListNode add(ListNode head, ListNode nodeToAdd, int position) {
        if (position < 0) {
            exceptByPosition();
        }

        ListNode pre = updatePreNode(head, position);

        nodeToAdd.setNext(pre.getNext());
        pre.setNext(nodeToAdd);

        return nodeToAdd;
    }

    public static ListNode remove(ListNode head, int positionToRemove) {
        if (positionToRemove < 0) {
            exceptByPosition();
        }

        ListNode pre = updatePreNode(head, positionToRemove);
        if (pre.getNext() == null) {
            exceptByPosition();
        }

        ListNode node = pre.getNext();
        pre.setNext(pre.getNext().getNext());
        
        return node;
    }

    public static boolean contains(ListNode head, ListNode nodeToCheck) {
        for (ListNode node = head; node != null; node = node.getNext()) {
            if (node == nodeToCheck) {
                return true;
            }
        }
        return false;
    }

    private static ListNode exceptByPosition() {
        throw new IllegalStateException("Invalid Position.");
    }

    private static ListNode updatePreNode(ListNode head, int position) {
        ListNode pre = head;
        for (int i = 0; i < position; i++) {
            pre = pre.getNext();
            if (pre == null) {
                exceptByPosition();
            }
        }
        return pre;
    }
}

 

<테스트>

class LinkedListTest {

    @Test
    public void addTest() {
        //given
        ListNode head = new ListNode();
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(2);
        ListNode listNode3 = new ListNode(3);

        //when
        LinkedList.add(head, listNode1, 0);
        LinkedList.add(head, listNode2, 0);
        LinkedList.add(head, listNode3, 1);

        //then
        assertAll(
                () -> assertEquals(listNode2, head.getNext()),
                () -> assertEquals(listNode3, head.getNext().getNext()),
                () -> assertEquals(listNode1, head.getNext().getNext().getNext()),
                () -> assertThrows(IllegalStateException.class,
                        () -> LinkedList.add(head, new ListNode(4), 4))
        );
    }

    @Test
    public void removeTest() {
        //given
        ListNode head = new ListNode();
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(2);
        ListNode listNode3 = new ListNode(3);

        LinkedList.add(head, listNode1, 0);
        LinkedList.add(head, listNode2, 1);
        LinkedList.add(head, listNode3, 2);

        //when
        ListNode removedNode = LinkedList.remove(head, 1);

        //then
        assertAll(
                () -> assertEquals(listNode1, head.getNext()),
                () -> assertEquals(listNode3, head.getNext().getNext()),
                () -> assertEquals(listNode2, removedNode),
                () -> assertThrows(IllegalStateException.class,
                        () -> LinkedList.remove(head, 2))
        );
    }

    @Test
    public void containsTest() {
        //given
        ListNode head = new ListNode();
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(2);
        ListNode listNode3 = new ListNode(3);

        LinkedList.add(head, listNode1, 0);
        LinkedList.add(head, listNode2, 1);
        LinkedList.add(head, listNode3, 2);

        //when
        boolean result1 = LinkedList.contains(head, listNode2);
        boolean result2 = LinkedList.contains(head, new ListNode(4));

        //then
        assertTrue(result1);
        assertFalse(result2);
    }
}

 

과제 3. Stack을 구현하세요.


<Stack>

public class Stack {

    private static final int STACK_SIZE = 100;
    private int top = -1;
    private int[] stack = new int[STACK_SIZE];

    public void push(int data) {
        if (++top == STACK_SIZE) {
            throw new IllegalStateException("stack is full");
        }
        stack[top] = data;
    }

    public int pop() {
        if (top == -1) {
            throw new IllegalStateException("stack is empty.");
        }
        return stack[top--];
    }

    public int getTop() {
        return top;
    }

    public int[] getStack() {
        return stack;
    }
}

 

<테스트>

class StackTest {

    @Test
    public void stackTest() {
        //given
        Stack stack = new Stack();

        //when
        stack.push(1);
        stack.push(2);
        stack.push(3);
        int popData = stack.pop();

        //then
        int top = stack.getTop();
        assertAll(
                () -> assertEquals(2, stack.getStack()[top]),
                () -> assertEquals(3, popData)
        );
    }

    @Test
    public void stackFull() {
        //given
        Stack stack = new Stack();

        //when
        for (int i = 0; i < 100; i++) {
            stack.push(i);
        }

        //then
        assertThrows(IllegalStateException.class,
                () -> stack.push(100));
    }

    @Test
    public void stackEmpty() {
        //given
        Stack stack = new Stack();

        //when
        stack.push(1);
        stack.pop();

        //then
        assertThrows(IllegalStateException.class,
                () -> stack.pop());
    }
}

 

과제 4. 앞서 만든 ListNode를 사용해서 Stack을 구현하세요.


<ListNodeStack>

public class ListNodeStack {

    private ListNode head;

    public ListNodeStack() {
        head = new ListNode();
    }

    public void push(int data) {
        LinkedList.add(head, new ListNode(data), 0);
    }

    public int pop() {
        return LinkedList.remove(head, 0).getData();
    }

    public ListNode getHead() {
        return head;
    }
}

 

<테스트>

class ListNodeStackTest {

    @Test
    public void listNodeStackTest() {
        //given
        ListNodeStack listNodeStack = new ListNodeStack();

        //when
        listNodeStack.push(1);
        listNodeStack.push(2);
        listNodeStack.push(3);
        int data = listNodeStack.pop();

        //then
        assertAll(
                () -> assertEquals(2, listNodeStack.getHead().getNext().getData()),
                () -> assertEquals(1, listNodeStack.getHead().getNext().getNext().getData()),
                () -> assertEquals(3, data)
        );
    }

    @Test
    public void listNodeStackEmpty() {
        //given
        ListNodeStack listNodeStack = new ListNodeStack();

        //when
        listNodeStack.push(1);
        listNodeStack.pop();

        //then
        assertThrows(IllegalStateException.class,
                () -> listNodeStack.pop());
    }
}

 

과제 5. Queue를 구현하세요.


배열 사용

<Queue>

public class Queue {

    private static final int QUEUE_SIZE = 100;
    private int front =-1, rear = -1;
    private int[] queue = new int[QUEUE_SIZE];

    public void offer(int data) {
        if (++rear == QUEUE_SIZE) {
            throw new IllegalStateException("queue is full");
        }
        queue[rear] = data;
    }

    public int poll() {
        if (front == rear) {
            throw new IllegalStateException("queue is empty.");
        }
        return queue[++front];
    }

    public int getFront() {
        return front;
    }

    public int getRear() {
        return rear;
    }

    public int[] getQueue() {
        return queue;
    }
}

 

<테스트>

class QueueTest {

    @Test
    public void queueTest() {
        //given
        Queue queue = new Queue();

        //when
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        int popData = queue.poll();

        //then
        int front = queue.getFront();
        int rear = queue.getRear();
        assertAll(
                () -> assertEquals(2, queue.getQueue()[front + 1]),
                () -> assertEquals(3, queue.getQueue()[rear]),
                () -> assertEquals(1, popData)
        );
    }

    @Test
    public void queueFull() {
        //given
        Queue queue = new Queue();

        //when
        for (int i = 0; i < 100; i++) {
            queue.offer(i);
        }

        //then
        assertThrows(IllegalStateException.class,
                () -> queue.offer(100));
    }

    @Test
    public void queueEmpty() {
        //given
        Queue queue = new Queue();

        //when
        queue.offer(1);
        queue.poll();

        //then
        assertThrows(IllegalStateException.class,
                () -> queue.poll());
    }
}

ListNode 사용

<ListNodeQueue>

public class ListNodeQueue {
    private ListNode head;
    private int size = 0;

    public ListNodeQueue() {
        head = new ListNode();
    }

    public void offer(int data) {
        LinkedList.add(head, new ListNode(data), size++);
    }

    public int poll() {
        return LinkedList.remove(head, 0).getData();
    }

    public ListNode getHead() {
        return head;
    }
}

 

<테스트>

class ListNodeQueueTest {

    @Test
    public void listNodeQueueTest() {
        //given
        ListNodeQueue listNodeQueue = new ListNodeQueue();

        //when
        listNodeQueue.offer(1);
        listNodeQueue.offer(2);
        listNodeQueue.offer(3);
        int data = listNodeQueue.poll();

        //then
        assertAll(
                () -> assertEquals(2, listNodeQueue.getHead().getNext().getData()),
                () -> assertEquals(3, listNodeQueue.getHead().getNext().getNext().getData()),
                () -> assertEquals(1, data)
        );
    }

    @Test
    public void listNodeQueueEmpty() {
        //given
        ListNodeQueue listNodeQueue = new ListNodeQueue();

        //when
        listNodeQueue.offer(1);
        listNodeQueue.poll();

        //then
        assertThrows(IllegalStateException.class,
                () -> listNodeQueue.poll());
    }
}