본문 바로가기
Challenge

4주차 과제: 제어문

by Daisy :) 2020. 12. 3.
반응형

제어문(control statement)이란?

프로그램의 흐름을 개발자가 원하는 방향으로 이끌어 주는 구문을 제어문이라고 합니다. 

 

 

  • 조건문: if문, switch문
  • 반복문 : for문, while문
  • 분기문 : break, continue, return

if문 

if(조건식){
	// 조건식이 true일 경우 수행될 구문을 작성합니다.
}

if문은 조건식과 괄호로 이루어져있으며, 조건식이 참일 경우 {} 안의 구문이 수행됩니다.

 

if-else문 

if(조건식){
	// 조건식이 true일 때 수행될 구문을 기재합니다
}else{
	//조건식이 false일 때 수행될 구문을 기재합니다.
}

if-else문은 조건식이 거짓일 경우 else블럭의 문장을 수행하게 됩니다. 

 

if-else if문

if(조건식1){
	// 조건식 1이 true일 경우 수행될 문장을 기재합니다.
}else(조건식2){
	// 조건식 2가 true일 경우 수행될 문장을 기재합니다. 
}else(조건식3){
	// 조건식 3이 true일 경우 수행될 문장을 기재합니다. 
}else{
	// 위의 조건식1, 2, 3 이 모두 false일 경우 수행될 문장을 기재합니다.
}

if-else if문은 조건식이 여러가지 일 경우 사용이 되며, 마지막은 else로 끝나지만 생략이 가능합니다. 

 

중첩if문

if(조건식1){ 
	// 조건식1이 true일 경우 수행될 문장을 기재합니다. 
    if(조건식2){
    	//조건식1과 조건식2가 모두 true일 경우 수행될 문장을 기재합니다
    }else{
    	// 조건식1이 true이지만, 조건식2가 false일 경우 수행될 문장을 기재합니다. 
    }
}else{
	//조건식1이 false일 때 수행될 문장을 기재합니다. 
}

중첩if문은 if문 블럭 안에 또 다른 if문을 포함시키는 것이며 횟수의 제한은 거의 없습니다. 

 

switch문

switch(조건식){
	case A:
    	//조건식의 결과가 A일 경우 수행될 구문을 기재합니다. 
        break;
    case B:
    	//조건식의 결과가 B일 경우 수행될 구문을 기재합니다. 
        break;
    case C :
    	//조건식의 결과가 C일 경우 수행될 구문을 기재합니다.
        break;
    default :
        // 조건식과 일치하는 case가 없는 경우 수행될 구문을 기재합니다.
  }

switch문은 하나의 조건식을 여러 경우의 수로 처리할 경우 이용하면 간결하지만 제약조건이 있습니다.

 

switch문의 제약조건

1) switch문의 조건식 결과는 정수 또는 문자열이어야 합니다.

2) case문의 값은 정수 상수(문자포함), 문자열만 가능하며 중복이 되지 읺아야 합니다.

3) 변수나 실수는 불가합니다.

 

for문

for(초기화; 조건식; 증감식){
	조건식이 true일 경우 수행될 구문을 기재합니다. 
}

for문의 구조는 초기화, 조건식, 증감식, 블럭으로 이루어져 있습니다. 

 

1) 초기화

반복문에 사용될 변수의 초기화로 처음 한번만 수행됩니다. 

둘 이상의 변수 일 경우 ,(콤마)를 이용해서 초기화하며 변수의 타입은 동일해야합니다.

 

2) 조건식

조건식의 조건이 true이면 반복수행하고, false이면 수행을 중단하게 됩니다.

조건식이 true일 경우 {}내부에 구문이 수행됩니다.

 

3) 증감식

반복문을 제어하는 변수의 값을 증가 또는 감소 시키는 것으로, 증감식으로 변수의 값이 변하다가 false가 될 경우 더이상 수행되지 않습니다.

증감식도 ,(콤마)를 이용해서 두 문장 이상을 하나로 연결해서 쓸 수 있으며, 초기화, 조건식, 증감식 모두 생략 가능합니다.

 

while문

while(조건식){
	// 조건식의 결과가 true인 동안 반복될 문장을 기재합니다. 
}

while문은 조건식이 true일 경우 {} 블럭안의 구문을 수행하게 됩니다. 

for문이 while문보다 더 간결하지만 필요에 따라서는 while문이 더 적합할 수 있습니다. 

 

do-while문 

do{
	// 조건식의 연산결과가 참 일떄 수행될 구문을 기재합니다. 
}while(조건식);

do-while문은 조건식과 {}블럭의 순서를 바꿔놓은 것 입니다. 

while문은 조건식의 결과 여부에 따라서 {}블럭 안의 구문이 한번도 수행되지 않을 수도 있지만 do-while문은 조건식이 한번은 수행이 됩니다. 

 

break문

break문은 자신이 포함된 가장 가까운 반복문을 벗어나게 됩니다. 

주로 if문과 함꼐 사용되어 특정 조건을 만족 할 떄 반복문을 벗어나게 합니다.

 

continue문

continue문은 반복문 내에서만 사용될 수 있으며 반복이 진행되는 도중에 continue문을 만나면 반복문의 끝으로 이동하여 다음 반복으로 넘어가게 됩니다. 

continue문은 반복문 전체를 벗어나지 않고 다음 반복을 계속 수행한다는 부분에서 break문과 다르게 됩니다. 

 

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

srpingboot 2.2부터는 기본 Junit 의존성이 5점대로 변경되었습니다. 
기존에 스프링부트 2.1이하에서 만들던 프로젝트는 Junit버전이 다릅니다 . 

JUnit4는 하나의 jar파일로 Dependency로 들어오고, JUnit이 참조하는 다른 라이브러리가 있는 형태였으나, 
JUnit5부터는 그 자체로 여러 모듈화가 되어있습니다. 

JUnit 5 = JUnit 플랫폼 + JUnit Jupiter + JUnit 빈티지

JUnit 5는 Java 8 이상이 필요하지만, 이전 버전의 JDK로 컴파일 된 코드는 계속 테스트 할 수 있습니다.

JUnit5를 시작할때에는 Spring Starter Project를 생성하고 pom.xml 파일에 Junit dependency를 추가합니다. 

저는 따로 버전을 기재하지않았고, Maven Dependencies에 junit-jupiter-5.7.0.jar 파일이 추가된것이 확인됩니다. 

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

JUnit5 이름설정하기 

노란색으로 표시한 부분으로 설명을 해드리겠습니다.

Line 18) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)

클래스에 해당 어노테이션을 붙이면 @Test메소드 이름에 _로 표시한 부분이 space로 처리됩니다.

Line 22) @DisplayName("스터디 만들기 \uD83D\uDE31")

이 어노테이션은 사용자가 정의한 이름으로 테스트 이름을 표기할 수 있습니다. 첨부한 이미지처럼 이모티콘도 가능합니다.

위의 @DisplayNameGeneration보다 우선순위가 높습니다. 

Line 39) @Disabled 

이 어노테이션이 있으면 해당 test는 실행을 하지않습니다. 

 

 

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

1) pom.xml에 깃허브 api 사용을 위한 dependency를 추가합니다

<!-- https://mvnrepository.com/artifact/org.kohsuke/github-api -->
<dependency>
  <groupId>org.kohsuke</groupId>
  <artifactId>github-api</artifactId>
  <version>1.117</version>
</dependency>

2) 코드구현

package com.example.dashboard;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.kohsuke.github.GHIssue;
import org.kohsuke.github.GHIssueComment;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubBuilder;

public class GithubIssueComment {

	private GitHub github;
	
	public GithubIssueComment() {
		try {
			this.github = GitHub.connectAnonymously();
		} catch (Exception e) {
			System.out.println("git hub 연결 실패");
			e.printStackTrace();
		}
	}
	
	public GithubIssueComment(String token) {
		try {
			if( token == null || token.isEmpty() ) {
				this.github = GitHub.connectAnonymously();
			} else {
				this.github = new GitHubBuilder().withOAuthToken(token).build();
			}
		} catch (Exception e) {
			System.out.println("git hub 연결 실패");
			e.printStackTrace();
		}
	}
	
	public boolean isConnect() {
		return github != null;
	}
	
	public boolean connect() {
		try {
			if( this.github == null ) {
				this.github = GitHub.connectAnonymously();
			}
		} catch (Exception e) {
			System.out.println("git hub 연결 실패");
			e.printStackTrace();
		}
		
		return isConnect();
	}
	
	public boolean connect(String token) {
		try {
			if( token == null || token.isEmpty() ) {
				this.github = GitHub.connectAnonymously();
			} else {
				this.github = new GitHubBuilder().withOAuthToken(token).build();
			}
		} catch (Exception e) {
			System.out.println("git hub 연결 실패");
			e.printStackTrace();
		}
		
		return isConnect();
	}
	
	public GHIssue getIssue(GHRepository repository, int id) {
		try {
			return repository.getIssue(id);
		} catch (Exception e) {
			return null;
		} 
	}
	
	public List<GHIssueComment> getAllComments(GHIssue issue) {
		try {
			return issue.getComments();
		} catch (Exception e) {
			return new ArrayList<GHIssueComment>();
		} 
	}
	
	public Map<String, Map<Integer, List<GHIssueComment>>> getCommentsForDashBoard(String repositoryName) {
		
		if( repositoryName == null || repositoryName.isEmpty() ) {
			return null;
		}
		
		try {
			
			Map<String, Map<Integer, List<GHIssueComment>>> groupByUser = new HashMap<String, Map<Integer, List<GHIssueComment>>>();
			
			GHRepository repository  = this.github.getRepository(repositoryName);
			System.out.println(repository.getDescription());
			
			int weekCount = 18;
			
			for( int i = 1 ; i <= weekCount ; i++ ) {
				GHIssue issue = getIssue(repository, i);
				
				if( issue == null ) {
					continue;
				}
				
				List<GHIssueComment> comments = getAllComments(issue);
				
				for( GHIssueComment cmt : comments ) {
					String loginId = cmt.getUser().getLogin();
					
					Map<Integer, List<GHIssueComment>> temp = groupByUser.get(loginId);
					if( temp == null ) {
						temp = new HashMap<Integer, List<GHIssueComment>>();
						groupByUser.put(loginId, temp);
					}
					
					List<GHIssueComment> tempIssueList = temp.get(i);
					if( tempIssueList == null ) {
						tempIssueList = new ArrayList<GHIssueComment>();
						temp.put(i, tempIssueList);
					}
					tempIssueList.add(cmt);
				}
			}
			
			return groupByUser;
		} catch ( Exception e ) {
			System.out.println("조회 실패");
			e.printStackTrace();
		}
		return null;
	}
	
	public List<Map<String, Object>> getDashBoardData(String repositoryName) {
		
		List<Map<String, Object>> resultList = new ArrayList<Map<String,Object>>();
		
		Map<String, Map<Integer, List<GHIssueComment>>> commentsForDashBoard = getCommentsForDashBoard(repositoryName);
		if( commentsForDashBoard == null ) {
			return resultList;
		}
		
		int weekCount = 18;
		
		DecimalFormat formtter = new DecimalFormat("##0.00");
		StringBuffer weekName = new StringBuffer();
		for( Entry<String, Map<Integer, List<GHIssueComment>>> dashBoardEntry : commentsForDashBoard.entrySet() ) {
			String user = dashBoardEntry.getKey();
			Map<Integer, List<GHIssueComment>> cmtInfo = dashBoardEntry.getValue();
			
			Map<String, Object> rows = new LinkedHashMap<String, Object>();
			
			rows.put("참여자", user);
			double participationCount = 0.0;
			
			for( int i = 1 ; i <= weekCount ; i++ ) {
				List<GHIssueComment> cmtlist = cmtInfo.get(i);
				int size = cmtlist == null ? 0 : cmtlist.size();
				participationCount += size > 0 ? 1 : 0;
				weekName.setLength(0);
				weekName.append(i);
				weekName.append("주차");
				rows.put(weekName.toString(), size > 0 ? "Y" : "N");
			}
			
			double participationRate = participationCount * 100.0 / 18.0;
			
			rows.put("참여율", formtter.format(participationRate));
			
			resultList.add(rows);
		}
		
		return resultList;
	}
	
	public static void main(String[] args) {
		
		GithubIssueComment githubIssueComment = new GithubIssueComment("f04e800feca14a20321d665e55dc7b34c77e44cd ");
		
		List<Map<String, Object>> dashboard = githubIssueComment.getDashBoardData("pka0220z/study");
		
		if( !dashboard.isEmpty() ) {
			Set<String> headers = dashboard.get(0).keySet();
			
			for( String header : headers ) {
				System.out.print(header);
				System.out.print("\t");
			}
			System.out.println();
			for( Map<String, Object> rows : dashboard ) {
				for( String header : headers ) {
					System.out.print(rows.get(header));
					System.out.print("\t");
				}
				System.out.println();
			}
			
		}
		
		
	}

}

 

 

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

package study;

public class ListNode {

	private int value;
	private ListNode next;

	public ListNode() {
	}

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

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}

	public ListNode getNext() {
		return next;
	}

	// Next Node를 함부로 못바꾸게 하기 위해 접근제어자를 default로 설정
	void setNext(ListNode next) {
		this.next = next;
	}

	public ListNode add(ListNode head, ListNode nodeToAdd, int position) {

		if (head == null || nodeToAdd == null) {
			return null;
		}

		// head 를 기준으로 교체작업을 할 position의 Node 찾기
		ListNode target = head;

		for (int i = 0; i < position - 1; i++) {
			target = target.next;

			if (target == null) {
				System.out.println("position 초과");
				return head;
			}
		}
		
		// 작업 대상 뒤의 Node를 삽입할 Node의 next에 연결
		ListNode addTarget = nodeToAdd;
		while( addTarget.getNext() != null ) {
			addTarget = addTarget.getNext();
		}
		
		addTarget.setNext(target.next);
		// 작업 대상의 next에 삽입할 Node 연결
		target.setNext(nodeToAdd);

		return head;
	}

	public ListNode remove(ListNode head, int positionToRemove) {
		if (head == null) {
			return null;
		}
		// head를 기준으로 삭제작업할 positionToRemove의 Node찾기
		ListNode target = head;

		for (int i = 0; i < positionToRemove - 1; i++) {
			target = target.next;

			if (target == null) {
				System.out.println("position 초과");
				return head;
			}
		}
		// 한단계 앞의 node의 next를 제거할 positionToRemove의 다음 node와 연결
		ListNode removeTarget = target.getNext();
		if (removeTarget != null) {
			target.next = removeTarget.getNext();
		}

		return head;
	}

	public boolean contains(ListNode head, ListNode nodeTocheck) {
		
		//head Null체크
		if( head == null) {
			return false;
		}

		// head부터 더이상 연결된 ListNode가 없을 때까지 반복하며
		ListNode compareTarget = head;
		
		// nodeTocheck 와 같은 value를 가진 ListNode가 있는지 검사
		do {
			// 발견 즉시 return true;
			if( compareTarget.getValue() == nodeTocheck.getValue() ) {
				return true;
			}
			compareTarget = compareTarget.next;
		} while (compareTarget != null);
		
		// 발견이 안되면 return false;
		return false;
	}

	public String toString() {
		return "[value=" + String.valueOf(value) + ", next=" + next + "]";
	}

	public static void main(String[] args) {

		ListNode head = new ListNode(1);
		
		ListNode search = new ListNode(3);
		head.add(head, new ListNode(2), 1);
		head.add(head, search, 2);
		head.add(head, new ListNode(4), 3);
		head.remove(head, 1);

		System.out.println(head);
		
		System.out.println(head.contains(head, new ListNode(3)));
	}
}

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

package list.linkedlist.implementation;

public class Stack {
		
	private int max; // 스택의 용량 
	private int position; // 스택의 포인터 
	private int[] values; // 스택에 저장된 값
	
	
	//stack 생성자 
	public Stack() {
		this(10);
	}
	public Stack(int capacity) {
		position  = 0;
		max = capacity;
		try {
			values = new int[max];
		}catch (OutOfMemoryError e) {
			max = 0;
		}
		
	}
	
	// 푸시메서드 생성
	public int push(int data) {
		// 스택이 다 차게 될 경우 
		if(max-1  == position) {
			// max의 값을 특정 양만큼 늘린다.
			max = max + 10;
			int[] temp = new int[max];
			
			for( int i = 0 ; i < values.length ; i++ ) {
				temp[i] = values[i];
			}
			
			values = temp;
		}
		 
		return values[position++] = data;
	}
	
	// 팝 메서드 생성
	public int pop() {
		return values[--position];
	}
	
	

	public static void main(String[] args) {
		Stack stack = new Stack();
		System.out.println(stack.push(3));
		System.out.println(stack.push(2));
		System.out.println(stack.push(3));
		System.out.println(stack.push(3));
		System.out.println(stack.push(3));
		System.out.println(stack.push(3));
		System.out.println(stack.push(3));
		System.out.println(stack.push(3));
		System.out.println(stack.push(3));
		System.out.println(stack.push(3));
		System.out.println();
		System.out.println(stack.push(3));
		System.out.println(stack.push(3));
		System.out.println();
		System.out.println(stack.pop());
		System.out.println(stack.pop());
		System.out.println(stack.pop());

	}

}

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

package list.linkedlist.implementation;

import study.ListNode;

public class ListNodeStack {
	// ListNode의 시작은 head
	ListNode head;

	// 숫자를 집어넣는 역할
	void push(int data) {

		// data 를 값으로 가지는 ListNode 객체 생성
		ListNode dataNode = new ListNode(data);

		// 원래 가지고 있던 head 를 새로 생성한 ListNode 에 next로 지정
		dataNode.add(dataNode, this.head, 1);

		System.out.println(dataNode);
		// 현재 head 에 새로 생상한 ListNode를 지정
		this.head = dataNode;
		
	}

	// 마지막 들어온 숫자를 돌려주는 역할 + 돌려주면서 해당 스택에서 삭제가 되야함.

	int pop() {
		
		if (this.head == null) {
			throw new RuntimeException("stack이 비었습니다. ");
		}

		// 반환할 head값을 선택함
		int popValue = this.head.getValue();

		// 원래 head 뒤에있던 ListNode를 head로 지정
		this.head = this.head.getNext();

		// 꺼내놓은 head를 반환
		return popValue;

	}
	public static void main(String[] args) {
		ListNodeStack listNodeStack = new ListNodeStack();
		
		listNodeStack.push(1);
		listNodeStack.push(2);
		listNodeStack.push(3);
		listNodeStack.push(4);
		
		
		System.out.println(listNodeStack.pop());
		System.out.println(listNodeStack.pop());
		System.out.println(listNodeStack.pop());
		System.out.println(listNodeStack.pop());
		System.out.println(listNodeStack.pop());
	
	}

}

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

  • ListNode를 사용해서 한번.
package list.linkedlist.implementation;

import study.ListNode;

public class ListNodeQueue {

		ListNode head; // ListNode의 시작은 head
		private int position; // 큐의 포인터 
	

	// 숫자를 집어넣는 역할
		void push(int data) {

			// data 를 값으로 가지는 ListNode 객체 생성
			ListNode dataNode = new ListNode(data);
			
			// position null 체크
			if(position == 0) {
				this.head = dataNode;
				position++;
			}else {
				// 원래 가지고 있던 head 를 새로 생성한 ListNode 에 head로 지정
				dataNode.add(this.head,dataNode,position++);
				
			}
			System.out.println(this.head);
				
		}
		
		int pop() {
			if (this.position == 0) {
				throw new RuntimeException("Queue가 비었습니다. ");
			}
			// 반환할 head값을 선택함
			int popValue = this.head.getValue();

			// 원래 head 뒤에있던 ListNode를 head로 지정
			this.head = this.head.getNext();
			position--;
			System.out.println(this.head);
			// 꺼내놓은 head를 반환
			return popValue;
			
		}
		

	public static void main(String[] args) {
		ListNodeQueue listNodeQueue = new ListNodeQueue();
		
		listNodeQueue.push(1);
		listNodeQueue.push(2);
		listNodeQueue.push(3);
		System.out.println();
		listNodeQueue.pop();
		listNodeQueue.pop();
		listNodeQueue.pop();
		
	}

}
  • 배열을 사용해서 한번
package list.linkedlist.implementation;

public class Queue {
	
	private int max; // 큐의 용량 
	private int position; // 큐의 포인터 
	private int[] values; // 큐에 저장된 값
	
	
	//큐 생성자 
	public Queue() {
		this(10);
	}
	public Queue(int capacity) {
	    position  = 0;
		max = capacity;
		try {
			values = new int[max];
		}catch (OutOfMemoryError e) {
			max = 0;
		}
	}	
	
	// 푸시메서드 생성
		public int push(int data) {
			// 큐가 다 차게 될 경우 
			if(max-1  == position) {
				// 큐의 값을 특정 양만큼 늘린다.
				max = max + 10;
				int[] temp = new int[max];
				
				for( int i = 0 ; i < values.length ; i++ ) {
					temp[i] = values[i];
				}
				
				values = temp;
				
			}
			 
			return values[position++] = data;
		}
		
		// 팝 메서드 생성
		public int pop() {
			
			int popValue = values[0];
			
			for( int i = 1 ; i < position ; i++ ) {
				values[i - 1] = values[i];
			}
			
			position--;
			return popValue;
		}
		

	public static void main(String[] args) {
		Queue queue = new Queue();
		
		System.out.println(queue.push(1));
		System.out.println(queue.push(2));
		System.out.println(queue.push(3));
		System.out.println(queue.push(4));
		System.out.println(queue.push(5));
		System.out.println(queue.push(6));
		System.out.println(queue.push(7));
		System.out.println(queue.push(8));
		System.out.println(queue.push(9));
		System.out.println(queue.push(10));
		System.out.println(queue.push(11));
		System.out.println();
		System.out.println(queue.pop());
		System.out.println(queue.pop());
		System.out.println(queue.pop());
		

	}

}

 

 

 

 

 

 

 

<reference>

자바의 정석 저자:남궁 성

www.inflearn.com/course/the-java-application-test?inst=86d1fbb8 

 

더 자바, 애플리케이션을 테스트하는 다양한 방법 - 인프런

자바 프로그래밍 언어를 사용하고 있거나 공부하고 있는 학생 또는 개발자라면 반드시 알아야 하는 애플리케이션을 테스트하는 다양한 방법을 학습합니다. 초급 프로그래밍 언어 프레임워크

www.inflearn.com

junit.org/junit5/docs/current/user-guide/ 

 

JUnit 5 User Guide

Although the JUnit Jupiter programming model and extension model will not support JUnit 4 features such as Rules and Runners natively, it is not expected that source code maintainers will need to update all of their existing tests, test extensions, and cus

junit.org

www.youtube.com/user/egoing2

반응형

댓글