자바가 제공하는 제어문을 학습하세요.
- 선택문
- 반복문
선택문
if/else 문
- if 문에 들어가는 조건식이 참인 경우 if 내 블록 코드 실행
int a = 1;
if(a>0) {
a += 5;
}
- if문에 들어가는 조건식이 참이 아닌 경우 else if 문의 조건을 비교하고 else if 문의 조건이 참이 아닌 경우 else문 내 블록 코드 실행
int a = 1;
if(a>0) {
a += 5;
}else if(a>1) {
a += 6;
}else if(a>2) {
a += 7;
}else {
a += 10;
}
- 중첩 if문 사용 가능
int a = 1;
if(a>0) {
a += 5;
if(a==0) {
return a;
}
}
switch/case 문
- switch의 매개변수에 맞는 조건에 따라 case문을 실행하여 다중 if문의 단점을 개선
- 각각의 case문에 break 키워드를 사용하지 않으면 switch문을 탈출하지 않고 그 다음 case문을 실행하기 때문에 꼭 break 키워드를 써주어야 한다.
- 자바 13부터 switch/case 문과 유사한 switch 연산자가 만들어졌다.
public static void main(String[] args) {
String day = "FRIDAY";
switch (day) {
case "MONDAY":
case "TuDAY":
case "WENDAY":
System.out.println("WENDAY");
break;
case "NOT":
System.out.println("not");
default:
System.out.println("default");
}
}
반복문
for문
- 초기화 ; 조건문 ; 증감식
- 초기화한 값을 가지고 조건문을 검사해 초기화한 값을 증감식의 조건에 따라 증감해가며 내부 코드를 반복하는 구문
for(int i = 0 ; i < array.length() ; i++) {
// 0 ~ array.length()만큼 반복 수행
}
while문
- 조건이 참인 경우 계속하여 반복하는 구문
- 무한루프 주의
- 유한적인 조건을 주거나 while문 내부에 탈출 조건을 명시해야 한다.
int i = 0;
while(i<10){
i++; // i가 10 이상일 경우 반복 해제됨
}
do-while문
- 조건이 하단에 있는 구문
- 구문을 실행한 후 마지막에 조건을 확인함으로 구문을 반드시 한번 이상 실행
- 하단 조건 이후 세미콜론을 써야 한다.
int i = 0;
do{
i++; // i가 10 이상일 경우 반복 해제됨
}while(i<10);
for-each문
- for문과 동일하지만 for문보다 직관적이며, 반복할 객체를 하나씩 차례대로 가져와 사용
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
list.add("Hello");
}
for (String s : list) {
System.out.println(s);
}
}
Iterator
- iterator는 java의 collection에 저장되어 있는 데이터를 읽어오는 방법을 표준화한 기술 중 하나이다.
- hasNext(), next(), remove() 메소드를 이용해 데이터를 사용할 수 있다.
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Hello1");
set.add("Hello2");
set.add("Hello3");
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
it.remove();
}
}
과제 0. JUnit 5 학습하세요.
- 인텔리J, 이클립스, VS Code에서 JUnit 5로 테스트 코드 작성하는 방법에 익숙해 질 것.
- 이미 JUnit 알고 계신분들은 다른 것 아무거나!
- 더 자바, 테스트 강의도 있으니 참고하세요~
Maven Dependencies
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
Junit 5 가 4 버전과 달라진 점
접근 제어자 변경
- public 접근 제어자가 필요했던 4 버전과 달리 5 버전은 패키지 범위에서 실행이 가능하다.
확장성
- Extension 하나로 여러 규칙을 통합, 조합 가능하다.
- -> @ExtendWith, @RegisterExtension, Java ServiceLoader
분리된 jar(모듈)
- Junit 4의 Jar→Vintage(4 버전과의 호환성), Jupiter(5 버전 모듈), Platform(Extension, 실행, 관리 등)
다양해진 assert 방식
- assertThat → assertThrows, assertEquals, assertTimeout, assertNotNull 등..
한번에 여러 테스트 실행 가능
- 기존에 하나의 테스트가 실패하면 더 이상 진행되지 않는 Junit 4의 문제점을 해결
assertAll(
() -> assertNotNull(),
() -> assertEquals(),
() -> assertTrue(),
() -> assertTimeout(),
);
Dynamic Test
- 테스트가 런타임 환경으로 생성되고 수행이 가능해졌다.
@TestFactory
Stream<DynamicNode> dynamicTests() {
return Stream.of("AAA","BBB","CCC","DDD")
.map(text -> dynamicTest("AAAEEETTT", () -> assertTrue(text.contains("AAA")));
}
Test 순서 설정
- @Order(정수 값) 을 이용하여 우선순위를 정한다.
테스트에 대한 환경 변수 설정
- @EnabledIfEnvironmentVariable : 지정된 환경 변수 값이 지정된 정규식과 일치하는 경우 활성화
- @EnabledIfSystemProperty : JVM 시스템에 따라서 테스트를 활성화
- @EnabledOnJre : 지정된 JRE (Java Runtime Environment) 버전에서만 활성화
- @EnabledForJreRange : min으로 지정된 jre와 max로 지정된 jre 버전 사이에서 활성화
- @EnabledOnOs : 지정된 운영 체제에서만 활성화
@EnabledIfEnvironmentVariable(named = "GDMSESSION", matches = "ubuntu") // ununtu 서버에서 실행
@EnabledIfSystemProperty(named = "java.vm.vendor", matches = "Oracle.*") // Oracle jvm에서 실행
@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_13) // 8 ~ 13 버전의 자바에서 실행
@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9}) // 8, 9 버전의 자바에서만 실행
@EnabledOnOs({OS.WINDOWS, OS.LINUX}) // windows와 linux에서 실행
기본 Annotation
@BeforeAll
- 해당 annotation이 달린 메서드가 현재 클래스의 모든 테스트 메서드보다 먼저 실행된다.
- 해당 메서드는 static 이어야 한다.
- 이전의 @BeforeClass와 동일
@BeforeEach
- 해당 annotation이 달린 메서드가 각 테스트 메서드 전에 실행된다.
- 이전의 @Before와 동일
@DisplayName
- 테스트 클래스 또는 테스트 메서드의 이름을 정의할 수 있다.
@Disable
- 테스트 클래스 또는 메서드를 비활성화 할 수 있다.
- 예전의 @Ignore와 동일
@AfterAll
- 해당 annotation이 달린 메서드가 현재 클래스의 모든 테스트 메소드보다 이후에 실행된다.
- 해당 메서드는 static 이어야 한다.
- 이전의 @AfterClass와 동일
@AfterEach
- 해당 annotation이 달린 메서드가 각 테스트 메서드 이후에 실행된다.
- 이전의 @After와 동일
Assertions
- org.junit.jupiter.api.Assertions로 이동
assertAll, assertTrue
- assertAll()을 사용하여 assertions을 그룹화하여 그룹 내에서 실패한 assertions를 MultipleFailuresError와 함께 기록할 수 있다.
- 즉 실패의 정확한 위치를 파악할 수 있기 때문에 복잡한 assertions를 만들어도 안전하게 사용할 수 있다.
assertThrows
assertTimeout
@Test
static void assertTimeoutTest() {
assertTimeout(ofSeconds(1), () -> {
// 1초 이내에 수행해야함
});
}
Assumptions
- 특정 조건이 충족되는 경우에만 테스트를 실행하는데 사용된다.
- 일반적으로 테스트가 제대로 실행되기 위해 필요한 외부 조건에 사용된다.
- 테스트와 직접적인 관련은 없다.
- assumptions가 실패하면 TestAbortedException이 발생하고 테스트는 수행되지 않는다.
assumeTrue(), assumeFalse(), assumingThat()
Dynamic Test
@TestFactory
- 해당 annotation이 달린 메서드는 동적 테스트를 위한 testfactory 메서드이다.
- 런타임에 생성된 테스트 케이스를 선언하고 실행할 수 있다.
- e.g. 각각 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를 리턴해야 한다.
ETC
@Nested
- 중첩된 비정적 테스트 클래스임을 나타낸다.
- 테스트 클래스 안에서 내부 클래스를 정의해 테스트를 계층화할 수 있다.
- 내부 클래스로 정의하기 때문에 부모 클래스의 멤버 필드에 접근할 수 있고, Before / After와 같은 테스트 생명주기에 관계된 메소드들도 계층에 맞게 동작한다.
@Tag
- 테스트 필터링을 위한 태그를 선언할 수 있다.
@ExtendWith
- 사용자 정의 확장명을 등록하는데 사용된다.
@RepeatedTest
- @RepeatedTest(반복횟수)를 이용하면 해당 테스트를 반복 실행할 수 있다.
과제 1. live-study 대시 보드를 만드는 코드를 작성하세요.
- 깃헙 이슈 1번부터 18번까지 댓글을 순회하며 댓글을 남긴 사용자를 체크 할 것.
- 참여율을 계산하세요. 총 18회에 중에 몇 %를 참여했는지 소숫점 두자리가지 보여줄 것.
- Github 자바 라이브러리를 사용하면 편리합니다.
- 깃헙 API를 익명으로 호출하는데 제한이 있기 때문에 본인의 깃헙 프로젝트에 이슈를 만들고 테스트를 하시면 더 자주 테스트할 수 있습니다.
package gitlivestudy;
import org.kohsuke.github.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LiveStudyExample {
public static void main(String[] args) throws IOException {
String myToken = "";
GitHub github = new GitHubBuilder().withOAuthToken(myToken).build();
GHRepository ghRepository = github.getRepository("whiteship/live-study");
Map<String,Double> userMap = new HashMap<>();
List<GHIssue> issues = ghRepository.getIssues(GHIssueState.ALL);
for (GHIssue issue : issues) {
List<GHIssueComment> ghIssueComments = issue.getComments();
for (GHIssueComment ghIssueComment : ghIssueComments) {
String name = ghIssueComment.getUser().getName();
userMap.put(name,userMap.getOrDefault(name,0.0) + 1);
}
}
for (String s : userMap.keySet()) {
double v = (userMap.get(s) / 18) * 100;
System.out.println(s + " : " + String.format("%.2f",v));
}
}
}
과제 2. LinkedList를 구현하세요
- LinkedList에 대해 공부하세요.
- 정수를 저장하는 ListNode 클래스를 구현하세요.
- ListNode add(ListNode head, ListNode nodeToAdd, int position)를 구현하세요.
- ListNode remove(ListNode head, int positionToRemove)를 구현하세요.
- boolean contains(ListNode head, ListNode nodeTocheck)를 구현하세요.
ListNode.java
package linkedlistex;
public class ListNode {
int data;
ListNode link;
public ListNode() {
}
public ListNode(int data) {
this.data = data;
}
ListNode add(ListNode head, ListNode nodeToAdd, int position) {
ListNode node = head;
for(int i = 0; i < position -1 ; i++) {
node = node.link;
}
nodeToAdd.link = node.link;
node.link = nodeToAdd;
return head;
}
ListNode remove(ListNode head, int positionToRemove) {
ListNode node = head;
if(positionToRemove == 0) {
ListNode deleteNode = node;
head = node.link;
deleteNode.link = null;
return deleteNode;
}
for(int i = 0; i < positionToRemove -1 ; i++) {
node = node.link;
}
ListNode deleteNode = node.link;
node.link = deleteNode.link;
deleteNode.link = null;
return deleteNode;
}
boolean contains(ListNode head, ListNode nodeTocheck) {
while(head.link != null){
if(head.link == nodeTocheck) {
return true;
}
head = head.link;
}
return false;
}
}
ListNodeTest.java
package linkedlistex;
import org.junit.jupiter.api.*;
import java.util.ArrayList;
import java.util.List;
class ListNodeTest {
private List<Integer> array;
private ListNode listNode;
private static final int[] ADD_DATA = {1,2,4,3};
@BeforeEach
void init() {
array = new ArrayList<>();
listNode = new ListNode();
ListNode first = new ListNode(1);
ListNode second = new ListNode(2);
ListNode third = new ListNode(3);
this.listNode = first;
first.link = second;
second.link = third;
}
@Test
void add() {
listNode = listNode.add(listNode, new ListNode(4), 2);
while (listNode != null) {
array.add(listNode.data);
listNode = listNode.link;
}
for (int i = 0 ; i < array.size() ; i++) {
Assertions.assertEquals(ADD_DATA[i], array.get(i));
}
}
@Test
void delete() {
ListNode removeNode = listNode.remove(this.listNode,0);
Assertions.assertEquals(1,removeNode.data);
}
@Test
void contains() {
boolean contains = listNode.contains(listNode, new ListNode(2));
Assertions.assertEquals(contains,true);
}
}
과제 3. Stack을 구현하세요.
- int 배열을 사용해서 정수를 저장하는 Stack을 구현하세요.
- void push(int data)를 구현하세요.
- int pop()을 구현하세요.
Stack.java
package stackex;
import java.util.ArrayList;
import java.util.List;
public class Stack {
public List<Integer> array = new ArrayList<>();
public void push(int data) {
array.add(data);
}
public int pop() {
if(array.size() == 0) {
return 0;
} else {
return array.remove(array.size()-1);
}
}
}
StackTest.java
package stackex;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class StackTest {
private Stack stack;
private static final int[] PUSH_DATA = {5,4,3,2,1};
@Test
void push() {
Stack stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
for (int i=0;i<PUSH_DATA.length;i++) {
Assertions.assertEquals(PUSH_DATA[i],stack.pop());
}
}
}
과제 4. 앞서 만든 ListNode를 사용해서 Stack을 구현하세요.
- ListNode head를 가지고 있는 ListNodeStack 클래스를 구현하세요.
- void push(int data)를 구현하세요.
- int pop()을 구현하세요.
ListNodeStack.java
package linkedliststackex;
import linkedlistex.ListNode;
import java.util.ArrayList;
import java.util.List;
public class ListNodeStack {
static int top;
ListNode node;
public ListNodeStack() {
this.node = null;
this.top = -1;
}
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);
}
}
public int pop() {
if(top == -1) {
return top;
} else {
return node.remove(node,top--).getData();
}
}
}
ListNodeStackTest.java
package linkedliststackex;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class ListNodeStackTest {
ListNodeStack listNodeStack;
private static final int[] ADD_DATA = {5,4,3,2,1};
@Test
void Test() {
listNodeStack = new ListNodeStack();
listNodeStack.push(1);
listNodeStack.push(2);
listNodeStack.push(3);
listNodeStack.push(4);
listNodeStack.push(5);
for(int i=0; i<ADD_DATA.length; i++) {
Assertions.assertEquals(ADD_DATA[i],listNodeStack.pop());
}
}
}
과제 5. Queue를 구현하세요.
- 배열을 사용해서 한번
- ListNode를 사용해서 한번.
QueueExample.java
package queueex;
import java.util.NoSuchElementException;
public class QueueExample {
private int[] array;
private int maxSize;
private int front;
private int rear;
QueueExample() {
final int DEFAULT_QUEUE_SIZE = 11;
this.array = new int[DEFAULT_QUEUE_SIZE];
this.maxSize = DEFAULT_QUEUE_SIZE;
this.front = 0;
this.rear = 0;
}
public QueueExample(int maxSize) {
this.array = new int [maxSize + 1];
this.maxSize = maxSize + 1;
this.front = 0;
this.rear = 0;
}
public boolean enQueue(int data) {
if ((this.rear + 1) % this.maxSize == this.front)
throw new IllegalStateException("full");
this.rear = (this.rear + 1) % this.maxSize;
this.array[this.rear] = data;
return true;
}
public Integer deQueue() {
if(this.front == this.rear){
throw new NoSuchElementException();
}
int removed = element();
this.front = (this.front + 1) % this.maxSize;
return removed;
}
public Integer element() {
if(this.front == this.rear) throw new NoSuchElementException("Queue is empty...");
return this.array[(this.front + 1) % this.maxSize];
}
}
QueueExampleTest.java
package queueex;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class QueueExampleTest {
final int FIRST_DATA_VALUE = 1;
final int SECOND_DATA_VALUE = 2;
final int THIRD_DATA_VALUE = 3;
@Test
void enqueue() {
QueueExample queue = new QueueExample();
Assertions.assertAll(
() -> Assertions.assertTrue(queue.enQueue(FIRST_DATA_VALUE)),
() -> Assertions.assertTrue(queue.enQueue(SECOND_DATA_VALUE)),
() -> Assertions.assertTrue(queue.enQueue(THIRD_DATA_VALUE))
);
}
@Test
void dequeue() {
QueueExample queue = new QueueExample();
Assertions.assertAll(
() -> Assertions.assertTrue(queue.enQueue(FIRST_DATA_VALUE)),
() -> Assertions.assertTrue(queue.enQueue(SECOND_DATA_VALUE)),
() -> Assertions.assertTrue(queue.enQueue(THIRD_DATA_VALUE)),
() -> {
int removed = queue.deQueue();
Assertions.assertEquals(removed, FIRST_DATA_VALUE);
},
() -> {
int removed = queue.deQueue();
Assertions.assertEquals(removed, SECOND_DATA_VALUE);
},
() -> {
int removed = queue.deQueue();
Assertions.assertEquals(removed, THIRD_DATA_VALUE);
}
);
}
}
Queue<Integer> queue = new LinkedList<>();
queue.offer(1); // null 리턴
queue.add(1); // 예외 발생
queue.poll(); // null 리턴
queue.remove(); // 예외 발생
queue.peek(); // null 리턴
queue.element(); // 예외 발생
'Back-end > java' 카테고리의 다른 글
스터디 6주차 - 상속 (0) | 2021.06.30 |
---|---|
스터디 5주차 - 클래스 (0) | 2021.06.30 |
스터디 3주차 - 연산자 (0) | 2021.06.28 |
스터디 2주차 - 자바 데이터 타입, 변수 그리고 배열 (0) | 2021.06.28 |
스터디 1주차 - JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가 (0) | 2021.06.24 |