백기선 자바 스터디 1기 4주차

2022. 4. 15. 15:02Java/java-live-study

728x90
반응형

목표

자바가 제공하는 제어문(Control Statement)을 학습하세요

학습할 것

  • 선택문
  • 반복문

과제

  • JUnit 5를 학습하세요
  • live-study 대시 보드를 만드는 코드를 작성하세요
  • LinkedList를 구현하세요
  • Stack을 구현하세요
  • 앞서 만든 ListNode를 사용해서 Stack을 구현하세요
  • Queue를 구현하세요

선택문(Decision-making Statement)

if

가장 기본적인 선택문(조건문)으로 소괄호 안의 조건식이 참이면 중괄호 안의 구문을 실행한다.

//if문의 기본적인 형태
if (조건식) {
	//구문
}

//if-else 형태
if (조건식1) {
	//조건식1이 참이면 실행
}
else if(조건식2) {
	//조건식1이 거짓이고 조건식2가 참이면 실행
}
else {
	//조건식1, 2 모두 거짓이면 실행
}

자바에서는 조건식에 무조건 boolean 값이 들어가야한다. (0, 1과 같은 숫자 불가)

 

switch

다중 if문 대신 사용할 수 있는 문법으로 소괄호 안의 조건식과 같은 값의 case 문부터 실행된다. (break 문을 적절히 사용해야함)

  • 정수 값이나 열거된 값 또는 문자, 문자열만을 사용할 수 있다.
public class ControlStatementTest {
    public static void main(String[] args) {
        int num = 1;
        switch (num) {
            case 1:
                System.out.println(1);
            case 2:
                System.out.println(2);
            case 3:
                System.out.println(3);
                break; //break 문을 만나 1 2 3까지 출력
            case 4:
                System.out.println(4);
            default:
                System.out.println("default");
        }
    }
}

반복문(Looping Statment)

조건식이 참이면 구문 안의 명령을 반복하여 수행한다. for, for-each, while, do-while 문이 있다.

 

for

for (초기값; 조건; 방향&간격) {
	//statement
}

for-each

for (<type> <instance>: <type-iterable>) {
	//statement
}

while

while (expression) {
	//statement
}

do-while

do { 
	//statement
} while (expression)

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

  • 인틸리제이, 이클립스, VS Code에서 JUnit 5로 테스트 코드 작성하느 방법에 익숙해 질 것.
  • 더 자바, 테스트 강의 참고

JUnit 5 는 자바 개발자가 가장 많이 사용하는 테스팅 프레임워크이다. JAVA 버전 8 이상을 필요로한다.

 

JUnit 5 구성(세부 모듈)

출처 : https://www.inflearn.com/course/the-java-application-test/dashboard

JUnit Platform

테스트를 실행해주는 런처를 제공한다. TestEngine API 제공.

 

Jupiter

TestEngine API 구현체로 JUnit 5 를 제공한다.

 

Vintage

JUnit 4와 3을 지원하는 TestEngine 구현체이다.

 

JUnit 기본 어노테이션

@Test 테스트 메소드임을 선언 JUnit Platform으로 실행된다.
@BeforeAll 테스트 클래스 안에 있는 테스트 메소드가 실행 전에 딱 한번 실행된다.
@AfterAll 테스트 클래스 안에 있는 테스트 메소드가 종료 후에 딱 한번 실행된다.
@BeforeEach 테스트 클래스 안의 각 테스트 메소드의 실행 전에 실행된다.
@AfterEach 테스트 클래스 안의 각 테스트 메소드의 종료 후에 실행된다.
@Disabled 이 테스트를 사용하지 않음을 표시한다.
@DisplayNameGeneration 메소드와 클래스 레퍼런스를 사용하여 테스트 이름을 표기하는 전략 설정
@DisplayName 테스트 이름을 지정하는 어노테이션

 

Assertion

org.junit.jupiter.api.Assertions.*

assertEqulas(expected, actual) 실제 값이 기대한 값과 같은지 확인
assertNotNull(actual) 값이 null이 아닌지 확인
assertTrue(boolean) 다음 조건이 참(true)인지 확인
assertAll(executables...) 모든 확인 구문 확인
assertThrows(expectedType, executable) 예외 발생 확인
assertTimeout(duration, executable) 특정 시간 안에 실행이 완료되는지 확인

마지막 매개변수인 Supplier<String> 타입의 인스턴스를 람다 형태로 제공할 수 있다.

  • 복잡한 메시지를 생성해야 하는 경우 사용하면 실패한 경우에만 해당 메시지를 만들게 할 수 있다.

 

JUnit 필요한거 추가하기


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

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

소스코드

import org.kohsuke.github.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LiveStudyDashBoard {

    final String repo = "whiteship/live-study"; //레포지토리 명
    final String token = "(Github token)"; //토큰 값

    List<GHIssue> issues; //레포지토리에 있는 이슈들 저장
    Map<String, boolean[]> participant; //참여자, 몇 주차(인덱스 역순)에 참여했는지 배열로 저장

    public LiveStudyDashBoard() throws IOException {
        this.issues = GitHub.connectUsingOAuth(token).getRepository(repo).getIssues(GHIssueState.ALL);
        this.participant = savePartAndPartWeek();
    }

    public Map<String, boolean[]> savePartAndPartWeek() throws IOException {
        Map<String, boolean[]> hm = new HashMap<>();

        for (int i = 0; i < issues.size(); i++) {
            for (GHIssueComment comment : issues.get(i).getComments()) {
                String userLogin = comment.getUser().getLogin();
                if (hm.containsKey(userLogin)) {
                    boolean[] weeks = hm.get(userLogin);
                    weeks[i] = true;
                    hm.put(userLogin, weeks);
                }
                else {
                    boolean[] newWeeks = new boolean[issues.size()];
                    newWeeks[i] = true;
                    hm.put(userLogin, newWeeks);
                }
            }
        }
        return hm;
    }

    public String drawFirstRow() {
        String firstRow = "|";
        for (int i = 0; i < issues.size(); i++) {
            firstRow += "|" + (i+1) + "주차";
        }
        firstRow += "|출석률|\n|-";
        for (int i = 0; i < issues.size(); i++) {
            firstRow += "|-";
        }
        firstRow += "|-|\n";
        return firstRow;
    }

    public String checkParticipationWeeksPerUser(String userLogin) {
        boolean[] weeks = participant.get(userLogin);
        String checkWeeks = "";
        for (boolean isPartWeek : weeks) {
            if (isPartWeek)
                checkWeeks = "O|" + checkWeeks;
            else
                checkWeeks = "X|" + checkWeeks;
        }
        checkWeeks = "|" + checkWeeks;
        return checkWeeks;
    }

    public double calcParticipationRatio(String userLogin) {
        boolean[] weeks = participant.get(userLogin);
        double partCnt = 0;
        for (boolean isPartWeek : weeks) {
            if (isPartWeek)
                partCnt++;
        }
        return Math.round(partCnt / issues.size() * 10000) / 100D;
    }

    public String makeDashBoard() {
        String dashBoard = drawFirstRow();
        for (String userLogin : participant.keySet()) {
            dashBoard += "|"
                    + userLogin
                    + checkParticipationWeeksPerUser(userLogin)
                    + calcParticipationRatio(userLogin)
                    + "|\n";
        }
        return dashBoard;
    }

    public static void main(String[] args) throws IOException {
        LiveStudyDashBoard liveStudyDashBoard = new LiveStudyDashBoard();
        System.out.println(liveStudyDashBoard.makeDashBoard());
    }
}

 

생성된 문자열(Github 마크다운)

||1주차|2주차|3주차|4주차|5주차|6주차|7주차|8주차|9주차|10주차|11주차|12주차|13주차|14주차|15주차|16주차|17주차|18주차|출석률|
|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|
|kimzerovirus|X|X|X|X|X|O|X|X|X|X|X|X|X|X|X|X|X|X|5.56|
|KwangJongJeon|O|O|O|X|O|O|O|O|O|O|O|O|X|X|X|X|X|X|61.11|
|jessi68|O|O|X|X|X|X|X|X|X|X|X|X|X|X|X|X|X|X|11.11|
|ufonetcom|O|O|O|O|O|X|X|X|X|X|X|X|X|X|X|X|X|X|27.78|
|JIN-096|O|O|O|O|O|O|O|O|O|O|O|O|X|X|X|X|X|X|66.67|
|ssonsh|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|O|X|88.89|
|Ohzzi|O|O|O|O|O|O|O|O|O|O|O|O|O|X|X|X|X|X|72.22|
|dongsub-joung|O|O|X|X|X|X|X|X|X|X|X|X|X|X|X|X|X|X|11.11|
|moo1o|O|X|X|X|X|X|X|X|X|X|X|X|X|X|X|X|X|X|5.56|
|Azderica|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|X|X|83.33|
|jymaeng95|O|O|O|O|O|O|O|O|O|O|O|O|O|O|O|X|X|X|83.33|

. . . . . .(이하 생략) . . . . . .

 

결과

생성한 문자열(마크다운)으로 Github에 표 생성


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

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

LinkedList란?

 

ListNode 구현

 

소스코드

public class ListNode {

    ListNode nextNode;
    int data;

    public ListNode() {}

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

    public static ListNode add(ListNode head, ListNode nodeToAdd, int position) {
        ListNode tmp = head;

        for (int i = 1; i < position; i++) {
            tmp = tmp.nextNode;
            if (tmp == null) {
                System.out.println("범위를 초과하였습니다.");
                return head;
            }
        }

        tmp.nextNode = nodeToAdd;

        return head;
    }

    public static ListNode remove(ListNode head, int positionToRemove) {
        ListNode tmp = head;
        ListNode pre = null;
        for (int i = 1; i <=positionToRemove; i++) {
            pre = tmp;
            tmp = tmp.nextNode;

            if (tmp == null) {
                System.out.println("범위를 초과하였습니다.");
                return head;
            }
        }

        pre.nextNode = tmp.nextNode;
        tmp = null;

        return head;
    }

    public static boolean contains(ListNode head, ListNode nodeToCheck) {
        boolean isContain = false;

        while (head != null) {
            if (head == nodeToCheck) {
                isContain = true;
                break;
            }
            head = head.nextNode;
        }

        return isContain;
    }
}

 

테스트

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

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

class ListNodeTest {

    @Test
    @DisplayName("add 함수 테스트")
    void add() {
        ListNode head = new ListNode();
        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(3);

        ListNode.add(head, node1, 1);
        ListNode.add(head, node2, 2);

        assertTrue(ListNode.contains(head, node1));
        assertTrue(ListNode.contains(head, node2));
        assertFalse(ListNode.contains(head, node3));
    }

    @Test
    @DisplayName("remove 함수 테스트")
    void remove() {
        ListNode head = new ListNode();
        ListNode node1 = new ListNode(1);

        ListNode.add(head, node1, 1);
        assertTrue(ListNode.contains(head,node1));

        ListNode.remove(head,1);
        assertFalse(ListNode.contains(head,node1));
    }

    @Test
    @DisplayName("contains 함수 테스트")
    void contains() {
        ListNode head = new ListNode();
        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(3);

        ListNode.add(head, node1, 1);
        ListNode.add(head, node2, 2);

        assertTrue(ListNode.contains(head, node1));
        assertTrue(ListNode.contains(head, node2));
        assertFalse(ListNode.contains(head, node3));
    }
}

 


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

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

소스코드

public class Stack {

    public int top = -1;
    public int size;
    public int[] arr;

    public Stack(int size) {
        this.size = size;
        this.arr = new int[size];
    }

    public void push(int data) {
        if (isFull()) {
            System.out.println("stack이 가득 찼습니다");
            return ;
        }
        this.arr[++this.top] = data;
    }

    public int pop() {
        if (isEmpty()) {
            //에러처리 다시 짜기
            System.out.println("stack이 비어있습니다.");
        }
        return this.arr[this.top--];
    }

    public boolean isFull() {
        if (this.top == this.size-1)
            return true;
        return false;
    }

    public boolean isEmpty() {
        if (this.top == -1)
            return true;
        return false;
    }
}

 

테스트

import org.junit.jupiter.api.Test;

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

class StackTest {

    @Test
    void push() {
        Stack s = new Stack(5);

        for (int i=0; i<5; i++) {
            s.push(i);
        }

        assertEquals(s.top, 4);
    }

    @Test
    void pop() {
        Stack s = new Stack(5);

        for (int i=0; i<5; i++) {
            s.push(i);
        }

        assertEquals(s.pop(), 4);
    }
}

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

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

소스코드

public class ListNodeStack {

    public ListNode head;

    public void push(int data) {
        ListNode newNode = new ListNode(data);

        if (head == null) {
            head = newNode;
            return;
        }
        
        ListNode tmp = head;
        while (tmp.nextNode != null)
            tmp = tmp.nextNode;

        tmp.nextNode = newNode;
    }

    public int pop() {
        ListNode tmp = head;

        ListNode preNode = null;
        while (tmp.nextNode != null) {
            preNode = tmp;
            tmp = tmp.nextNode;
        }
        preNode.nextNode = null;

        return tmp.data;
    }
}

 

테스트

import org.junit.jupiter.api.Test;

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

class ListNodeStackTest {

    @Test
    void push() {

        ListNodeStack nodeStack = new ListNodeStack();

        nodeStack.push(1);
        nodeStack.push(2);

        int cnt = 0;
        while (nodeStack.head != null) {
            nodeStack.head = nodeStack.head.nextNode;
            cnt++;
        }

        assertEquals(cnt, 2);
    }

    @Test
    void pop() {
        ListNodeStack nodeStack = new ListNodeStack();

        nodeStack.push(1);
        nodeStack.push(2);
        nodeStack.push(3);
        nodeStack.push(4);
        nodeStack.push(5);

        assertEquals(nodeStack.pop(), 5);
        assertEquals(nodeStack.pop(), 4);
    }
}

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

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

배열

public class Queue {

    int front = 0;
    int rear = -1;
    int size;
    int[] arr;

    public Queue(int size) {
        this.size = size;
        this.arr = new int[size];
    }

    public void push(int data) {
        if (isFull())
            return ;
        arr[++rear] = data;
    }

    public int pop() {
        if (!isEmpty())
            return arr[front++];
        return 0;
    }

    public boolean isEmpty() {
        return front == rear + 1;
    }

    public boolean isFull() {
        return size <= rear;
    }
}

 

테스트

import org.junit.jupiter.api.Test;

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

class QueueTest {

    @Test
    void isEmpty() {
        Queue q = new Queue(10);
        assertTrue(q.isEmpty());
    }

    @Test
    void isFull() {
        Queue q = new Queue(1);
        q.push(1);
        assertTrue(q.isFull());
    }

    @Test
    void push() {
        Queue q = new Queue(10);
        q.push(1);
        int num = q.arr[0];
        assertEquals(1, num);
    }

    @Test
    void pop() {
        Queue q = new Queue(10);
        q.push(1);
        q.push(2);

        assertEquals(1, q.pop());
        assertEquals(2, q.pop());
    }
}

 

ListNode

public class ListNodeQueue {

    ListNode head;

    public void push(int data) {
        ListNode newNode = new ListNode(data);

        if (head == null) {
            head = newNode;
            return;
        }

        ListNode tmp = head;
        while (tmp.nextNode != null)
            tmp = tmp.nextNode;

        tmp.nextNode = newNode;
    }

    public int pop() {
        ListNode popNode = head;
        ListNode nextNode = popNode.nextNode;
        head = nextNode;

        int tmp = popNode.data;
        popNode = null;
        return tmp;
    }
}

테스트

import org.junit.jupiter.api.Test;

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

class ListNodeQueueTest {

    @Test
    void push() {
        ListNode head = null;
        ListNodeQueue nodeQueue = new ListNodeQueue();

        nodeQueue.push(1);
        nodeQueue.push(2);

        int cnt = 0;
        while (nodeQueue.head != null) {
            nodeQueue.head = nodeQueue.head.nextNode;
            cnt++;
        }
        assertEquals(2, cnt);
    }

    @Test
    void pop() {
        ListNodeQueue nodeQueue = new ListNodeQueue();

        nodeQueue.push(1);
        nodeQueue.push(2);
        nodeQueue.push(3);

        assertEquals(1, nodeQueue.pop());
        assertEquals(2, nodeQueue.pop());
        assertEquals(3, nodeQueue.pop());
    }
}
728x90
반응형