티스토리 뷰
4주 차 시작합니다!
선택문 (switch)?
주어진 조건 값의 결과에 따라 프로그램이 다른 명령을 수행하도록 하는 일종의 조건문이다.
-
모든 값, 범위를 기반으로 판단하는 if 문과 달리 정수 값이나 열거된 값 또는 문자, 문자열만을 사용할 수 있다.
-
컴파일러를 통해 실행 경로를 설정하는 점프 테이블이라는 것이 만들어지게 되어서 많은 조건을 비교하여야 할 때, if else 보다 더 빠른 성능을 보이게 된다.
→ case의 수가 5개 이상이라면, 성능 차이가 보이기 시작한다.
-
if else에 비하여서 좋은 가독성을 가지고 있다.
switch 문
public static String monthCheck(int num){
int days = 0;
switch (num) {
case 1 :
case 3 :
case 5 :
case 7 :
case 8 :
case 10 :
case 12 :
days = 31;
break;
case 4 :
case 6 :
case 9 :
case 11 :
days = 30;
break;
case 2 :
days = 28;
break;
default:
days = -1;
};
return "입력하신 달은 "+days+"일 입니다.";
}
if else 문 (비교 용)
public static String monthCheck(int num){
int days = 0;
if (num == 1 || num == 3 || num == 5 || num == 7 || num == 8 || num == 10 || num == 12){
days = 31;
} else if (num == 4 || num == 6 || num == 9 || num == 11){
days = 30;
} else if (num == 2){
days = 28;
} else {
days = -1;
}
return "입력하신 달은 "+days+"일 입니다.";
}
반복문?
어떠한 명령을 일정한 횟수만큼 반복하여 수행하도록 하는 명령문이다.
1부터 100까지를 더하는 코드를 여러 방법으로 작성해보았다.
while 문
- 조건 식이 맞는 경우 실행되는 반복문이다. (bool 값을 통해 반복한다.)
구조
while(조건식){
//do something
}
// 무한 루프 : 사용시 조건 검증과 break; 을 통해 탈출해야한다.
while(true){
//do something
}
public static void whiles(){
int total = 0;
int loopCount = 1;
while(loopCount <= 100){
total += loopCount;
++loopCount;
}
System.out.println(total);
}
do / while 문
- while 문과 비슷하지만 조건 식이 만족되지 않더라도 무조건 한 번은 실행되는 반복문이다.
구조
do{
//do something
}while(조건식);
// 무한 루프 : 사용시 조건 검증과 break; 을 통해 탈출해야한다.
do{
//do something
}while(true);
코드
public static void doWhiles(){
int total = 0;
int loopCount = 1;
do {
total += loopCount;
++loopCount;
}while(loopCount <= 100);
System.out.println(total);
}
for 문
- 반복된 횟수가 고정된 경우 사용하거나, index 위치나 값이 필요한 경우 사용한다.
구조
for(조건식){
//do something
}
// 무한 루프 : 사용시 조건 검증과 break; 을 통해 탈출해야한다.
// 해당 구문은 디컴파일 시 While(true)로 변경되어 있다.
for(;;){
//do something
}
코드
public static void fors(){
int total = 0;
for (int loopCount = 0; loopCount <= 100; loopCount++) {
total += loopCount;
}
System.out.println(total);
}
labeled for 문
- 각각의 for 문에 대하여서 라벨을 부여함으로써 중첩 for문에서 조건에 따라 중단하거나 계속하게끔 사용하기 좋다.
- 내부에 중첩된 for 문에 대해서도 라벨 부여가 가능하다.
구조
label:
for(조건식){
//do something
}
혹은
label:
for(조건식){
//do something
for(조건식){
//do something
break label;
// 혹은 continue;
}
}
코드
public static void labeledFors(){
int total = 0;
// 무한 루프
loop1: for (;;){
for (int inLoop=0;inLoop<=1000;inLoop++){
total += inLoop;
// 100번을 반복하게 되면 loop1을 탈출한다.
if(inLoop==100) {
break loop1;
}
}
}
System.out.println(total);
}
Enhanced for 문 (for each)
- index 값이 아닌 요소를 통한 값의 순회를 진행한다.
- 가변적인 컬렉션의 값을 처리하기에 좋다.
구조
for(Type variable : collection<Type>, Type[] array){
//do something
}
코드
public static void enhancedFors(){
int total = 0;
int[] numArr = {10,20,30,40,50,60,70,80,90,100};
for (int num : numArr){
total += num;
}
System.out.println(total);
}
HashTable, Vector, Stack의 Enumeration
-
Collection Framework가 만들어지기 전에 사용되던 인터페이스이다.
-
순차 접근 시 컬랙션 객체의 내부가 수정되더라도 이를 무시하고, 끝까지 동작한다
→ Enumeration을 이용해서는 내부 요소를 수정할 방법이 없다. (읽기만 가능하다.)
→ 해당 컬랙션 내부의 수정 메서드를 이용하여야 한다.
Enumeration<String> enumeration = vector.elements();
// 읽어올 요소가 존재한다면, True 요소가 없다면 false를 반환한다.
enumeration.hasMoreElements()
// 다음 요소를 읽어올 때 사용한다.
enumeration.nextElement()
Collection의 Iterator()
Collection Framework 에서 사용되는 Enumeration을 보완한 인터페이스이다.
→ 요소를 제거하는 기능을 포함하였다. (remove)
-
Fail Fast Iterator (ArrayList, HashMap)
-
순차적 접근이 끝나기 전에 객체에 변경이 일어날 경우 예외를 반환한다.
→ 동일한 자원의 수정 발생 시 데이터의 일관성을 보장하기 위함이다.
-
내부적으로 변경, 수정된 횟수를 나타내는 modCount 필드가 있다.
-
하나 이상의 요소가 제거된 경우
-
하나 이상의 요소가 추가된 경우
-
컬렉션이 다른 컬렉션으로 대체되었을 때
-
컬렉션이 정렬될 때 등
→ 구조가 변경될 때마다 카운터가 증가하게 된다..
→ 데이터를 순회하는 동안 expectedModCount에 modCount 값을 저장하고 비교하며,
→ 두 개의 값이 달라질 경우 ConcurrentModificationException()를 발생시킨다.
→ next(), remove(), add(), remove(), forEachRemaining()에서 사용된다.
→ HashTable에도 expectedModCount, modCount를 사용한다.
-
-
-
Fail Safe Iterator (CopyOnWriteArrayList, ConcurrentHashMap)
-
Enumeration와 같이 내부가 수정되더라도 예외가 발생하지 않는다.
-
사실은 컬렉션의 원본이 아닌 복제본을 순회하기 때문이다.
→ 복제된 컬렉션을 관리하기 위해 추가적인 메모리를 사용한다.
-
과제 0. JUnit 5 학습하세요.
JUnit 5를 만들게 된 이유? (JUnit 4의 단점)
-
IDE에 대한 강한 결합도를 해결하기 위하여
-
부족했던 확장성의 해결
→ 하나의 @Runwith에 여러 Rule을 사용하여 확장하고, Runwith들이 결합되지 못했다.
-
하나의 Jar에 포함되어 있던 코드를 분리하였다. (하나의 Jar의 큰 책임)
이전 버전의 문제점을 해결하며 좀 더 단순하고, 확장성 있게 만들기 위해 그런 선택을 하였다고 한다.
그 외에도 외부 라이브러리를 사용해야 했던 Parameter Test 등의 부가 기능을 공식적으로 지원한다.
//넘겨지는 Source의 수 만큼 테스트를 반복한다.
@ParameterizedTest(name = "{index} {displayName} SourceParam = {0}")
@ValueSource(strings = {"1", "2", "3"})
@NullAndEmptySource // CsvSource 등..
void repeatParameterTest(String Param) {
System.out.println("Param = " + Param);
}
// 넘겨지는 정수 값 만큼 테스트 반복.
@RepeatedTest(10)
void repeatTest(String Param) {
System.out.println("test");
}
혹시 Junit 4를 사용하고 있다면, Parameter Test가 필요한 경우
해당 라이브러리를 사용하면 된다.
그 외에도
접근 제어자 변경
- public 접근 제어자가 필요했던 4 버전과 달리 5 버전은 패키지 범위에서 실행이 가능하다.
좋아진 확장성
-
Extension 하나로 여러 규칙을 통합, 조합 가능하다.
→ @ExtendWith, @RegisterExtension, Java ServiceLoader
분리된 Jar (모듈)
- Junit 4의 Jar→Vintage(4 버전과의 호환성), Jupiter(5 버전 모듈), Platform(Extension, 실행, 관리 등)
다양해진 assert 방식
- assertThat → assertThrows, assertEquals, assertTimeout, assertNotNull 등..
한 번에 여러 test를 실행 가능
-
기존에 하나의 테스트가 실패하면 더 이상 진행되지 않는 Junit 4의 문제점을 해결
assertAll( () -> assertNotNull(), () -> assertEquals(), () -> assertTrue(), () -> assertTimeout(), );
등이 변경되었다.
Junit 5의 Test Cycle
// 모든 테스트가 실행되기 이전에 1번 호출된다.
@BeforeAll
public static void beforeAll() {
System.out.println("AppTest.beforeAll");
}
// 모든 테스트가 실행된 이후에 1번 호출된다.
@AfterAll
public static void afterAll() {
System.out.println("AppTest.afterAll");
}
// 각각의 테스트가 실행되기 이전에 호출된다.
@BeforeEach
public void beforeEach() {
System.out.println("AppTest.beforeEach");
}
// 각각의 테스트가 실행된 이후에 호출된다.
@AfterEach
public void afterEach() {
System.out.println ("AppTest.afterEach");
}
JUnit 5의 Dynamic Test
- Junit 5부터는 테스트가 런타임 환경으로 생성되고 수행이 가능하게 되었다.
- 이를 통해 외부 자원을 활용하고, 랜덤 데이터를 생성하여 활용할 수 있다.
@TestFactory
Stream<DynamicNode> dynamicTests() {
return Stream.of("AAA","BBB","CCC","DDD")
.map(text -> dynamicTest("AAAEEETTT", () -> assertTrue(text.contains("AAA")));
}
Junit 5의 Tagging, Filtering
- @Tag 주석을 통해 테스트 클래스 및 메서드에 태그를 지정할 수 있다.
@Tag("fast")
@Tag("User Test")...
Junit 5의 Test 순서 설정
-
@Order(정수 값) : 넘겨진 정수 값을 우선순위로 설정한다.
→ test_1 → test_2 → test_3...
@TestMethodOrder(OrderAnnotation.class)
class OrderedTest {
----------------------------
@Test
@Order(1)
void test_1() {
// do someThing
}
@Test
@Order(2)
void test_2() {
// do someThing
}
@Test
@Order(3)
void test_3() {
// do someThing
}
JUnit 5의 Test 이름 표시
-
@DisplayName("test name")
-
DisplayNameGenerator 보다 우선적으로 적용된다.
-
method 위에 작성한다.
@Test @DisplayName("AAA Test") void Arrange_Act_Assert() { // Arrange : 생성 // Act : 조작 // Assert : 결과 비교 }
-
-
@DisplayNameGenerator
-
Class 내부의 모든 메서드에 적용된다.
-
Class 위에 작성한다.
// 모든 밑줄 문자를 공백으로 바꾸는 static class @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) // 표준 표시 생성 static class @DisplayNameGeneration(DisplayNameGenerator.Standard.class)
-
Junit 5의 테스트에 대한 환경 변수 설정
- @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에서 실행
Junit5 Assertions
// assertEquals(A, B);
assertEquals("user", user.getUserName());
// assertTrue(A, B);
assertTrue("L", firstName.startsWith(user.getFirstName().charAt(0));
Exception exception = assertThrows(ArithmeticException.class, () -> calculator.divide(1, 0));
assertEquals("/ by zero", exception.getMessage());
// 시간 제한
assertTimeout(Duration.ofSeconds(1), () -> new user("Lob"));
// 시간이 초과되면 테스트 실패
assertTimeoutPreemptively(ofSeconds(1), () -> { Thread.sleep(5000); });
과제 1. live-study 대시 보드를 만드는 코드를 작성하세요.
package assignment.gitapi;
import org.kohsuke.github.*;
import java.io.IOException;
import java.util.*;
public class Application {
private final String token = "tokenString";
private GitHub github;
public static void main(String[] args){
Application app = new Application();
try {
app.run();
} catch (IOException e) {
e.printStackTrace();
}
}
private void run() throws IOException {
// 연결
connectGitApi();
GHRepository ghRepository = github.getRepository("whiteship/live-study");
// 참여자 이름, 참여 횟수
Map<String, Integer> participant = new HashMap<>();
// 모든 이슈를 가져온다.
List<GHIssue> issues = ghRepository.getIssues(GHIssueState.ALL);
//Find Issue
for (GHIssue issue : issues) {
// 각각의 Issue 에 존재하는 comment 들을 저장.
List<GHIssueComment> commentList = issue.getComments();
// 혹시 모를 유저 중복을 제거하기 위한 Set
Set<String> nameList = new HashSet<>();
addParticipantInSet(commentList, nameList);
// 참여자 명단에서 비교한다.
for (String s : nameList) {
hasParticipantInSet(participant, s);
}
}
printParticipantRate(participant);
}
private void hasParticipantInSet(Map<String, Integer> participant, String s) {
if (!participant.containsKey(s)){
participant.put(s, 1);
} else {
Integer integer = participant.get(s);
participant.put(s, ++integer);
}
}
private void addParticipantInSet(List<GHIssueComment> commentList, Set<String> name) throws IOException {
for (GHIssueComment ghIssueComment : commentList) {
name.add(ghIssueComment.getUser().getLogin());
}
}
private void printParticipantRate(Map<String, Integer> participant) {
participant.forEach((key, value)-> {
double percent = (double) (value * 100) / 18;
System.out.println(key+" : "+String.format("%.2f", percent)+"%");
});
}
private void connectGitApi() throws IOException {
github = new GitHubBuilder().withOAuthToken(token).build();
}
}
과제 2. LinkedList를 구현하세요.
package assignment.linkedlist;
public class ListNode {
private int elements;
private ListNode next = null;
public ListNode(int data) {
elements = data;
}
public ListNode add(ListNode newElement){
if (this.next == null){
this.next = newElement;
return this;
}
ListNode nextNode = this.next;
while (nextNode.next != null){
nextNode = nextNode.next;
}
nextNode.next = newElement;
return this;
}
public ListNode add(ListNode head, ListNode nodeToAdd, int position){
ListNode nextNode = head;
for (int loop = 0; loop < position-1; loop++) {
if (nextNode.next == null){ break; }
nextNode = nextNode.next;
}
ListNode tmp = nextNode.next;
nextNode.next = nodeToAdd;
nodeToAdd.next = tmp;
return this;
}
public ListNode remove(ListNode head, int positionToRemove){
ListNode nextNode = head;
for (int loop = 0; loop < positionToRemove-1; loop++) {
nextNode = nextNode.next;
}
// 현재 시점의 nextNode 에서 next 가 지워져야할 node
ListNode tmp = nextNode.next;
nextNode.next = tmp.next;
tmp = null;
return this;
}
public boolean contains(ListNode head, ListNode nodeToCheck){
ListNode nextNode = head;
while (nextNode.next != null){
if (nextNode.elements == nodeToCheck.elements){
return true;
}
nextNode = nextNode.next;
}
return false;
}
public void printForEach(){
ListNode nextNode = this;
while (nextNode != null){
System.out.println(nextNode.elements);
nextNode = nextNode.next;
}
}
public int size(){
ListNode nextNode = this;
int size = 0;
while (nextNode != null){
++size;
nextNode = nextNode.next;
}
return size;
}
}
테스트
과제 3. Stack을 구현하세요.
package assignment.stack;
public class StackNode {
private int[] elements;
private int head = 0;
private int size = 16;
private int modifyCount = 0;
public StackNode() {
elements = new int[size];
}
public StackNode(int size) {
elements = new int[this.size = size];
System.out.println(this.size);
}
public boolean push(int data){
if (modifyCount >= size){ return false; }
elements[modifyCount] = data;
head = modifyCount;
++modifyCount;
return true;
}
public int pop(){
if (head < 0) { return -1; }
int res = elements[head];
elements[head] = -1;
head--;
return res;
}
public void print(){
for (int index : elements){
if (index == 0 || index == -1){
System.out.println("is Empty");
break;
}
System.out.println(index);
}
}
}
테스트
과제 4. 앞서 만든 ListNode를 사용해서 Stack을 구현하세요.
package assignment.stack;
import assignment.linkedlist.ListNode;
import java.util.List;
public class ListStack {
private ListNode node = null;
private ListNode head;
public void push(int data){
if (node == null){
node = new ListNode(data);
head = node;
} else {
ListNode nextNode = node.next;
while (nextNode.next != null){
nextNode = nextNode.next;
}
nextNode.next = new ListNode(data);
head = nextNode.next;
}
}
public int pop(){
ListNode nextNode = node;
ListNode preNode = head;
if (node.next == null){ node = null; }
while (nextNode.next != null){
preNode = nextNode;
nextNode = nextNode.next;
}
int result = head.elements;
head = preNode;
preNode.next = null;
return result;
}
public void print(){
if (node == null){
System.out.println("is empty");
} else if (node.next == null){
System.out.println(node.elements);
} else{
while (node.next != null){
System.out.println(node.elements);
}
}
}
public static class ListNode{
private int elements;
private ListNode next = null;
public ListNode(int data){
elements = data;
}
}
}
테스트
(optional) 과제 5. Queue를 구현하세요.
배열 사용
package assignment.queue;
public class ArrayQueue {
private int[] elements;
private int size = 16;
private final int head = 0;
private int modifyCount = 0;
public ArrayQueue() {
elements = new int[size];
}
public ArrayQueue(int size) {
elements = new int[size];
}
public boolean offer(int data){
if (modifyCount >= size){ return false; }
if (data < 0){ return false; }
elements[modifyCount] = data;
++modifyCount;
return true;
}
public int poll(){
int res = elements[head];
int modify = 0;
for (int loop = 1; loop < modifyCount; loop++) {
elements[loop-1] = elements[loop];
modify = loop;
}
elements[modify] = -1;
modifyCount = modify;
return res;
}
public int size() {
int size = 0;
for (int index : elements){
if (index == -1){ break; }
if (index == 0){ break; }
++size;
}
return size;
}
public void print() {
for (int index : elements){
if (index == -1){ break; }
if (index == 0){ break; }
System.out.println(index);
}
}
}
테스트
ListNode 사용
package assignment.queue;
import assignment.stack.ListStack;
public class ListQueue{
private ListNode node = null;
private ListNode head;
public ListQueue() {
}
public ListQueue(int element) {
node = new ListNode(element);
head = node;
}
public void offer(int data){
if (node == null){
node = new ListNode(data);
head = node;
} else {
ListNode nextNode = node;
while (nextNode.next != null){
nextNode = nextNode.next;
}
nextNode.next = new ListNode(data);
}
}
public int poll(){
int result = head.elements;
ListNode nextNode = head.next;
head = null;
head = nextNode;
return result;
}
public int size() {
int size = 0;
ListNode nextNode = head;
while (nextNode != null){
++size;
nextNode = nextNode.next;
}
return size;
}
public void print() {
if (head == null){
System.out.println("is empty");
} else if (head.next == null){
System.out.println(node.elements);
} else {
ListNode nextNode = head;
while (nextNode != null){
System.out.println(nextNode.elements);
nextNode = nextNode.next;
}
}
}
public static class ListNode{
private int elements;
private ListNode next = null;
public ListNode(int data){
elements = data;
}
}
}
테스트
참고 자료
Fail Fast and Fail Safe Iterators in Java - GeeksforGeeks
Difference between Iterator and Enumeration in Java
Loops in Java | Java For Loop - Javatpoint
'Live Study' 카테고리의 다른 글
Live Study_Week 06. 상속 (0) | 2020.12.21 |
---|---|
Live Study_Week 05. 클래스 (0) | 2020.12.15 |
Live Study_Week 03. 연산자 (0) | 2020.11.24 |
Live Study_Week 02. 자바 데이터 타입, 변수 그리고 배열 (1) | 2020.11.16 |
Live Study_Week 01. JVM 은 무엇이며, 자바 코드는 어떻게 실행하는 것인가. (0) | 2020.11.13 |
- Total
- Today
- Yesterday
- spring
- spring AOP
- Global Cache
- lambda
- RPC
- Local Cache
- RESTful
- hypermedia
- 근황
- 게으른 개발자 컨퍼런스
- mybatis
- Data Locality
- Url
- 소비자 관점의 api 설계 패턴과 사례 훑어보기
- java
- JDK Dynamic Proxy
- AMQP
- HTTP
- THP
- configuration
- 게으른개발자컨퍼런스
- URN
- Distributed Cache
- Switch
- Cache Design
- JPA
- URI
- cglib
- JVM
- rabbitmq
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |