[백기선님과 함께하는 Live-Study] 4주차 - 제어문/반복문

JoonYoung Maeng·2020년 12월 7일
0
post-thumbnail

목표

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

학습할 것

  • 선택문
  • 반복문

선택문(조건문)

Java는 if/else문(조건문)과 Switch/case문(선택문)을 제공한다.

if/else 문

if문에 들어가는 조건식이 참인 경우에 if문 내의 블록 코드를 실행한다.

int a = 10;
if(a > 5) {   //조건이 참이므로 코드 실행 
	a += 5;   
}

만약 조건식이 거짓인 경우 else if문이 있다면 else if 문의 조건을, else문이 있다면 else문의 코드를 실행한다.

int a = 5;
if(a > 5) {
	System.out.println("a가 5보다 큰 경우 코드 실행");
}else if(a < 5) {
	System.out.println("a가 5보다 작은 경우 코드 실행");
}else {
	System.out.println("a가 5인경우 코드 실행");
}

또한, if문 내에 다시 if문 사용이 가능하다. 이를 중첩 if문이라 한다.

int a = 8;
if(a > 5) {
	if(a < 10) {
		System.out.println("a가 5보다 크고 10보다 작으면 코드 실행");
	}else{
		System.out.println("a가 10이상이면 코드 실행");
	}
}

switch/case 문

여러개의 if문은 코드의 가독성 및 여러 조건 탐색을 해야하므로 속도가 늦어진다는 단점이있다. switch문은 switch의 매개변수에 맞는 조건에 따라 case문을 실행하여 다중 if문의 단점을 개선한 선택문이다.

각각의 case문에 break 키워드를 사용하지 않으면 switch문을 탈출하지 않으므로 다음 case문도 실행하기 때문에 주의해야한다.


int a = 3;
switch(a){
	case 1 : 
		System.out.println("a가 1이면 코드 실행");
		break;
	case 2 : 
		System.out.println("a가 2이면 코드 실행");
		break;
	case 3 :
		System.out.println("a가 3이면 코드 실행");
		****break;
	default : 
		System.out.println("a가 그 외의 값들인 경우 코드 실행 ");
}

3주차 스터디 마지막에서 다룬 java13 swicth문을 보면 최근 Java 12부터 switch/case문에서 사용할 수 있는 기능이 확장되었다.


반복문

코드를 조건에 맞게 반복해주는 구문을 말한다.

반복문에는 for문, while문, do-while문, for-each(향상된 for문),Iterator가 있다.

for문(초기화;조건문;증감식)

for문은 초기화한 값을 가지고 조건문을 검사해 초기화한 값을 증감식의 조건에 따라 증감해가면서

for문 내부의 코드를 반복하는 구문이다.

for(int i=0;i<10;i++){
	//코드 0~9회 즉, 10번 실행
}

while문(조건)

while문은 조건의 값이 참인 경우에는 계속 반복하는 구문이다. 따라서, 조건이 항상 참인 경우 무한루프가 발생하기 때문에 유한적인 조건을 주거나 while문 내부에 탈출 조건을 반드시 명시해주어야 한다.

int i=0;
while(i<10){
	//코드 10회 반복
	i++; //for문과 달리 증감식이 없기 때문에 증감식을 통해 유한적인 조건이 되게함
}

do-while문(하단 조건)

do-while문은 while문과 달리 조건문이 하단에 있는 구문이다.

while문은 처음에 조건을 확인하고 실행하는 반면, do-while문의 경우 먼저 구문을 실행한 후 마지막에 조건을 확인함으로써 반드시 한번은 실행한다는 차이점이 있다.

do-while문은 반드시 하단 조건을 명시한 후 세미콜론(;)을 써야한다.

int i=0;
do{
	//코드 10회 반복
	i++;
}while(i<10);

for-each문(향상된 for문)

for문과 동일하게 for를 사용하지만 구조가 for문보다 직관적이고, 반복할 객체를 하나씩 차례대로 가져와 사용하는 구조이다.

List<Integer> list = new ArrayList<>();
for(int i=0;i<5;i++){
	list.add(i);
}

for(int num : list){
	//1부터 5를 list에서 하나씩 가져와 출력 
	System.out.println(num);
}

Iterartor

Iterator는 Java의 Collection에 저장되어 있는 데이터를 읽어오는 방법을 표준화한 기술 중 하나이다.

hasNext(), next(), remove() 메소드를 이용해 데이터를 뽑아와 사용할 수 있다.

Set<String> set = new HashSet<>();
set.add("안녕");
set.add("hello");
set.add("world");

Iterator<String> it = set.iterator();
while(it.hasNext()){
	//요소 출력 후 다음 요소로 이동 
	System.out.println(it.next());
	
	it.remove(); //요소 삭제 
}

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

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

JUnit5의 Life-Cycle

  • @BeforeAll : @Test 메소드들이 실행되기 전에 실행
  • @BeforeEach : 각각의 @Test 메소드가 실행되기 전에 실행
  • @AfterEach : 각각의 @Test 메소드가 실행된 후에 실행
  • @AfterAll : @Test 메소드들이 실행된 후에 실행
import org.junit.jupiter.api.*;

public class JUnit5Test {
    @BeforeAll
    static void beforeAll() {
        System.out.println("BeforeAll Test");
    }
    @BeforeEach
    static void beforeEach(){
        System.out.println("BeforeEach");
    }

    @Test
    @DisplayName("테스트 1☆")
    static void testing() {
        System.out.println("testing");
    }

    @AfterEach
    static void afterEach() {
        System.out.println("AfterEach");
    }

    @AfterAll
    static void afterAll() {
        System.out.println("AfterAll");
    }

JUnit5 Feature

  • @DisplayName : 한글, 스페이스,이모지를 통해 테스트 이름의 표기가능
  • @Nested : 계층 구조 테스트가 가능하게 지원
  • @ParameterizedTest : 여러개의 테스트 데이터를 매개변수 형태로 간편하게 사용 가능, NullSource, ValueSource, EmptySource, CsvSource, EnumSource, MethodSource등 최소 하나의 소스 어노테이션이 필요
//DisplayName을 이용한 테스트 이름 작성
@Test
@DisplayName("테스트 1☆")
static void testing() {
	System.out.println("testing");
}

//Nested를 이용한 계층 구조 테스트
@Nested
@DisplayName("people")
class People {
	@Nested
  @DisplayName("man")
  class Man {
	  @Test
    static void manTest() {
	    System.out.println("man");
    }
  }
	@Nested
  @DisplayName("woman")
  class Woman {
	  @Test
    static void womanTest() {
	    System.out.println("woman");
    }
  }
}

//ParameterizedTest를 이용한 매개변수이용 
@ParameterizedTest
@ValueSource(ints = {1,2,3,4,5})
static void isOdd(int num){
	assertTrue(Numbers.isOdd(num));
}

JUnit Assert

기존 JUnit4는 assert 메소드가 하나라도 실패하면 다음 assert를 실행하지 않았다. 하지만 JUnit5는 assertAll이라는 메소드를 통해 여러개의 assert를 실행하게 하여 실패하더라도 모든 결과를 확인할 수 있게 지원하였다.

@Test
static assertAllTest() {
	int num = 10;
	assertAll("assertAll test",
				  () -> assertEquals(10,num),
          () -> assertEquals(13,num+5),
          () -> assertEquals(15,num+5)
	);
}

또한, JUnit4의 경우 라이브러리를 이용해 예외 검증이 가능했다면, JUnit5는 assertThrows를 이용해 예외 검증이 가능하게 되었다.

@Test
static void assertThrowsTest() {
	Exception exception = assertThrows(
				  IllegalArgumentException.class, () -> {
					    throw new IllegalArgumentException("a message");
					}
	);
  assertEquals("message",exception.getMessage());
}

그리고, 어노테이션을 이용해 테스트 실행시간을 확인한것에 반해 assertTimeout을 이용해 테스트 실행시간에 대한 검증이 가능하게 되었다.

@Test
static void assertTimeoutTest() {
	assertTimeout(ofSeconds(1), () -> {
	  // 1초 이내에 수행해야함
  });
}

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

import org.kohsuke.github.*;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.*;

public class GitHubIssue {
    //personal token need to secret
    private static final String MY_PERSONAL_TOKEN = "MY_SECRET_TOKEN";

    public static void main(String[] args) throws IOException {
        GitHub github = new GitHubBuilder().withOAuthToken(MY_PERSONAL_TOKEN).build();

        //Repository 연결
        GHRepository repo = github.getRepository("whiteship/live-study");

        //IssueState ALL, OPEN, CLOSED
        List<GHIssue> issues = repo.getIssues(GHIssueState.ALL);
        Map<String, Integer> participant = new HashMap<>();

        //1-18개 이슈
        for (GHIssue issue : issues) {
            Set<String> onlyOneParticipant = new HashSet<>();

            //댓글 한개 이상 단 경우 유저이름 중복 제거
            for (GHIssueComment comment : issue.getComments()) {
                onlyOneParticipant.add(comment.getUser().getName());
            }

            //카운트 증가해주기
            for (String name : onlyOneParticipant) {
                if(participant.containsKey(name)){
                    participant.replace(name,participant.get(name)+1);
                    continue;
                }
                participant.put(name,1);
            }
        }
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        //참여율 출력
        for(String name : participant.keySet()){
            double rate = (double)(participant.get(name) * 100) / issues.size();
            bw.write("name : " + name);
            bw.write(", Participation Rate : "+String.format("%.2f",rate)+"%");
            bw.newLine();
        }
        bw.close();
    }

}

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

LinkedList Interface

public interface LinkedList {

    // add remove contains
    ListNode add(ListNode head, ListNode nodeToAdd, int position);
    ListNode remove(ListNode head, int positionToRemove);
    boolean contains(ListNode head, ListNode nodeToCheck);
}

ListNode.java

public class ListNode implements LinkedList {
    int data;
    ListNode next;

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

    @Override
    public ListNode add(ListNode head, ListNode nodeToAdd, int position) {
        ListNode node = head;

        //position 이전까지 탐색
        for (int i = 0; i < position - 1; i++) {
            node = node.next;
        }

        //지정 위치에 노드 삽입
        nodeToAdd.next = node.next;
        node.next = nodeToAdd;
        return head;
    }

    @Override
    public ListNode remove(ListNode head, int positionToRemove) {
        ListNode node = head;
				
				//삭제 위치가 가장 앞인경우 
        if(positionToRemove == 0){
            ListNode deleteToNode = node;
            head = node.next;
            deleteToNode.next = null;
            return deleteToNode;
        }
        for (int i = 0; i < positionToRemove - 1; i++) {
            node = node.next;
        }
				
				//지정 위치 노드 삭제
        ListNode deleteToNode = node.next;
        node.next = deleteToNode.next;
        deleteToNode.next = null;
        return deleteToNode;
    }

    @Override
    public boolean contains(ListNode head, ListNode nodeToCheck) {
        while (head.next != null) {
            if (head.next == nodeToCheck)
                return true;
            head = head.next;
        }
        return false;
    }
}

ListNodeTest.java

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

class ListNodeTest {
    private ListNode listNode;
    private static final int[] ADD_DATA = {1,3,4,5,7,9};
    private static final boolean[] CONTAINS_DATA = {true, false};
    private static List<Integer> acc_data;

    @BeforeEach
    void setUp() {
        acc_data = new ArrayList<>();
        listNode = new ListNode();
        ListNode firstNode = new ListNode(1);
        ListNode secondNode = new ListNode(3);
        ListNode thirdNode = new ListNode(5);
        ListNode fourthNode = new ListNode(7);
        ListNode fifthNode = new ListNode(9);

        this.listNode = firstNode;
        firstNode.next = secondNode;
        secondNode.next = thirdNode;
        thirdNode.next = fourthNode;
        fourthNode.next = fifthNode;
    }
    @Test
    void add() {
        listNode = listNode.add(listNode,new ListNode(4),2);

        while(listNode != null){
            acc_data.add(listNode.data);
            listNode = listNode.next;
        }

        for(int i=0;i<acc_data.size();i++) {
            Assertions.assertEquals(ADD_DATA[i],acc_data.get(i));
        }

    }

    @Test
    void remove() {
        ListNode removed = listNode.remove(listNode,2);
        Assertions.assertEquals(5,removed.data);
    }

    @Test
    void contains() {
        boolean[] result = new boolean[2];
        result[0] = listNode.contains(listNode,new ListNode(9));
        result[1] = listNode.contains(listNode,new ListNode(10));

        for(int i=0;i<acc_data.size();i++) {
            Assertions.assertEquals(CONTAINS_DATA[i],result[i]);
        }
    }
}

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

Stack Interface

public interface Stack {
    void push(int data);
    int pop();
}

ArrayStack.java

public class ArrayStack implements Stack {
    int[] stack;
    int top;

    public ArrayStack(int size) {
        stack = new int[size];
        top = -1;
    }

    @Override
    public void push(int data) {
        stack[++top] = data;
    }

    @Override
    public int pop() {
        if(top == -1){
            System.out.println("Empty");
            return top;
        }
        return stack[top--];
    }
}

ArrayStackTest.java

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class ArrayStackTest {
    private ArrayStack arrayStack;
    private static final int[] PUSH_DATA = {1,3,5,7,9};

    @BeforeEach
    void setUp() {
        arrayStack = new ArrayStack(5);
    }

    @Test
    void push() {
        arrayStack.push(1);
        arrayStack.push(3);
        arrayStack.push(5);
        arrayStack.push(7);
        arrayStack.push(9);

        for(int i=0;i<arrayStack.stack.length;i++){
            Assertions.assertEquals(PUSH_DATA[i],arrayStack.stack[i]);
        }
    }

    @Test
    void pop() {
        arrayStack.push(1);
        arrayStack.push(3);
        arrayStack.push(5);
        arrayStack.push(7);
        arrayStack.push(9);

        Assertions.assertEquals(9,arrayStack.pop());

    }
}

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

ListNodeStack.java

public class ListNodeStack implements Stack {

    static int top;
    ListNode node;
    public ListNodeStack() {
        this.node = null;
        this.top = -1;
    }

    @Override
    public void push(int data) {
        ListNode pushNode = new ListNode(data);
        if(node == null){
            node = new ListNode(data);
            top++;
        }else {
            node = node.add(node, pushNode, ++top);
        }
    }

    @Override
    public int pop() {
        if(top == -1) {
            System.out.println("Empty");
            return top;
        }
        return node.remove(node,top--).data;
    }
}

ListNodeStackTest.java

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

class ListNodeStackTest {
    private ListNodeStack stack;
    private static final int[] PUSH_DATA = {1,3,5,7,9};
    @BeforeEach
    void setUp() {
        stack = new ListNodeStack();
    }

    @Test
    void push() {
        stack.push(1);
        stack.push(3);
        stack.push(5);
        stack.push(7);
        stack.push(9);

        ListNode node = stack.node;

        int i=0;
        while(node != null) {
            Assertions.assertEquals(PUSH_DATA[i++],node.data);
            node = node.next;
        }
    }

    @Test
    void pop() {
        stack.push(1);
        stack.push(3);
        stack.push(5);
        stack.push(7);
        stack.push(9);

        Assertions.assertEquals(9,stack.pop());
        Assertions.assertEquals(7,stack.pop());
        Assertions.assertEquals(5,stack.pop());
        Assertions.assertEquals(3,stack.pop());
        Assertions.assertEquals(1,stack.pop());

    }
}

Reference

https://wikidocs.net/264

https://pathas.tistory.com/109?category=880477

https://vaert.tistory.com/108

https://sabarada.tistory.com/79

https://if.kakao.com/session/108

https://www.javaguides.net/2018/09/junit-5-assertthrows-example.html

profile
백엔드 개발자 지망생입니다!

0개의 댓글