본문 바로가기

개발 스토리/Java live study

Java 4주차 : 제어문

목표


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

학습할 것


  • 선택문
  • 반복문

과제


과제 0. JUnit 5 학습하세요.


  • 인텔리J, 이클립스, VS Code에서 JUnit5로 테스트 코드 작성하는 방법에 익숙해질 것.

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

  • 깃헙 이슈 1번부터 18번까지 댓글을 순회하며 댓글을 남긴 사용자를 체크할 것.
  • 참여율을 계산하세요. 총 18회에 중에 몇 %를 참여했는지 소수점 두 자리까지 보여줄 것.
  • Github 자바 라이브러리를 사용하면 편리합니다.
  • 깃헙 API를 익명으로 호출하는데 제한이 있기 때문에 본인의 깃헙 프로젝트에 이슈를 만들고 테스트를 하시면 더 자주 테스트할 수 있습니다.

과제 2. LinkedList를 구현하세요

  • LinkedList에 대해 공부하세요.
  • 정수를 저장하는 ListNode 클래스를 구현하세요.
  • ListNode add(ListNode head, ListNode nodeToAdd, int position)를 구현하세요.
  • ListNode remove(ListNode head, int positionToRemove)를 구현하세요.
  • boolean contains(ListNode head, ListNode nodeTocheck)를 구현하세요.

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

  • int 배열을 사용해서 정수를 저장하는 Stack을 구현하세요.
  • void push(int data)를 구현하세요.
  • int pop()을 구현하세요.

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

  • ListNode head를 가지고 있는 ListNodeStack 클래스를 구현하세요.
  • void push(int data)를 구현하세요.
  • int pop()을 구현하세요.

(optional) 과제 5. Queue를 구현하세요.

  • 배열을 사용해서 한번
  • ListNode를 사용해서 한번.

- 제어문

  • 조건에 따라 문장을 건너뛰고, 때로는 같은 문장을 반복해서 수행해야 할 때 프로그램의 흐름을 바꾸는 역할을 하는 문장들을 제어문이라고 한다.
  • 제어문에는 '조건문과 반복문'이 있다.

- 조건문 - if문

  • 'if'의 뜻이 '만일 ~ 이라면 ...'이므로 '만일(if) 조건식이 참(true)이면 괄호{ } 안의 문장들을 수행하라.'라는 의미이다.
  • 조건식에는 boolean 변수 또는 true/false 값을 산출하는 연산식
  • 조건식이 true이면 블록 실행, false이면 실행하지 않는다.

 

예제를 보면 if문 조건식이 참이므로 "합격입니다."가 보인다.

 

- if ~ else문

  • if문의 조건식이 참이 아닐 때 else블럭의 문장을 수행하라는 뜻이다.
  • 조건식의 결과에 따라 두 개의 블록 중 한 블록만 실행 후 전체 if문을 벗어나게 된다.

 

 

 

왼쪽의 두 개의 if문을 if-else문으로 바꾸면 오른쪽과 같다. 왼쪽의 두 조건식은 어느 한쪽이 참이면 다른 한쪽이 거짓인 상반된 관계에 있기 때문에 오른쪽과 같이 if-else문으로 바꿀 수 있다.

 

- if - else if문

  • if - else if문은 처리해야 할 경우의 수가 셋 이상인 경우에 한 문장에 여러 개의 조건식을 쓸 수 있는 'if - else if'문을 사용하면 된다.
  • 첫 번째 조건식부터 순서대로 평가해서 결과가 참인 조건식을 만나면, 해당 블럭{ }만 수행하고 'if - else if'문 전체를 벗어난다.
  • 만일 결과가 참인 조건식이 하나도 없으면, 마지막에 있는 else블럭의 문장들이 수행된다. 그리고 else블럭은 생략이 가능하다.
  • else블럭이 생략되었을 때는 if - else if문의 어떤 블럭도 수행되지 않을 수 있다.
if (조건식1) {

	// 조건식1의 연산결과가 참일 때 수행될 문장들을 적는다.  
    
} else if (조건식2) {

	// 조건식2의 연산결과가 참일 때 수행될 문장들을 적는다.
    
} else if (조건식3) {

	// 조건식3의 연산결과가 참일 때 수행될 문장들을 적는다.
    
} else {

	// 위의 어느 조건식도 만족하지 않을 때 수행될 문장들을 적는다.
    
}

 

- 중첩 if문

  • if문의 블럭 내에 또 다른 if문을 포함시킨 것.
  • 중첩의 횟수에는 거의 제한이 없다.
if (조건식1) {

	// 조건식1의 연산결과가 true일 때 수행될 문장들을 적는다.
    
    if (조건식2) {
    	
        // 조건식1, 조건식2 모두 true일 때 수행될 문장들
        
    } else {
    	
        // 조건식1이 true이고, 조건식2가 false일 때 수행되는 문장들
        
    }
} else {

	// 조건식1이 false일 때 수행되는 문장들
    
}

 

- switch문

  • 단 하나의 조건식으로 많은 경우의 수를 처리한다.
  • switch문의 조건식 결과는 정수 또는 문자열이어야 한다.
  • case문의 값은 정수 상수만 가능하며, 중복되지 않아야 한다.
switch (조건식) {

	case 값1: 
    
    	// 조건식의 결과가 값1과 같을 경우 수행될 문장들
      	// ...
        break; // break는 조건에 해당하는 실행문을 작동시키고 switch문을 종료한다.
	
   	case 값2:
    
     	// 조건식의 결과가 값2과 같을 경우 수행될 문장들
      	// ...
		break;
        
	default:
    
    	// 조건식의 결과와 일치하는 case문이 없을 때 수행될 문장들
        // ...
        
}

 

 

- for문

  • for문은 '초기화', '조건식', '증감식', '블럭 { }', 모두 4 부분으로 이루어져 있으며, 조건식이 참인 동안 블럭 내의 문장들을 반복하다 거짓이 되면 반복문을 벗어난다.
for( 초기화; 조건식; 증감식) {
	// 조건식이 참(true)인 동안 수행될 문장들을 적는다.
}    

 

  • for문은 제일 먼저 초기화가 수행되고, 그 이후부터는 조건식이 참 인동 안 조건식 -> 수행될 문장 -> 증감식의 순서대로 계속 반복된다. 그러다가 조건식이 거짓이 되면, for문 전체를 빠져나가게 된다.

1. 초기화

  • 반복문에 사용될 변수를 초기화하는 부분이며 처음에 한 번만 수행된다. 보통 변수 하나로 for문을 제어하지만, 둘 이상의 변수가 필요할 때는 콤마 ' , '를 구분자로 변수를 초기 화하면 된다.
  • ex) for(int i=1; i<=10; i++) { . . . }

2. 조건식

  • 조건식의 값이 참이면 반복을 계속하고, 거짓이면 반복을 중단하고 for문을 벗어난다.
  • ex) for(int i=1i<=10; i++) { . . . }

3. 증감식

  • 반복문을 제어하는 변수의 값을 증가 또는 감소시키는 식이다.
  • ex) for(int i=1i<=10i++) { . . . }   // 1부터 10까지 1씩 증가

4. 예제

for (int i = 0; i < 5; i++) {

	for (int j = 0; j <= i; j++) {
    
		System.out.print("*");
        
	}
    
	System.out.println();
    
}
        
// 결과
*
**
***
****
*****

 

 

5. 향상된 for문

  • JDK1.5부터 배열과 컬렉션에 저장된 요소에 접근할 때 기존보다 편리한 방법으로 처리할 수 있도록 for문의 새로운 문법이 추가되었다.
  • 타입은 배열 또는 컬렉션의 요소의 타입이어야한다.
  • 배열 또는 컬렉션에 저장된 값이 매 반복마다 하나씩 순서대로 읽혀서 변수에 저장된다.
for ( 타입 변수명 : 배열 또는 컬렉션 ) {
	// 반복할 문장
}

 

6. 예제

// 일반적인 for문
for (int i = 0; i < arr.length; i++) {
	System.out.println(arr[i]);
}

---------------------------------------------

// 향상된 for문
for(int tmp : arr) {
	System.out.println(tmp);
}

- while문

  • while문은 먼저 조건식을 평가해서 조건식이 거짓이면 문장 전체를 벗어나고, 참이면 블럭{ } 내의 문장을 수행하고 다시 조건식으로 돌아간다. 조건식이 거짓이 될 때까지 이 과정이 계속 반복된다.
while (조건식) {
	
    // 수행될 문장
    
}

 

 

  • for문과 while문을 비교하면 아래와 같다.
// 초기화, 조건식, 증감식
for(int i = 0; i <= 10; i++) {
	System.out.println(i);
}

------------------------------------------------

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

 

- do - while문

  • do - while문은 while문의 변형으로 기본적인 구조는 while문과 같으나 조건식과 블럭{ }의 순서를 바꿔놓은 것이다.
  • while문과 반대로 블럭{ }을 먼저 수행한 후에 조건식을 평가한다.
  • while문은 조건식의 결과에 따라 블럭{ }이 한 번도 수행되지 않을 수 있지만, do - while문은 최고한 한 번은 수행될 것을 보장한다.
do {
	// 조건식의 연산결과가 참일 때 수행될 문장들을 적는다.
} while (조건식);	// 끝에 ';'을 잊지 않도록 주의

 

 

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

1. JUnit5란?

  • 이전 버전의 JUnit과 다르게 JUnit5는 세 가지 하위 프로젝트의 여러 모듈로 구성됩니다.

출처 :https://beomseok95.tistory.com/303#JUnit_5%EB%9E%80___

  • JUnit5 = JUnit Platform + JUnit Jupiter + Junit Vintage
  • JUnit Platform : 테스트를 발견하고 테스트 계획을 생성하는 TestEngine 인터페이스를 가지고 있습니다. Platform은 TestEngine을 통해서 테스트를 발견하고, 실행하고, 결과를 보고합니다.
  • JUnit Jupiter : TestEngine의 실제 구현체는 별도 모듈입니다. 모듈 중 하나가 jupiter-engine입니다. 이 모듈은 jupiter-api를 사용해서 작성한 테스트 코드를 발견하고 실행합니다. Jupiter API는 JUnit5에 새롭게 추가된 테스트 코드용 API로서, 개발자는 Jupiter API를 사용해서 테스트 코드를 작성할 수 있습니다.
  • JUnit Vintage: 기존에 JUnit4 버전으로 작성한 테스트 코드를 실행할 때에는 vintage-engine모듈을 사용합니다.
  • JUnit5는 런타임 시에 Java8 이상이 필요합니다.

2. Maven Dependencies

JUnit5 설정은 pom.xml에 다음 종속성을 추가합니다.

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.1.0</version>
    <scope>test</scope>
</dependency>

 

3. JUnit Jupiter

  • 이 모듈에는 JUnit5에서 테스트를 작성하기 위한 새로운 프로그래밍 및 확장 모델이 포함되어 있습니다. JUnit4와 비교 한 새로운 어노테이션은 다음과 같습니다.
어노테이션 내용
@TestFactory 동적 테스트를 위한 테스트 팩토리임을 나타냅니다.
@DisplayName 테스트 클래스 또는 테스트 메서드에 대한 사용자 지정 표시 이름을 정의합니다.
@Nested 주석이 달린 클래스는 정적이 아닌 중첩 테스트 클래스임을 나타냅니다.
@Tag 클래스 또는 메서드 레벨에서 필터링 테스트를 위한 태그
@ExtendWith 확장을 선언적으로 등록하는데 사용합니다.
@BeforeEach 테스트 메소드 이전에 실행됨을 나타냅니다.
@AfterEach 테스트 메서드 이후에 실행됨을 나타냅니다.
@BeforeAll 현재 클래스의 모든 테스트 메서드보다 먼저 실행됨을 나타냅니다.
@AfterAll 현재 클래스의 모든 테스트 메서드 후에 주석이 추가 된 메서드가 실행됨을 나타냅니다.
@Disable 테스트 클래스 또는 메서드를 비활성화하는 데 사용됩니다. (이전엔 @Ignore)

 

4.1. @BeforeAll 및 @BeforeEach

 

주요 테스트 케이스 전에 실행되는 간단한 코드의 예입니다.

    @BeforeAll
    static void setup() {
        log.info("@BeforeAll - executes once before all test methods in this class");
    }

    @BeforeEach
    void init() {
        log.info("@BeforeEach - executes before each test method in this class");
    }

중요한 점은 @BeforeAll 어노테이션이 있는 메서드가 static 이어야 한다는 것입니다. 그렇지 않으면 코드가 컴파일되지 않습니다.

 

4.2. @DisplayName 및 @Disabled

@DisplayName("Single test successful")
@Test
void testSingleSuccessTest() {
    log.info("Success");
}

@Test
@Disabled("Not implemented yet")
void testShowSomething() {
}

 

@DisplayName으로 표시 이름을 변경하고 @Disabled로 메서드를 비활성화할 수 있습니다.

 

4.3. @AfterEach 및 @AfterAll

테스트 실행 후 작업에 연결된 메서드에 대해 살펴보겠습니다.

@AfterEach
void tearDown() {
    log.info("@AfterEach - executed after each test method.");
}

@AfterAll
static void done() {
    log.info("@AfterAll - executed after all test methods.");
}

@AfterAll이 있는 메서드도 static 메서드여야 합니다.

 

5.1. Assertions

Assertions가 org.junit.jupiter.api.Assertions로 이동되었으며 크게 개선되었다. 이제 Assertions에서 람다를 사용할 수 있다.

 

@Test
void lambdaExpressions() {
	assertTrue(Stream.of(1, 2, 3)
    	.stream()
        .mapToInt(i -> i)
        .sum() > 5, () -> "Sum should be greater than 5");
}

 

MultipleFailuresError로 그룹 내에서 실패한 주장을 보고하는 assertAll()을 사용하여 주장을 그룹화할 수도 있습니다.

 @Test
 void groupAssertions() {
     int[] numbers = {0, 1, 2, 3, 4};
     assertAll("numbers",
         () -> assertEquals(numbers[0], 1),
         () -> assertEquals(numbers[3], 3),
         () -> assertEquals(numbers[4], 1)
     );
 }

즉, 오류의 정확한 위치를 정확히 찾을 수 있으므로 더 복잡한 단언을 하는 것이 더 안전합니다.

 

5.2. 가정

특정 조건이 충족되는 경우에만 테스트를 실행하는데 가정이 사용됩니다. 이는 일반적으로 테스트를 제대로 실행하는데 필요하지만 테스트 중인 항목과 직접 관련이 없는 외부조건에 사용됩니다.

assumeTrue(), assumeFalse(), assumingThat()을 사용하여 가정을 선언할 수 있습니다.

 

@Test
void trueAssumpion() {
	assumeTrue(5 > 1);
    assertEquals(5 + 2, 7);
}

@Test
void falseAssumption() {
	assumeFalse(5 < 1);
    assertEquals(5 + 2, 7);
}

@Test
void assumptionThat() {
	String someString = "Just a string";
    assumingThat(
    	sumeString.equals("Just a string"),
        () -> assertEquals(2 + 2, 4)
	);
}

가정이 실패하면 TestAbortedException이 발생하고 테스트를 건너뜁니다. 가정은 람다 식도 이해합니다.

 

6. 예외 테스트

JUnit5에는 두 가지 예외 테스트 방법이 있습니다. 둘 다 assertThrows() 메서드를 사용하여 구현할 수 있습니다.

 

    @Test
    void shouldThrowException() {
        Throwable exception = assertThrows(UnsupportedOperationException.class, () -> {
            throw new UnsupportedOperationException("Not supported");
        });
        assertEquals(exception.getMessage(), "Not supported");
    }

    @Test
    void assertThrowsException() {
        String str = null;
        assertThrows(IllegalArgumentException.class, () -> {
            Integer.valueOf(str);
        });
    }

첫 번째 예제는 throw 된 예외의 세부 정보를 확인하는 데 사용되며 두 번째 예제는 예외 유형의 유효성을 검사합니다.

 

7. Test Suites

JUnit5의 새로운 기능을 계속하기 위해 Test Suites에서 여러 테스트 클래스를 집계하는 개념을 파악하여 함께 실행할 수 있습니다. JUnit5는 @SelectPackages 및 @SelectClasses라는 두 가지 어노테이션을 제공하여 Test Suites를 만듭니다.

이 초기 단계에서 대부분의 IDE는 이러한 기능을 지원하지 않습니다.

 

@RunWith(JUnitPlatform.class)
@SelectPackages("com.baeldung")
public class AllUnitTest {}

@SelectPackages는 Test Suites를 실행할 때 선택할 패키지 이름을 지정하는 데 사용됩니다. 이 예에서는 모든 테스트를 실행합니다.

 

@RunWith(JUnitPlatform.class)
@SelectClasses({AssertionTest.class, AssumptionTest.class, ExceptionTest.class})
public class AllUnitTest {}

@SelectClasses는 Test Suites를 실행할 때 선택할 클래스를 지정하는 데 사용됩니다. 예를 들어, 위의 클래스는 세 개의 테스트 클래스를 포함하는 suites를 만듭니다.

 

8. 동적 테스트

JUnit5 동적 테스트 기능으로, 런타임에 생성된 테스트 케이스를 선언하고 실행할 수 있습니다. 컴파일 시간에 고정된 수의 테스트 케이스를 정의하는 정적 테스트와는 달리 동적 테스트를 사용하면 런타임에서 테스트 케이스를 동적으로 정의할 수 있습니다.

@TestFactory로 주석이 달린 팩토리 메서드로 동적 테스트를 생성할 수 있습니다.

 

    @TestFactory
    public Stream<DynamicTest> translateDynamicTestsFromStream() {
        return in.stream()
                .map(word ->
                        DynamicTest.dynamicTest("Test translate " + word, () -> {
                            int id = in.indexOf(word);
                            assertEquals(out.get(id), translate(word));
                        })
                );
    }

이 예제는 in과 out이라는 두 개의 ArrayList를 사용하여 단어를 번역하려고 합니다. 팩토리 메서드는 Stream, Collection, Iterable 또는 Iteraotr를 반환해야 합니다. 

@TestFactory 메서드는 private 또는 static이 아니어야 합니다.

 

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

  • 배열은 가장 기본적인 형태의 자료구조로 구조가 간단하며 사용하기 쉽고 데이터를 읽어 오는데 걸리는 시간이 가장 빠르다는 장점을 가지고 있지만 크기를 변경할 수없고 비순차적인 데이터의 추가 또는 삭제에 시간이 많이걸린다는 단점이 있다. 이러한 배열의 단점을 보완하기 위해서 LinkedList라는 자료구조가 고안되었다.
  • 배열은 모든 데이터가 연속적으로 존재하지만 LinkedList는 불연속적으로 존재하는 데이터를 서로 연결한 형태로 구성되어 있다.

출처 : https://www.geeksforgeeks.org/difference-between-a-static-queue-and-a-singly-linked-list/

  • 위의 그림을 보면 LinkedList의 각 요소(node)들은 자신과 연결된 다음 요소에 대한 참조(주소값)와 데이터로 구성되어 있다.

 

생성자 또는 메서드 설 명
LinkedList() LinkedList객체를 생성
LinkedList(Collection c) 주어진 컬렉션을 포함하는 LinkedList객체를 생성
boolean add(Object o) 지정된 객체(o)를 LinkedList의 끝에 추가. 저장에 성공하면 true, 실패하면 false
void add(int index, Object element) 지정된 위치(index)에 객체(element)를 추가
boolean addAll(Collection c) 주어진 컬렉션에 포함된 모든 요소를 LinkedList의 끝에 추가한다.
성공하면 true, 실패하면 false
boolean addAll(int index, Collection c) 지정된 위치(index)에 주어진 컬렉션에 포함된 모든 요소를 추가.
성공하면 true, 실패하면 false
void clear() LinkedList의 모든 요소를 삭제
boolean contains(Object o) 지정된 객체가 LinkedList에 포함되었는지 알려줌
boolean containsAll(Collection c) 지정된 컬렉션의 모든 요소가 포함되었는지 알려줌
Object get(int index) 지정된 위치(index)의 객체를 반환
int indexOf(Object o) 지정된 객체가 저장된 위치를 반환
boolean isEmpty() LinkedList가 비어있는지 알려준다. 비어있으면 true
Iterator iterator() Iterator를 반환한다.
int lastIndexOf(Object o) 지정된 객체의 위치를 반환(끝부터 역순검색)
ListIerator listIterator() ListIterator를 반환한다.
ListIerator listIterator(int index) 지정된 위치에서부터 시작하는 ListIterator를 반환
Object remove(int index) 지정된 위치의 객체를 LinkedList에서 제거
boolean remove(Object o) 지정된 객체를 LinkedList에서 제거. 성공하면 true, 실패하면 false
boolean removeAll(Collection c) 지정된 컬렉션의 요소와 일치하는 요소를 모두 삭제
boolean retainAll(Collection c) 지정된 컬렉션의 모든 요소가 포함되어 있는지 확인
Object set(int index, Object element) 지정된 위치의 객체를 주어진 객체로 바꿈
int size() LinkedList에 저장된 객체의 수를 반환
List subList(int fromIndex, int toIndex) LinkedList의 일부를 List로 반환
Object[] toArray() LinkedList에 저장된 객체를 배열로 반환
Object element() LinkedList의 첫 번째 요소를 반환
Object[] toArray(Object[] a) LinkedList에 저장된 객체를 주어진 배열에 저장하여 반환
boolean offer(Object o) 지정된 객체를 LinkedList의 끝에 추가. 성공하면 true, 실패하면 false
Object peek() LinkedList의 첫 번째 요소를 반환
Object poll() LinkedList의 첫 번째 요소를 반환. LinkedList에서는 제거된다.
Object remove() LinkedList의 첫 번째 요소를 제거
void addFirst(Object o) LinkedList의 맨 앞에 객체를 추가
void addLast(Object o) LinkedList의 맨 끝에 객체를 추가
Iterator descendingIterator() 역순으로 조회하기 위한 DescendingIterator를 반환
Object getFirst() LinkedList의 첫 번째 요소를 반환
Object getLast() LinkedList의 마지막 요소를 반환
boolean offerFirst(Object o) LinkedList의 맨 앞에 객체를 추가. 성공하면 true
boolean offerLast(Object o) LinkedList의 맨 끝에 객체를 추가. 성공하면 true
Object peekFirst() LinkedList의 첫번째 요소를 반환
Object peekLast() LinkedList의 마지막 요소를 반환
Object pollFirst() LinkedList의 첫번째 요소를 반환하면서 제거
Object pollLast() LinkedList의 마지막 요소를 반환하면서 제거
Object pop() removeFirst()와 동일
void push(Object o) addFirst()와 동일
Object removeFirst() LinkedList의 첫번째 요소를 제거
Object removeLast() LinkedList의 마지막 요소를 제거
boolean removeFirstOccurrence(Object o) LinkedList에서 첫번째로 일치하는 객체를 제거
boolean removeLastOccurrence(Object o) LinkedList에서 마지막으로 일치하는 객체를 제거

 

- LinkedList 구현

public class ListNode {

    private int element;

    private ListNode next = null;

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

    public ListNode add(ListNode input) {

        //첫번째 노드인 경우
        if (this.next == null) {
            this.next = input;
            return this;
        }

        // 첫번째 노드가 아닌경우
        ListNode nextNode = this.next;
        while (nextNode.next != null) {
            nextNode = nextNode.next;
        }

        nextNode.next = input;
        return this;
    }

    public ListNode add(ListNode head, ListNode nodeToAdd, int position) {
        if (position == 0) {
            return addFirst(head, nodeToAdd);
        }

        while (--position > 0) {
            if (head.next == null) {
                break;
            }
            head = head.next;
        }

        nodeToAdd.next = head.next;
        head.next = nodeToAdd;

        return head;
    }

    public ListNode addFirst(ListNode head, ListNode nodeToAdd) {

        if (head == null) {
            return nodeToAdd;
        }
        ListNode node = nodeToAdd;
        node.next = head;
        head = node;
        return head;
    }

    public ListNode remove(ListNode head, int positionToRemove) {

        if(positionToRemove == 0) {
            head = head.next;
            return head;
        }

        ListNode node = head;
        positionToRemove -= 1;
        while (positionToRemove-- > 0) {
            node = node.next;
        }
        node.next = node.next.next;

        return head;
    }

    public boolean contains(ListNode head, ListNode nodeTocheck) {

        while (head != null) {
            if (head.element == nodeTocheck.element) {
                return true;
            }
            head = head.next;

        }
        return false;
    }

    public void printAllNode() {
        ListNode node = this;
        while (node != null) {
            System.out.println("this.element = " + node.element);
            node = node.next;
        }
    }
}

 

- Test

import org.junit.jupiter.api.Test;


class ListNodeTest {

    @Test
    public void addTest() {

        ListNode node = new ListNode(10);
        node.add(new ListNode(20));
        node.add(new ListNode(30));
        node.add(new ListNode(40));
        node.add(new ListNode(50));

        node.add(node, new ListNode(200), 3);

        // 첫 번째에 추가하는 경우
        node = node.add(node, new ListNode(100), 0);
        node.add(new ListNode(400));

        node.printAllNode();
    }

    @Test
    public void removeTests() {
        ListNode node = new ListNode(10);
        node.add(new ListNode(20));
        node.add(new ListNode(30));
        node.add(new ListNode(40));
        node.add(new ListNode(50));

        node = node.remove(node, 0);
        node.printAllNode();
    }

    @Test
    public void containTests() {
        ListNode node = new ListNode(10);
        node.add(new ListNode(20));
        node.add(new ListNode(30));
        node.add(new ListNode(40));
        node.add(new ListNode(50));

        System.out.println(node.contains(node, new ListNode(50)));
    }



}

 

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

public class ArrayStack {

    private int top;
    private int maxSize;
    private int[] stackArray;

    public ArrayStack(int maxSize) {
        this.maxSize = maxSize;
        this.stackArray = new int[maxSize];
        this.top = -1;
    }

    public void push(int input) {

        stackArray[++top] = input;
    }

    public int peek() {
        if (empty()) {
            throw new ArrayIndexOutOfBoundsException(top);
        }

        return stackArray[top];
    }

    public int pop() {
        int num = peek();
        top--;

        return num;
    }

    public boolean empty() {
        return top == -1;
    }
}

-Test

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class ArrayStackTest {

    @Test
    public void pushTest() {
        ArrayStack stack = new ArrayStack(5);
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5);


        for (int i = 0; i < 5; i++) {
            System.out.println("stack.pop() = " + stack.pop());
        }
    }

}

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

 

public class ListNodeStack {

    private ListNode head;

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

    public void push(int data) {
        ListNode node = new ListNode(data);
        this.head = node.addFirst(head ,node);
    }

    public int pop() {

        int num = head.getFirst();
        head = head.remove(head,0);
        return num;
    }

}

- Test

    @Test
    public void listNodeTest() {
        ListNodeStack stack = new ListNodeStack();

        stack.push(2);
        stack.push(3);

        System.out.println("stack.pop() = " + stack.pop());
        System.out.println("stack.pop() = " + stack.pop());
    }

Test 결과

 

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

  • 배열을 사용해서 한번
public class ArrayQueue {

    private int front;
    private int rear;
    private int maxSize;
    private int[] queueArray;

    public ArrayQueue(int maxSize) {
        this.front = 0;
        this.rear = -1;
        this.maxSize = maxSize;
        this.queueArray = new int[maxSize];
    }

    public void insert(int item) {
        queueArray[++rear] = item;
    }

    public int peek() {
        return queueArray[front];
    }

    public int remove() {
        int item = peek();
        front++;
        return item;
    }

}

- Test

    @Test
    public void queueTests() {
        ArrayQueue q = new ArrayQueue(5);
        q.insert(1);
        q.insert(2);
        q.insert(3);
        q.insert(4);
        q.insert(5);

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

 

 

 

  • ListNode를 사용해서 한번.
public class ListNodeQueue {

    private ListNode head = null;

    public void add(int data) {
        if(head == null) {
            head = new ListNode(data);
        } else {
            ListNode node = new ListNode(data);
            head = head.add(node);
        }

    }

    public int poll() {
        int num = head.getFirst();
        head = head.remove(head, 0);
        return num;
    }

}

- Test

    @Test
    public void queueListTest() {
        ListNodeQueue q = new ListNodeQueue();
        q.add(1);
        q.add(2);
        q.add(3);
        q.add(4);
        q.add(5);

        for (int i = 0; i < 5; i++) {
            System.out.println(q.poll());

        }
    }

 

 

- 참고 자료

www.baeldung.com/junit-5

beomseok95.tistory.com/303#JUnit_5%EB%9E%80

hyeonstorage.tistory.com/262

hyeonstorage.tistory.com/263