목표
- 자바가 제공하는 제어문을 학습하세요.
학습할 것
- 선택문
- 반복문
과제
- 과제 0. JUnit 5 학습하세요.
- 과제 1. live-study 대시 보드를 만드는 코드를 작성하세요.
- 과제 2. LinkedList를 구현하세요.
- 과제 3. Stack을 구현하세요.
- 과제 4. 앞서 만든 ListNode를 사용해서 Stack을 구현하세요.
- 과제 5. Queue를 구현하세요.
선택문
자바는 순차적으로 위에서 아래로 차례대로 실행합니다. 실행 순서는 조건에 의해 변경할 수 있습니다. 실행 순서를 변경하기 위해 제어문(Control Statement)을 사용합니다.
제어문은 다음과 같이 구분합니다.
1) 선택문: if 문, if ~ else 문, switch 문
2) 반복문: while 문, do ~ while 문, for 문
3) 점프문: goto 문, continue 문, break 문
특정한 기준(조건)에 해당할 때 지정한 문장을 실행할 것인지 안할 것인지 결정할 때 선택문(조건문)을 사용합니다.
if 문
if 문은 "만약 ~ 이라면(if)을 하고 그렇지 않으면(else) ~를 한다" 라는 논리 구조로 만약 ~ 부분의 조건을 조건식으로 표기합니다.
if(조건식) {
// 조건식이 맞으면 수행할 문장
}
if ~ else 문
if 문은 else와 함께 사용하여 하나의 세트 문장으로 인식합니다. else는 false 선택일 때 처리하기 위해서 사용합니다.
if (조건식) {
// 조건식이 맞으면 수행할 문장
} else {
// 조건식이 안 맞으면 수행할 문장
}
중첩 if 문
else 문 안에 또 다른 if 문을 포함하는 것을 중첩 if 문이라고 합니다. 여러 조건에 의해 선택하는 경우에 중첩합니다.
if 문은 또 다른 if 문이나 if ~ else 문을 포함한 어떤 문장도 얼마든지 중첩할 수 있습니다.
if (조건식1) {
// 위의 조건식과 맞으면 수행할 문장
} else if (조건식2) {
// 위의 조건식과 맞으면 수행할 문장
} else {
// 나머지의 경우 수행할 문장
}
switch 문
조건문의 경우의 수가 많은 경우에는 if 문 대신 switch 문을 사용하면 간결하고 가독성이 높습니다. switch 문은 다중 선택문 입니다.
switch (식) {
case 정수1:
// 식의 결과 값이 정수1이면 실행할 문장1;
break;
case 정수2:
// 식의 결과 값이 정수2이면 실행할 문장2;
break;
case 정수n:
// 식의 결과 값이 정수n이면 실행할 문장n;
break;
default:
// 옵션, 식의 결과 값과 일치하는 case 문이 없을 때 실행할 문장
}
반복문
사람이 하기 힘든, 귀찮은 반복적인 일을 반복문을 통해 기계가 대신 수행할 수 있습니다.
while
while 문은 반복 조건이 참(true)이면 중괄호 구간을 반복적으로 실행하고 조건이 거짓(false)이면 반복문을 실행하지 않고 빠져나옵니다.
while(조건){
// 반복 실행 영역
}
int i = 0;
while(i < 5){
System.out.println(i);
i++;
}
// 0
// 1
// 2
// 3
// 4
- i의 값이 10보다 작다면 true, 크다면 false가 됩니다. 구간 내 작업을 수행하고 크기가 증가하는 i의 값을 while문의 조건절에서 매번 확인하고 계속 반복을 해야하는지를 판단합니다.
for
for문은 특정한 횟수만큼 반복 실행을 하는 경우에 자주 사용됩니다.
for(초기화; 종료조건; 반복실행){
반복적으로 실행될 구문
}
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
// 0
// 1
// 2
// 3
// 4
- 초기화 : 반복문이 실행될 때 1회 실행됩니다.
- 종료조건 : 초기화가 실행된 후에 종료조건이 실행됩니다. 종료조건의 값이 false일 때까지 반복문의 중괄호 구간의 코드가 반복 실행됩니다.
- 중괄호 구간의 실행이 끝나면 반복 실행이 실행됩니다. 일반적으로 이 곳에 i++와 같이 변수를 증가시키는 로직이 위치하고, 이것이 실행된 후에 종료조건이 실행됩니다. 종료조건이 false가 될 때까지 이 과정이 반복됩니다.
break
반복 작업을 중간에 중단시키고 싶다면 break를 사용하면 됩니다.
for (int i = 0; i < 5; i++) {
if (i == 3)
break;
System.out.println("i");
}
// 0
// 1
// 2
continue
현재 반복 작업을 건너뛰고 다음 차례 반복 작업을 하고 싶다면 continue를 사용하면 됩니다.
for (int i = 0; i < 5; i++) {
if (i == 2)
continue;
System.out.println("Coding Everybody " + i);
}
// 0
// 1
// 3
// 4
과제 0. JUnit 5 학습하세요.
목표
- 인텔리J, 이클립스, VS Code에서 JUnit 5로 테스트 코드 작성하는 방법에 익숙해 질 것.
- 이미 JUnit 알고 계신분들은 다른 것 아무거나!
- 더 자바, 테스트 강의도 있으니 참고하세요~
기본 Annotation
@DisplayName
- 테스트 클래스 또는 테스트 메서드의 이름을 정의할 수 있습니다.
@Disable
- 테스트 클래스 또는 메서드를 비활성화할 수 있습니다.
@BeforeAll
- 해당 annotation 이 달린 메서드가 현재 클래스의 모든 테스트 메서드보다 먼저 실행됩니다.
- 해당 메서드는 static 이어야 합니다.
@BeforeEach
- 해당 annotation 이 달린 메서드가 각 테스트 메서드 전에 실행됩니다.
@AfterAll
- 해당 annotation 이 달린 메서드가 현재 클래스의 모든 테스트 메소드보다 이후에 실행됩니다.
- 해당 메서드는 static 이어야 합니다.
@AfterEach
- 해당 annotation 이 달린 메서드가 각 테스트 메서드 이후에 실행됩니다.
Assertions and Assumptions
Assertions
- Assert 구문은 어떤 조건이 참인지 검증하는 방법이다. 단언한 조건이 참이 아니면 테스트는 그 자리에서 멈추고 실패합니다.
- assertTrue, assertThat 등이 있습니다.
- assertAll()을 사용하여 assertions 을 그룹화하여 그룹 내에서 실패한 assertions 을 MultipleFailuresError 와 함께 기록할 수 있습니다.
Assumptions
- 특정 조건이 충족되는 경우에만 테스트를 실행하는 데 사용됩니다.
- 일반적으로 테스트가 제대로 실행되기 위해 필요한 외부 조건에 사용됩니다.
- 테스트와 직접적인 관련은 없습니다.
- assumptions 이 실패하면 TestAbortedException이 발생하고 테스트는 수행되지 않습니다.
- assumeTrue(), assumeFalse(), assumingThat() 등이 있습니다.
Exception Testing
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); }); }
Test Suites
@SelectPackages
- Test Suites 를 실행할 때 선택할 패키지 이름 지정합니다.
SelectClasses
- Test Suites 를 실행할 때 선택할 클래스 지정합니다.
- 각 테스트는 하나의 패키지에 있지 않아도 됩니다.
Dynamic Tests
@TestFactory
해당 annotation 이 달린 메서드는 동적 테스트를 위한 test factory 메서드입니다.
런타임에 생성된 테스트 케이스를 선언하고 실행할 수 있습니다.
각각 in, out 이라는 두 개의 ArrayList 를 사용하여 단어를 번역합니다.
@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)); }) ); }
- @TestFactory 메서드는 private 또는 static 이면 안됩니다.
- 테스트 수는 동적이며, ArrayList 크기에 따라 달라집니다.
- @TestFactory 메서드는 Stream, Collection, Iterable 또는 Iterator 를 return 해야 합니다.
과제 1. live-study 대시 보드를 만드는 코드를 작성하세요.
목표
- 깃헙 이슈 1번부터 18번까지 댓글을 순회하며 댓글을 남긴 사용자를 체크 할 것.
- 참여율을 계산하세요. 총 18회에 중에 몇 %를 참여했는지 소숫점 두자리가지 보여줄 것.
- Github 자바 라이브러리를 사용하면 편리합니다.
- 깃헙 API를 익명으로 호출하는데 제한이 있기 때문에 본인의 깃헙 프로젝트에 이슈를 만들고 테스트를 하시면 더 자주 테스트할 수 있습니다.
Github.java
public class Github {
private static final String LIVE_STUDY_PATH = "whiteship/live-study";
private static final int TOTAL_NUMBER_OF_ISSUE = 18;
private GitHub github;
public Github(String token) throws IOException {
github = new GitHubBuilder().withOAuthToken(token).build();
}
public List<GithubUserReport> getGithubUserReportOfParticipation() throws IOException {
Map<String, Integer> numberOfParticipationCounter = new HashMap<>();
List<GHIssue> issues = github.getRepository(LIVE_STUDY_PATH).getIssues(GHIssueState.ALL);
for (GHIssue issue : issues) {
Set<String> notDuplicatedUser = getNotDuplicatedUserCommentedInIssue(issue);
updateNumberOfParticipationCounter(numberOfParticipationCounter, notDuplicatedUser);
}
return getGithubUserReportOfParticipation(numberOfParticipationCounter);
}
private Set<String> getNotDuplicatedUserCommentedInIssue(GHIssue issue) throws IOException {
Set<String> notDuplicatedUser = new HashSet<>();
for (GHIssueComment ghIssueComment : issue.getComments()) {
String user = ghIssueComment.getUser().getLogin();
notDuplicatedUser.add(user);
}
return notDuplicatedUser;
}
private void updateNumberOfParticipationCounter(Map<String, Integer> counter, Set<String> notDuplicatedUser) {
for (String user : notDuplicatedUser) {
if (counter.containsKey(user)){
counter.put(user, counter.get(user) + 1);
} else {
counter.put(user, 1);
}
}
}
private List<GithubUserReport> getGithubUserReportOfParticipation(Map<String, Integer> counter) {
return counter.entrySet().stream()
.map(e -> {
String username = e.getKey();
int numberOfParticipation = e.getValue();
double rate = calculateRateOfParticipant(e.getValue());
return new GithubUserReport(username, numberOfParticipation, rate);
})
.sorted(Comparator.comparing(GithubUserReport::getUsername))
.collect(Collectors.toList());
}
private double calculateRateOfParticipant(int value) {
return (double) (value * 100) / TOTAL_NUMBER_OF_ISSUE;
}
}
GithubUserReport.java
public class GithubUserReport {
private final String username;
private final int numberOfParticipation;
private final double rateOfParticipation;
public GithubUserReport(String username, int numberOfParticipation, double rateOfParticipation) {
this.username = username;
this.numberOfParticipation = numberOfParticipation;
this.rateOfParticipation = rateOfParticipation;
}
public String getUsername() {
return username;
}
public int getNumberOfParticipation() {
return numberOfParticipation;
}
public double getRateOfParticipation() {
return rateOfParticipation;
}
}
GithubTest.java
class GithubTest {
@Test
void printGithubUserReportOfParticipation() throws IOException {
final String TITLE_ALIGNMENT = "| %20s | %5s | %5s |";
final int WIDTH = 45;
final String ROW_ALIGNMENT = "| %20s | %8d | %8.2f |";
final String HYPHEN = "-";
final String TOKEN = "github 토큰을 넣으면 됩니당";
Github github = new Github(TOKEN);
System.out.println(HYPHEN.repeat(WIDTH));
System.out.println(String.format(TITLE_ALIGNMENT, "Github ID", "참여 횟수", "참여율(%)"));
System.out.println(HYPHEN.repeat(WIDTH));
List<GithubUserReport> userReports = github.getGithubUserReportOfParticipation();
userReports.forEach(userReport -> {
System.out.println(
String.format(ROW_ALIGNMENT,
userReport.getUsername(),
userReport.getNumberOfParticipation(),
userReport.getRateOfParticipation()));
});
System.out.println(HYPHEN.repeat(WIDTH));
}
}
---------------------------------------------
| Github ID | 참여 횟수 | 참여율(%) |
---------------------------------------------
| 0417taehyun | 3 | 16.67 |
| 1031nice | 3 | 16.67 |
| 2yeseul | 2 | 11.11 |
| 372dev | 3 | 16.67 |
| 9m1i9n1 | 3 | 16.67 |
| Ahnyezi | 1 | 5.56 |
| BaeJi77 | 2 | 11.11 |
| ByungJun25 | 3 | 16.67 |
| CODEMCD | 3 | 16.67 |
...
과제 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()을 구현하세요.
과제 5. Queue를 구현하세요.
목표
- 배열을 사용해서 한번
- ListNode를 사용해서 한번.
출처
'Java' 카테고리의 다른 글
[Java] 클래스 (live-study 5주차) (0) | 2020.12.18 |
---|---|
[Java] 연산자 (live-study 3주차) (0) | 2020.11.27 |
[Java] 자바 데이터 타입, 변수 그리고 배열 (live-study 2주차) (0) | 2020.11.21 |
[Java] JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가 (live-study 1주차) (0) | 2020.11.21 |
[이펙티브 자바] 일반적인 프로그래밍 원칙 (0) | 2020.09.21 |