학습할 것
- 선택문
- 반복문
- 과제
- JUnit5 학습
- live-study 대시보드 만들기
- LinkedList구현
- Stack구현
- 과제3을 이용한 Stack 구현
- Queue 구현
0. 제어문
Java에서 코드의 실행흐름은 위에서 아래로 한 문장씩 순차적으로 진행되었다.
때로는 조건에 따라 문장을 건너뛰거나 같은 문장을 반복해서 수행해야할 때가 있다.
이처럼 프로그램의 흐름(flow)을 바꾸는 역할을 하는 문장들을 제어문(control statement) 이라 한다.
제어문에는 조건문과 반복문이 있는데 조건문은 조건에 따라 다른 문장이 수행되도록 하고, 반복문은 특정 문장들을 반복해서 수행한다.
1. 선택문 (조건문)
조건문은 조건식과 문장을 포함하는 블럭 {} 으로 구성되어 있으며, 조건식의 연산 결과에 따라 실행할 문장이 달라져 프로그램의 실행 흐름을 변경할 수 있다.
조건문은 if문과 switch문이 있다.
1.1 if문
if문은 가장 기본적인 조건문이며 아래와 같이 조건식 과 괄호 {} 로 이루어져있다.
만일 (if) 조건식이 참(true)면 괄호 {} 안의 문장들을 수행해라 라는 의미이다.
if(조건식){
// 조건식이 참(true)일 때 수행될 문장
}
if문의 작동방식은 다음과 같다.
- Control falls into the if block.
- The flow jumps to Condition.
- Condition is tested.
- If Condition yields true, goto Step 4.
- If Condition yields false, goto Step 5.
- The if-block or the body inside the if is executed.
- Flow steps out of the if block.
ex)
if(score > 60){
System.out.printl("합격입니다.");
}
여기서 괄호 {}를 이용해서 여러 문장을 하나의 단위로 묶을 수 있는데 이것을 블럭(block)이라 한다.
블럭 안에는 보통 여러 문장을 넣지만, 한 문장만 넣거나 아무런 문장도 넣지 않을 수 있다.
만약 블럭 내에 문장이 하나뿐일 때 다음과 같이 괄호 {} 를 생략할 수 있다. (생략하지 않는 편이 좋다)
나중에 새로운 문장들이 추가되면 괄호 {} 로 문장들을 감싸 주어야 하는데, 이때 괄호를 잊기 쉽다.
if(score > 60)
System.out.println("합격입니다.); // if문에 속한 문장
System.out.println("축하드립니다.); // if문제 속한 문장이 아님
다음 예제를 살펴보자
public class IfTest {
public static void main(String[] args) {
int input;
System.out.print("숫자를 하나 입력하세요 : ");
Scanner scanner = new Scanner(System.in);
String tmp = scanner.nextLine();
input = Integer.parseInt(tmp);
if(input == 0){
System.out.println("입력하신 숫자는 0 입니다.");
}
if(input != 0)
System.out.println("입력하신 숫자는 0이 아닙니다.");
System.out.printf("입력하신 숫자는 %d입니다.", input); // a
}
}
0을 입력할 때 a문장이 실행되지 않아야 하는데 실행되는 것을 알 수 있다.
즉, a문장이 if문에 영향을 받지 않아 항상 출력된다.
1-2. if-else문
if문의 변형으로 if-else문 구조는 다음과 같다.
if문에 else블럭이 더 추가되었다. if문에서 조건식의 결과가 참이 아닐때 else 블럭의 문장을 수행하라는 뜻이다.
if (조건식) {
// 조건식이 참(true) 일 때 수행될 문장들을 적는다.
} else {
// 조건식이 거짓(false)일 때 수행될 문장들을 적는다.
}
작동 방법은 다음과 같다.
- Control falls into the if block.
- The flow jumps to Condition.
- Condition is tested.
- If Condition yields true, go to Step 4.
- If Condition yields false, go to Step 5.
- The if-block or the body inside the if is executed.
- The else block or the body inside the else is executed.
- Flow exits the if-else block.
ex)
public class IfElseTest {
public static void main(String[] args) {
System.out.print("숫자를 하나 입력하세요. : ");
Scanner scanner = new Scanner(System.in);
int input = scanner.nextInt();
if(input == 0){
System.out.println("입력하신 숫자는 0 입니다.");
} else {
System.out.println("입력하신 숫자는 0 이 아닙니다.");
}
}
}
if문을 따로 쓰면 될텐데 왜 if-else 문을 쓸까 라는 의문이 들 것이다.
예제를 통해 설명하자면,
if(input == 0){
System.out.println("0입니다.");
}
if(input != 0){
System.out.println("0이 아닙니다.");
}
다음 코드를 아래와 같이 쓸 수 있다.
if(input == 0) {
System.out.println("0입니다.");
} else {
System.out.println("0이 아닙니다.");
}
위쪽 코드는 두개의 조건식을 계산해야 하지만, if-else문을 사용한 오른쪽의 코드는 하나의 조건식만 계산하며 ㄴ되므로 더 효율적이고 간단하다.
1-3. if-else if문
if-else에서 두가지 경우 중 하나를 만족할 때 수행된다. 만약 세가지 이상 일 때 if- else if 문을 사용한다.
if(조건식1){
// 조건식1의 연산결과가 참일 때 수행될 문장들을 적는다.
} else if (조건식2) {
// 조건식2의 연산결과가 참일 때 수행될 문장들을 적는다.
} else if (조건식3) { // 여러개의 if-else문을 찾는다.
// 조건식3의 연산결과가 참일 때 수행될 문장들을 적는다.
} else{ // 마지막에는 보통 else 블럭으로 끝나며, else블럭은 생략 가능하다.
// 위의 어느 조건식도 만족하지 않을 때 수행될 문장들을 적는다.
}
- Control falls into the if block.
- The flow jumps to Condition 1.
- Condition is tested.
- If Condition yields true, goto Step 4.
- If Condition yields false, goto Step 5.
- The present block is executed. Goto Step 7.
- The flow jumps to Condition 2.
- If Condition yields true, goto step 4.
- If Condition yields false, goto Step 6.
- The flow jumps to Condition 3.
- If Condition yields true, goto step 4.
- If Condition yields false, execute else block.
Goto Step 7.
- Exit the if-else-if ladder.
첫 번째 조건식부터 순서대로 평가해서 결과가 참인 조건식을 만나면, 해당 블럭 {} 만 수행하고 if-else if문 전체를 벗어난다.
만일 결과가 참인 조건식이 하나도 없다면, 마지막에 있는 else블럭의 문장들이 생략된다. (else문장은 생략가능하다.)
class ElseIfTest {
public static void main(String[] args) {
int score = 0; // 점수를 저장하기 위한 변수
char grade =' '; // 학점을 저장하기 위한 변수. 공백으로 초기화한다.
System.out.print("점수를 입력하세요.>");
Scanner scanner = new Scanner(System.in);
String tmp = scanner.nextLine(); // 화면을 통해 입력받은 내용을 tmp에 저장
score = Integer.parseInt(tmp); // 입력받은 문자열(tmp)을 숫자로 변환
if (score >= 90) { // score가 90점 보다 같거나 크면 A학점
grade = 'A';
} else if (score >=80) { // score가 80점 보다 같거나 크면 B학점
grade = 'B';
} else if (score >=70) { // score가 70점 보다 같거나 크면 C학점
grade = 'C';
} else { // 나머지는 D학점
grade = 'D';
}
System.out.println("당신의 학점은 "+ grade +"입니다.");
}
}
결과
// output 1
점수를 입력하세요.> 0
당신의 학점은 C입니다.
// output 2
점수를 입력하세요.> 63
당신의 학점은 D입니다.
1-4. 중첩 if문
if문의 블럭 내에 또 다른 if문을 포함시키는 것이 가능한데 이것을 중첩 if문이라고 부르며 중첩의 횟수에는 거의 제한이 없다.
if(조건식1){
// 조건식1이 true일 경우 수행될 문장
if(조건식2){
//조건식1과 조건식2가 모두 true일 경우 수행될 문장
}else{
// 조건식1이 true이지만, 조건식2가 false일 경우 수행될 문장
}
}else{
//조건식1이 false일 때 수행될 문장
}
1-5.switch문
if문은 조건식의 결과가 참과 거짓, 두 가지 밖에 없기 때문에 경우의 수가 많아질수록 else-if를 계속 추가해야한다.
이때 조건식이 많아져서 복잡해지고, 여러개의 조건식을 계산 해야하므로 처리시간도 많이 걸린다.
switch문은 단 하나의 조건식으로 많은 경우의 수를 처리할 수 있고, 표현도 간결하므로 알아보기 쉽다.
switch문은 다음과 같다.
switch(조건식){
case 값1:
// 조건식의 결과가 값1과 같은 경우 수행될 문장
// ...
break;
case 값2:
// 조건식의 결과가 값2와 같은 경우 수행될 문장
// ...
break;
// ...
default:
// 조건식의 결과와 일치하는 case문이 없을 때 수행될 문장들
// ....
}
switch문은 다음과 같이 작동된다.
- 조건식을 계산한다
- 조건식의 결과와 일치하는 case문으로 이동한다
- 이후의 문장들을 수행한다
- break문이나 switch문의 끝을 만나면 switch문 전체를 빠져나간다.
만일 조건식의 결과와 일치하는 case문이 하나도 없는 경우에는 default문으로 이동한다.
default문은 if문의 else블러고가 같은 역할을 한다고 보면 이해가 쉬울 것이다. default문의 위치는 어디라도 상관없으나 보통 마지막에 놓기 때문에 break문으로 쓰지 않아도 된다.
그러나 경우에 따라서 break문을 생략하는 경우도 있다.
switch (level){
case 3:
grantDelete();
case 2:
grantWrite();
case 1:
grantRead();
}
switch문을 사용할 때 제약조건이 있다.
- switch문의 조건식 결과는 정수 또는 문자열 이여야한다.
- case문의 값은 정수 상수만 가능하며, 중복되지 않아야 한다.
ex)
import java.util.*;
class SwitchTest {
public static void main(String[] args) {
int month = 0;
System.out.print("현재 월을 입력하세요.>");
Scanner scanner = new Scanner(System.in);
String tmp = scanner.nextLine(); // 화면을 통해 입력받은 내용을 tmp에 저장
month = Integer.parseInt(tmp); // 입력받은 문자열(tmp)을 숫자로 변환
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("현재의 계절은 가을입니다.");
break;
default:
// case 12: case 1: case 2:
System.out.println("현재의 계절은 겨울입니다.");
}
} // main의 끝
}
1-6. switch 중첩문
if문처럼 switch문의 중첩이 가능하다.
switch문에서 break문을 작성하는 것을 잊을 수 있으니 유의해야 한다.
import java.util.*;
class SwitchTest2 {
public static void main(String[] args) {
char gender;
String regNo = "";
System.out.print("당신의 주민번호를 입력하세요.(011231-1111222)>");
Scanner scanner = new Scanner(System.in);
regNo = scanner.nextLine();
gender = regNo.charAt(7); // 입력받은 번호의 8번째 문자를 gender에 저장
switch(gender) {
case '1':
case '3':
switch(gender) {
case '1':
System.out.println("당신은 2000년 이전에 출생한 남자입니다.");
break;
case '3':
System.out.println("당신은 2000년 이후에 출생한 남자입니다.");
}
break; // 이 break문을 빼먹지 않도록 주의
case '2':
case '4':
switch(gender) {
case '2':
System.out.println("당신은 2000년 이전에 출생한 여자입니다.");
break;
case '4':
System.out.println("당신은 2000년 이후에 출생한 여자입니다.");
break;
}
break;
default:
System.out.println("유효하지 않은 주민등록번호입니다.");;
}
} // main의 끝
}
2. 반복문
반복문은 어떤 작업이 반복적으로 수행되도록 할 때 사용되며, 반복문의 종류로는 for문과 while문, 그리고 while문의 변형인 do-while문이 있다.
for문이나 while문에 속한 문장은 조건에 따라 한 번도 수행되지 않을 수 있지만 do-while문에 속한 문장은 무조건 최소한 한 번은 수행될 것이 보장된다.
반복문은 주어진 조건을 만족하는 동안 주어진 문장들을 반복적으로 수행하므로 조건식을 포함한다.
if문과 마찬가지로 조건식의 결과가 참이면 true, 거짓이면 false으로 판단한다.
2-1. for문
for문은 반복 횟수를 알고 있을 때 적합하다.
for(초기화;조건식;증감식){
수행될 문장
}
1) 초기화
반복문에 사용될 변수의 초기화로 처음 한번만 수행된다.
둘 이상의 변수 일 경우 ,(콤마)를 이용해서 초기화하며 변수의 타입이 동일해야 한다.
2) 조건식
조건식의 조건이 true이면 반복수행하고, false이면 수행을 중단한다.
조건식이 true일 경우 {}내부에 구문이 수행된다.
3) 증감식
반복문을 제어하는 변수의 값을 증가 또는 감소 시키는 것으로, 증감식으로 변수의 값이 변하다가 false가 될 경우 더이상 수행되지 않는다.
증감식도 ,(콤마)를 이용해서 두 문장 이상을 하나로 연결해서 쓸 수 있으며, 초기화, 조건식, 증감식 모두 생략 가능하다.
ex)
for(int i = 1; i<=5; i++){
System.out.println("true");
}
- 1번에 변수 i를 저장하고 초기값을 지정한다.
- 조건문을 확인한다.
- 조건문이 참이면
- 블록안의 문장을 실행한다.
- 블록이 끝나면 i++연산을 수행한다.
- 조건을 확인한다.
- 반복....
ex)
class GFG {
public static void main(String[] args)
{
for (int i = 1; i <= 10; i++) {
System.out.println(i);
}
}
}
/* output
1
2
3
4
5
6
7
8
9
10
*/
2-2. 중첩 for문
if문 안에 또 다른 if문을 넣을 수 있는 것처럼, for문 안에 또 다른 for문을 포함시키는 것도 가능하다.
for(int i = 1; i<=5; i++){
for(int j = 1; i<=5; j++){
System.out.print("*");
}
System.out.println();
}
/* output
*****
*****
*****
*****
*****
*/
2-3. 향상된 for문
JDK1.5부터 배열과 컬렉션에 저장된 요소에 접근할 때 기존보다 편리한 방법으로 처리할 수 있도록 새로운 for문 문법이 추가되었다.
for(타입 변수명 : 배열 또는 컬렉션 ){
// 반복할 문장
}
그러나 향상된 for문은 일반적인 ㄹor문과는 달리 배열이나 컬렉션에 저장된 요소들을 읽어오는 용도로만 사용할 수 있는 제약이 있다.
class ImproveForStatementTest {
public static void main(String[] args) {
int[] arr = {10,20,30,40,50};
int sum = 0;
for(int i=0;i<arr.length;i++) {
System.out.printf("%d ", arr[i]);
}
System.out.println();
for(int tmp : arr) {
System.out.printf("%d ", tmp);
sum += tmp;
}
System.out.println();
System.out.println("sum="+sum);
}
}
/* output
10 20 30 40 50
10 20 30 40 50
sum=150
*/
2-4. while문
조건식과 블럭 {} 으로 이루어져 있으며 while문의 조건식이 참(true)인 동안 블럭 {} 내의 문장을 반복한다.
while문의 조건식은 생략이 불가능하다.
while(조건식) {
// 조건식의 연산결과가 참(true)인 동안, 반복할 문장
}
- 조건식이 참(true)이면 블럭 {} 안으로 들어가고, 거짓(false)이면 while문을 벗어난다.
- 블럭 {} 의 문장을 수행하고 다시 조건식으로 돌아간다.
ex)
class FlowEx23 {
public static void main(String[] args) {
int i= 5;
while(i--!=0) {
System.out.println(i);
}
}
}
/*output
4
3
2
1
0
*/
2-5. do-while 문
do-while문은 while문의 변형으로 기본적인 구조는 while문과 같으나 조건식과 블럭 {} 의 순서를 바꿔놓은 것이다.
그래서 while문과 반대로 블럭 {}을 먼저 수행한 후에 조건식을 평가한다.
while문은 조건식의 결과에 따라 블럭 {} 이 한번도 수행하지 않을 수 있지만, do-while문은 최소한 한번은 수행할 것을 보장한다.
do{
// 조건식의 연산결과가 참일 때 수행될 문장들을 적는다.
}while(조건식);
다음 예제처럼 반복적으로 사용자의 입력을 받아서 처리할 때 유용한다.
import java.util.*;
class DoWhileTest {
public static void main(String[] args) {
int input = 0;
int answer = 0;
answer = (int)(Math.random() * 100) + 1; // 1~100사이의 임의의 수를 저장
Scanner scanner = new Scanner(System.in);
do {
System.out.print("1과 100사이의 정수를 입력하세요.>");
String tmp = scanner.nextLine();
input = Integer.parseInt(tmp);
if(input > answer) {
System.out.println("더 작은 수로 다시 시도해보세요.");
} else if(input < answer) {
System.out.println("더 큰 수로 다시 시도해보세요.");
}
} while(input!=answer);
System.out.println("정답입니다.");
}
}
2-6. break 문
앞서 switch문에서 break문을 사용한 것이 생각날 것이다.
반복문에서도 switch문을 사용할 수 있다.
break문은 자신이 포함된 가장 가까운 반복문을 벗어난다.
class BreakLoopDemo {
public static void main(String args[])
{
// Initially loop is set to run from 0-9
for (int i = 0; i < 10; i++) {
// terminate loop when i is 5.
if (i == 5)
break;
System.out.println("i: " + i);
}
System.out.println("Loop complete.");
}
}
/* output
i: 0
i: 1
i: 2
i: 3
i: 4
Loop complete.
*/
예제를 살펴보면 for문에서 i가 10이 되기 전에 i가 5일 때 break문을 만나 for문 블록을 탈출 한 것을 알 수 있다.
2-7. continue문
continue문은 반복문 내에서만 사용할 수 있다. 반복이 진행되는 도중에 continue문을 만나면 반복문의 끝으로 이동하여 다음 반복문으로 넘어간다.
continue문은 반복문 전체를 벗어나지 않고 다음 반복을 계속 수행한다는 점이 break문과 다르다.
주로 if문과 함께 사용되어 특정 조건을 만족하는 경우에 continue문 이후의 문장들을 수행하지 않고 다음 반복으로 넘어가서 계속 진행하도록 한다.
ex)
class ContinueTest {
public static void main(String[] args) {
for(int i=0;i <= 10;i++) {
if (i%3==0)
continue;
System.out.println(i);
}
}
}
3. 과제
3-1. JUnit5 학습
참고하였습니다.
공부한 코드를 첨부합니다.
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.condition.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.*;
import java.lang.annotation.*;
import java.time.Duration;
public class StudyTest {
@Test
void create() {
Study study = new Study();
assertNotNull(study);
System.out.println("create");
}
@Test
void create1() {
System.out.println("create1");
}
/*
// @BeforeAll, @AfterAll은 전체 테스트 시작과 끝에 수행할 코드를 작성한다.
// @BeforeAll, @AfterAll은 반드시 메서드에 static void를 붙여주어야 한다.
@BeforeAll
static void beforeAll() {
System.out.println("before all");
}
@AfterAll
static void afterAll() {
System.out.println("after all");
}
// @BeforeEach, @AfterEach는 각각의 테스트 시작과 끝에 수행할 코드를 작성하면 된다.
@BeforeEach
void beforeEach() {
System.out.println("before each");
}
@AfterEach
void afterEach() {
System.out.println("after each");
}
@Test
@Disabled // 수행하고 싶지 않은 테스트에 대해 붙여주면 JUnit이 해당 테스트는 무시하게 된다.
void create2() {
System.out.println("create1");
}
*/
/*
테스트 이름은 기본적으로 메서드 이름으로 지정된다.
그래서 보통 다음과 같이 메서드 이름에 Snake Case를 사용한다.
Camel Case에 비해 알아보기 쉽기 때문이다.
*/
@Test
void create_new_studyyy() {
Study study = new Study();
assertNotNull(study);
System.out.println("create");
}
@Test
void create_new_study_again() {
System.out.println("create1");
}
/*
@DisplayName
테스트 이름을 보다 쉽게 표현할 수 있는 방법을 제공하는 애노테이션이다.
@DisplayNameGeneration보다 우선 순위가 높다.
*/
@Test
@DisplayName("스터디 만들기")
void create_new_study() {
Study study = new Study(-10);
// assert문들의 성공 유무를 확인하고 싶다면 asserAll()을 사용
assertAll(
// 값이 null이 아닌지 확인
() -> assertNotNull(study),
// asserEquals()는 메서드의 첫 번째 인자와 두 번째 인자가 같은지 확인한다.
() -> assertEquals(StudyStatus.DRAFT, study.getStudyStatus(), () -> "스터디를 처음 만들면 " + StudyStatus.DRAFT + " 상태다."),
// 다음 조건이 참(true)인지 확인
() -> assertTrue(study.getLimit() > 0, () -> "스터디 최대 참석 가능 인원은 0보다 커야 한다.")
);
}
@Test
@DisplayName("스터디 만들기2")
void create_new_study2() {
Study study = new Study();
// assertNotNull()은 인자가 null이 아니면 테스트를 통과
assertNotNull(study);
// assertTrue()는 인자가 True이면 테스트를 통과한다.
assertTrue(1 < 2);
}
@Test
@DisplayName("스터디 만들기3")
void create_new_study3() {
// assertThrows()는 특정 exception이 발생할 것으로 기대되는 상황에 대해서 테스트하는 메서드
assertThrows(IllegalArgumentException.class, () -> new Study(-10));
}
// assertThrows()의 반환값으로 exception을 받아서 또 다른 테스트에 활용할 수 있다.
@Test
@DisplayName("스터디 만들기4")
void create_new_study4() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new Study(-20));
assertEquals("limit은 0보다 커야 한다.", exception.getMessage());
}
// assertTimeout()은 특정 로직이 특정 시간 안에 수행되도록 기대하는 테스트
@Test
@DisplayName("스터디 만들기5")
void create_new_study5() {
assertTimeout(Duration.ofMillis(100), () -> {
new Study(10);
Thread.sleep(300);
});
}
// Jupiter가 제공하는 테스트 라이브러리 중 하나인 Assumptions의 assumTrue()를 사용
@Test
@DisplayName("스터디 만들기6")
void create_new_study6() {
String test_env = System.getenv("TEST_ENV");
assumeTrue("LOCAL".equalsIgnoreCase(test_env));
}
// Assumptions를 활용해서 특정 조건에 따라 테스트를 실행하는 방법 => assumingThat()
// if문처럼 환경변수의 값에 따라 다른 테스트 로직을 수행하도록 설정할 수 있다.
@Test
@DisplayName("스터디 만들기7")
void create_new_study7() {
String test_env = System.getenv("TEST_ENV");
assumingThat("LOCAL".equalsIgnoreCase(test_env), () -> {
System.out.println("local");
});
assumingThat("REMOTE".equalsIgnoreCase(test_env), () -> {
System.out.println("remote");
});
}
@Test
@DisplayName("스터디 만들기8")
@EnabledOnOs({OS.MAC, OS.LINUX})
void create_new_study8() {
System.out.println("study");
}
@Test
@DisabledOnOs(OS.MAC)
void create_new_study_again2() {
System.out.println("again");
}
// @EnabledOnJre는 특정 자바 버전에 대해 테스트 코드를 수행
@Test
@DisplayName("스터디 만들기9")
@EnabledOnOs({OS.MAC, OS.LINUX})
@EnabledOnJre({JRE.JAVA_8,JRE.JAVA_9, JRE.JAVA_10, JRE.JAVA_11})
void create_new_study9() {
System.out.println("study");
}
@Test
@DisabledOnOs(OS.MAC)
@EnabledOnJre(JRE.OTHER)
void create_new_study_again3() {
System.out.println("again");
}
// @EnabledEnvironmentVariable은 환경 변수에 따라 테스트를 수행
@Test
@DisplayName("스터디 만들기")
@EnabledOnOs({OS.MAC, OS.LINUX})
@EnabledOnJre({JRE.JAVA_8,JRE.JAVA_9, JRE.JAVA_10, JRE.JAVA_11})
@EnabledIfEnvironmentVariable(named = "TEST_ENV", matches = "LOCAL")
void create_new_study10() {
System.out.println("study");
}
@Test
@DisabledOnOs(OS.MAC)
@EnabledOnJre(JRE.OTHER)
@EnabledIfEnvironmentVariable(named = "TEST_ENV", matches = "remote")
void create_new_study_again4() {
System.out.println("again");
}
// Junit5 태깅과 필터링
/*
@Tag를 사용해서 각각의 value 값을 다르게 설정
첫 번째 테스트는 빠르게 끝낼 수 있어 fast,
두 번째 테스트는 테스트 시간이 오래걸려 slow 태그를 달았다고 하자.
*/
/* 태그만 실행
1. 프로젝트 우측 상단에 "Edit Configurations" 메뉴를 클릭
2. Build and run -> Tags 선택 -> 우측 블록에 태그 value 값 설정
3. 실행항목을 이전에 설정한 Tags로 실행.
*/
@Test
@DisplayName("스터디 만들기 fast")
@Tag("fast")
void create_new_study11() {
System.out.println("fast");
}
@Test
@DisplayName("스터디 만들기 slow")
@Tag("slow")
void create_new_study_again5() {
System.out.println("slow");
}
// JUnit 5는 애노테이션을 조합하여 커스텀 태그를 만들 수 있다
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("fast")
public @interface FastTest {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("slow")
public @interface SlowTest {
}
/*
@Target, @Retetion은 애노테이션을 만들 때 사용하는 메타 애노테이션이고,
중요한건 @Test, @Tag를 붙임으로써 기존에 여러 애노테이션으로 설정했던 부분을
하나의 애노테이션으로 설정한다는 것이다.
아래 예제는 이전 예제와 같은 코드가 된다.
*/
@FastTest
@DisplayName("스터디 만들기 fast")
void create_new_study12() {
System.out.println("fast");
}
@SlowTest
@DisplayName("스터디 만들기 slow")
void create_new_study_again6() {
System.out.println("slow");
}
// 특정 테스트를 반복할 수 있다. 다음 예제는 반복 횟수를 10회로 설정했다.
@RepeatedTest(10)
void repeatTest() {
System.out.println("test");
}
// @RepeatedTest는 반복 테스트의 이름을 설정할 수 있고, RepetitionInfo 인자를 받아서 반복 횟수를 출력할 수 있다.
/*
@ParameterizedTest는 @ValueSource에 있는 배열의 요소들을 하나하나 불러와 반복하는 테스트이다.
@RepeatedTest와 마찬가지로 name 옵션으로 이름을 지정할 수 있다.
*/
@DisplayName("스터디 만들기")
@ParameterizedTest(name = "{index} {displayName} message={0}")
@ValueSource(strings = {"날씨가", "많이", "추워지고", "있네요."})
void parameterizedTest(String message) {
System.out.println(message);
}
}
3-2. live-study dash board
main
package w4.hw1;
import org.kohsuke.github.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ApplicationHW1 {
public static final String gitToken = "";
public static final String REPOSITORY = "whiteship/live-study";
public static final String NO_ISSUE_MESSAGE = "No issue";
private GitHub gitHub;
public static void main(String[] args) throws IOException{
ApplicationHW1 applicationHW1 = new ApplicationHW1();
try {
applicationHW1.run();
} catch (Exception e) {
throw new IOException("Check your github token");
}
}
public void run() throws IOException{
gitHub = new GitHubBuilder().withOAuthToken(gitToken).build();
gitHub.checkApiUrlValidity();
// 레지 이슈 불러옴
List<GHIssue> issues = getIssue();
// 이름 저장 (중복되지 않은 이름)
List<String> usersName = getUsers(issues);
// 이름과 참여 수 저장
HashMap<String, Integer> userParticipant = checkParticipant(usersName);
showPercent(issues, userParticipant);
}
public void showPercent(List<GHIssue> issues, HashMap<String, Integer> userParticipant){
for(Map.Entry<String, Integer> entry : userParticipant.entrySet()){
double percent = Math.round(entry.getValue() / (double)issues.size()*100.0*100.0)/100.0;
System.out.println("User : '"+ entry.getKey() +"' issueProgress : '" + percent +"%'");
}
}
public HashMap<String, Integer> checkParticipant(List<String> usersName){
HashMap<String, Integer> userParticipant = new HashMap<>();
for (String name : usersName) {
if (userParticipant.containsKey(name)) {
userParticipant.put(name, userParticipant.get(name) + 1);
} else {
userParticipant.put(name, 1);
}
}
return userParticipant;
}
public List<String> getUsers(List<GHIssue> issues) throws IOException {
List<String> usersName = new ArrayList<>();
for(GHIssue issue : issues){
for(GHIssueComment comment : issue.getComments()){
usersName.add(comment.getUser().getLogin());
}
}
return usersName;
}
public List<GHIssue> getIssue() throws IOException {
List<GHIssue> issues = gitHub.getRepository(REPOSITORY).getIssues(GHIssueState.ALL);
nullcheckIssue(issues);
return issues;
}
public void nullcheckIssue(List<GHIssue> issues){
if(issues.size() == 0){
throw new IndexOutOfBoundsException(NO_ISSUE_MESSAGE);
}
}
}
test-code
import org.junit.jupiter.api.Test;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubBuilder;
import java.io.IOException;
class ConnectTest {
@Test
public void connectGithub() throws IOException {
try {
String gitToken = "";
GitHub gitHub = new GitHubBuilder().withOAuthToken(gitToken).build();
gitHub.checkApiUrlValidity();
} catch (Exception e) {
throw new IOException("Check your github token");
}
}
}
import org.junit.jupiter.api.Test;
import org.kohsuke.github.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class IssueTest {
public static final String gitToken = "";
@Test
public void getIssue() throws IOException {
GitHub gitHub = new GitHubBuilder().withOAuthToken(gitToken).build();
List<GHIssue> issues = gitHub.getRepository("whiteship/live-study").getIssues(GHIssueState.ALL);
assertEquals(18, issues.size());
}
@Test
public void getComment() throws IOException{
GitHub gitHub = new GitHubBuilder().withOAuthToken(gitToken).build();
List<GHIssue> issues = gitHub.getRepository("whiteship/live-study").getIssues(GHIssueState.ALL);
List<String> users = new ArrayList<>();
for(GHIssue issue : issues){
for(GHIssueComment comment : issue.getComments()){
users.add(comment.getUser().getLogin());
}
}
System.out.println(users);
System.out.println(users.size());
}
@Test
public void checkDuplicate() throws IOException{
GitHub gitHub = new GitHubBuilder().withOAuthToken(gitToken).build();
List<GHIssue> issues = gitHub.getRepository("whiteship/live-study").getIssues(GHIssueState.ALL);
List<String> usersName = new ArrayList<>();
for(GHIssue issue : issues){
for(GHIssueComment comment : issue.getComments()){
usersName.add(comment.getUser().getLogin());
}
}
System.out.println(usersName);
System.out.println(usersName.size());
HashMap<String, Integer> userParticipant = new HashMap<>();
for (String name : usersName) {
if (userParticipant.containsKey(name)) { // if there is duplicate name
userParticipant.put(name, userParticipant.get(name) + 1);
} else {
userParticipant.put(name, 1);
}
}
System.out.println(userParticipant);
}
}
3-3. linkedList
... 추가 예정
참고
자바의 정석 3판 - 남궁성
https://www.geeksforgeeks.org/break-statement-in-java/?ref=gcse
https://www.geeksforgeeks.org/continue-statement-in-java/?ref=gcse
https://kils-log-of-develop.tistory.com/349
https://lob-dev.tistory.com/entry/Live-StudyWeek-04-%EC%A0%9C%EC%96%B4%EB%AC%B8-%EA%B3%BC%EC%A0%9C
https://www.notion.so/Live-Study-4-ca77be1de7674a73b473bf92abc4226a
'Language > Java-Weekly-study' 카테고리의 다른 글
[Java] W06: 자바 상속 (0) | 2022.06.26 |
---|---|
[Java] W05: 자바 클래스 (0) | 2022.06.19 |
[Java] W03: 자바 연산자 (0) | 2022.06.03 |
[Java] W02: 자바 데이터 타입, 변수 그리고 배열 (0) | 2022.05.29 |
[Java] W01: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가 (0) | 2022.05.21 |