2020-03-17 TIL

할 일 목록

  • 코어자바 5장 공부
  • 순열 알고리즘 한번 더 만들어 보기
  • 하루 3분 네트워크 3장 시험, 그림으로 배우는 network & http Ch1,2 풀기
  • 코어자바 5장 정리
  • 학교 수업 듣기

완료하지 못한 목록

완료 목록

  • 코어자바 5장 공부
  • 순열 알고리즘 한번 더 만들어 보기
  • 학교 수업 듣기

코어자바 9

예외, 단정, 로깅

예외 처리

(exception handling)을 지원하므로 메서드에서 예외를 던질 수 있다. 연이은 호출 과정에 있는 메서드 중 하나(직접 호출한 쪽일 필요는 없다.)는 해당 예외를 잡아서 처리할 책임이 있다. 예외 처리는 오류를 감지하는 과정과 처리하는 과정을 분리할 수 있다는 장점이 있다.

예외 던지기

필요한 리소스가 없거나 부적합한 매개변수를 받아 메서드가 해야 할 일을 할 수 없는 상황이라면 예외를 던지는 것이 최선이다.

두 경계값 사이에 있는 임의의 정수를 돌려주는 메서드에서 (10, 5)로 호출하여 문제가 생길 경우 예외를 던지는 코드이다.

public static void randInt(int low, int high) {
    if (low > high) {
        throw new IllegalArgumentException(
            String.format("low should be <= high but low is %d and high is %d", low, high);
        )
    }
    return low + (int) (Math.random() * (high - low + 1));
}

throw 문으로 예외 클래스의 객체를 던지고 있으며, 디버깅 메시지를 생성 인수로 전달해 예외 객체를 생성했다. throw 문이 실행되면 정상적인 실행 흐름이 즉시 중단되고, 제어는 예외 핸들러로 전달된다.

예외 계층

모든 예외는 Throwable 클래스의 서브클래스다. Error의 서브클래스는 예외 상황이 일어날 때 던지는 예외다. 예를 들어 메모리 고갈처럼 프로그램에서 처리할 수 없는 상황일 때 던진다. 이런 상황에선 프로그램이 할 수 있는 일은 사용자에게 뭔가 크게 잘못되었다는 메시지를 보여 주는 것 말고는 없다.

프로그래머가 보고하는 예외는 Exception 클래스의 서브 클래스이다. Exception 클래스에는 두가지 서브클래스가 존재한다.

  1. 비검사 예외(unchecked exception)

    • 비검사 예외 RuntimeException의 서브클래스다. RuntimeException의 서브 클래스로 만든 예외는 컴파일 과정에서 검사를 받지 않는다.
    • 실패를 예상하는 상황에서 사용된다. 예를 들어 입출력에 사용하는 파일이 손상되거나 문제가 생기면 많은 예외 클래스가 IOException을 확장하므로 상황에 적잡한 클래스를 사용해 오류를 보고한다.
  2. 다른 예외는 모두 검사 예외(checked exception)이다.

    • 검사를 한다는 의미는 컴파일 시간에 검사를 한다는 말이다. 그러므로 catch 이던 메서드 헤더에 exception signiture로 예외를 선언해야한다.
    • 한 예로 NullPointerException가 있다. 거의 모든 메서드가 이 예외를 던지니 잡을 노력할 필요없다.

구현자가 검사 예외를 던질지, 비검사 예외를 던질지 결정해야 할 때도 있다. Integer.parseInteger(str)은 str이 유효한 정수를 담고 있지 않으면 비검사 예외인 NumberFormatException을 던진다. 그 이유는 Integer.parseInt를 호출하기 전에는 문자열이 유효한 정수인지 검사할 수 있기 때문이다. 또 Class.forName(str)은 str이 유효한 클래스 이름을 담고 있지 않으면 검사 예외인 ClassNotFoundException을 던진다. 실제로 클래스를 로드하기 전에는 그 클래스를 로드할 수 있는지 알 수 없기 때문이다.

자바 API에는 많은 예외 클래스가 있지만, 목적에 맞는 표준 예외 클래스가 없다면 Exception 이나 RuntimeException, 기타 기존 예외 클래스를 확장해서 직접 만들어야 한다. 예외 클래스를 직접 만들 경우 인수 없는 생성자와 메시지 문자열을 받는 생성자를 구현하는 것이 좋다.

public class FileFormatException extends IOException {
    public FileFormatException() {}
    public FileFormatException(String message) {
        super(message);
    }
}
검사 예외 선언

검사 예외를 일으킬 수 있는 메서드는 메서드 헤더의 throws 절에 해당 예외를 선언해야 한다. 메서드에서 throw 문을 사용하기 위해서든, throws 절이 있는 또 다른 메서드를 호출하기 위해서든 해당 메서드가 던질 수 있는 예외를 모두 나열해야 한다.

public void write(Object obj, String filename)
    throws IOException, ReflectiveOperationException

throws 절에서 예외를 공통 슈퍼클래스로 묶을 수 있다. 공통 슈퍼클래스로 묶는 방벙비 좋은지 나쁜지는 던질 예외에 따라 다르다.

  1. 메서드에서 IOException의 여러 클래스를 던질 수 있으면 throws IOException 절로 묶어도 괜찬다.
  2. 하지만 관련 없는 예외를 던질 때는 throws Exception 절로 묶지 말아야한다.(예외 검사의 목적을 잃을 수도 있기 때문이다)

메서드를 오버라이드 할 때 슈퍼클래스 메서드에서 선언한 예외보다 광범위한 검사 예외는 던질 수 없다.(잘 이해가 안됨) 예를 들어 앞에서 나온 write 메서드를 오버라이드 한다고 하자. 그러면 다음과 같이 오버라이드하는 메서드에서 그보다 범위가 좁은 예외만 던질 수 있다. 하지만 관련 없는(관련 없는 기준이 대체 뭐임?) 검사 예외를 던지려고 하면 컴파일에 실패한다.

public void write(Object obj, String filename)
    throws FileNotFoundException

메서드에서 검사 예외나 비검사 예외를 던진다면 자바독의 @throws 태그로 문서화 할 수 있다. 프로그래머 대부분은 문서화할 만한 내용이 있을 때만 이 태그로 문서화 한다.

람다 표현식의 예외 타입은 절대로 명시하지 않는다. 하지만 람다 표현식ㅇ서 검사 예외를 던질 수 있다면 그 예외를 선언한 함수형 인터페이스에만 전달할 수 있다.

list.forEach(obj -> write(obj, "output.dat")); //이 코드는 컴파일 에러가 난다.

public interface Consumer<T> {  //accept 메서드는 어떤 검사 예외도 던지지 않도록 선언되어 있다.
    void accept(T t):
}
예외 잡기

예외를 잡기 위해 try 블록을 사용한다.

try {
    statements
} catch(ExceptionClass ex) {
    handler
}

try 블록에 들어있는 문장(statement)을 실행하다가 주어진 예외 클래스(ExceptionClass)의 예외가 나면 제어 핸들러(handler)로 이동한다. 예외 변수(이 예제에서는 ex)는 예외 객체를 참조하며, 핸들러는 필요하면 해당 예외 객체를 조사할 수 있다.

위의 기본 구조는 두가지로 변경이 가능하다.

서로 다른 예외 클래스에 대응하는 핸들러를 여러개 두는방법 - 위에 있는 예외 클래스 부터 일치하는 예외 타입을 찾고, 없으면 아래로 간다. - 이런 구조에서는 가장 상세한 예외 클래스부터 배치한다.

try{
    statements
} catch(ExceptionClass1 ex){
    handler1
} catch(ExceptionClass2 ex){
    handler2
} catch(ExceptionClass3 ex){
    handler3
}

하나의 catch에 여러개의 예외 클래스를 두는 방법 - 핸들러는 나열된 예외 클래스에 공통으로 있는 메서드만 예외 변수 ex로 호출할 수 있다.

try {
    statements
} catch(ExceptionClass1 ex1|ExceptionClass2 ex2|ExceptionClass3 ex3) {
    handler
}
try-with-resources 문

밑의 코드는 리소스에 접근하여 파일에 쓰기를 수행하고 완료하면 파일을 닫는 코드이다. 하지만 어떤 메서드든 예외를 던지면 out.close()가 호출되지 않는다.

ArrayList<String> lines = ...;
PrintWriter out = new PrintWriter("output.txt");
for (String line: lines) {
    out.println(line.toLowerCase());
}
out.close();

위의 코드는 특별한 try 문으로 해결할 수 있다. 리소스는 반드시 AutoCloseable(close 메서드 하나만 선언되어져 있다.) 인터페이스를 구현하는 클래스에 속해야한다. 예외를 잡는 catch 절을 붙히는 것도 가능하다.

ArrayList<String> lines = ...;
try(PrintWriter out = new PrintWriter("output.txt")){
    for (String line: lines) {
        out.println(line.toLowerCase());
}
}

또는 이전에 선언된 사실상 최종 변수를 헤더에 넣어도 된다.

PrintWriter out = new PrintWriter("output.txt")
try(out){
    for (String line: lines) {
        out.println(line.toLowerCase());
}
}

정상적으로 try 블록의 끝에 이르렀든 예외가 일어났든 간에 try 블록이 끝날 때 리소스 객체의 close 메서드가 호출된다.

여러 리소스를 세미콜콘으로 구분해 선언할 수 있다. 밑의 코드에서 리소스는 초기화 순서의 역순으로 닫는다. 즉 out.close()가 in.close()보다 먼저 호출된다.

try (Scanner in = new Scanner(Paths.get("/sr/share/dic/words"));
PrintWriter out = new PrintWriter("output.txt")) {
        while (in.hashNext())
            out.println(in.next().toLowerCase());
    }
}

PrinterWriter 생성자에서 예외를 던지면, 이 시점에 in은 이미 초기화 되었지만 out은 그렇지 않다. try 문은 이상황을 in.close()를 호출하고 예외를 전파하여 처리한다.

일부 close 메서드는 예외를 던질 수 있는데, try 블록이 정상적으로 끝난 후 이런 메서드에서 예외가 일어나면 호출하는 쪽으로 해당 예외를 던진다. 하지만 또 다른 예외가 일어나서 리소스들의 close 메서드가 호출되고, 그중 하나가 예외를 던지면 그 예외는 원래 일어난 예외보다 덜 중요하기 마련이다. 이런 상황에선 원래 일어난 예외를 다시 던지고, close 호출로 일어난 예외를 잡아서 억누른 예외(suppressed)로 첨부한다. 주 예외(primary exception)를 잡을 때 getSuppressed 메서드를 호출하면 부 예외(secondary exception)를 추출할 수 있다.

try {
    ...
} catch (IOException ex) {
    Throwable[] secondaryException = ex.getSuppressed();
}
finally절

가끔은 AutoCloseable이 아닌 무언가를 정리해야 할 때도 있다. 이대는 finally 절을 사용한다. finally 절은 정상으로든 예외가 일어다서든 try 블록이 끝날 때 실행된다. 이런 패턴은 잠금을 획득 해제 하거나 카운터를 증가 감소 시킬 때, 스택에 무언가를 넣었다가 작업을 마치고 꺼낼 때 사용한다.

try {
    작업수행
}
``` finally {
    정리 작업
}

finally 절에서는 예외를 던지지 말아야한다. try 블록 바디가 예외로 종료되더라도 finally 절에서 일어난 예외로 가려지기 때문이다.

finally 절에 return 문을 작성하면 안된다. try 블록 바디에 return 문이 있어도 finally 절에 있는 return 문이 반환 값을 교체해버린다.

catch 절 뒤에 finally 절을 붙여서 try 문을 구성할 수도 있지만 finally 절에서 in.close()같은 예외를 던지는 코드를 두는 실수를 조심해야한다. 그렇기 때문에 밑의 코드와 같이 try/catch/finally 문을 try-with-resources 문이나 try/catch 문 안에 try/finally를 중첩하는 방법으로 다시 작성하는게 낫다.

        BufferedReader in = null;
        try {
            try {
                in = Files.newBufferedReader(path, StandardCharsets.UTF_8);
            } finally {
                if (in != null) {
                    in.close();
                }
            }
        } catch (IOException e) {
            System.err.println("Caught IOException: "+ e.getMessage());
        }
예외 다시 던지기와 예외 연쇄

예외가 일어날 때 무슨 일을 해야 할지 모르더라도 실패를 로그로 기록하고 싶다면 예외를 다시 던져 적합한 예외 핸들러가 다룰 수 있도록 해야한다.

try{
    작업을 수행한다.
} catch(Exception ex) {
    logger.log(level, message, ex);
    throw ex;
}

아래의 코드는 catch 문에서 Exception 클래스 예외를 잡고 있어서 메서드 예외를 Exception으로 변경해야 할것 같지만, 자바 컴파일러는 실행 흐름을 주의깊게 추적하여 ex가 임의의 Exception이 아니라 try 블록 안에 있는 문장에서 던지는 예외라는 사실을 알아낸다.

public void read(String filename) throws IOException {
    try{
    작업을 수행한다.
    } catch(Exception ex) {
    logger.log(level, message, ex);
    throw ex;
    }
}

서브시스템의 실패를 서브시스템 사용자에게 의미 있는 예외클래스로 보고하고 싶을 때 또는 서블릿 실행중 DB 오류가 일어나 서블릿은 무엇이 잘못되었는지 자세히 알고 싶지 않지만, 서블릿에 문제가 있다는 것은 확실히 알고 싶을 것이다. 이 처럼 던져진 예외의 클래스를 변경하고 싶은 경우 원본 예외를 잡아서 상위 수준 예외로 연쇄해야한다.

try {
    DB에 접근
} catch(SQLException ex) {
    throw new ServletException("database error", ex);
}

ServletException을 잡을 때 예외의 원본을 추출할 수 있다.

Throwable cause = ex.getCause();

ServletException 클래스에는 예외의 원인을 매개변수로 받는 생성자가 있다. 물론 모든 클래스에 있는건 아니다. 이럴땐 initCause 메서드를 호출한다.

try {
    DB에 접근
} catch(SQLException ex) {
    Throwable ex2 = new CruftyOldException("DB error");
    ex2.initCause(ex);
    throw ex2;
}

그렇기 때문에 예외 클래스를 직접 작성하면 다음 생성자도 추가로 작성해줘야한다.

public class FileFormatException extends IOException {
    public FileFormatException(Throwable cause) { initCause(cause);}
    public FIleFormatException(String message, Throwable cause)
}

예외 연쇄 기법은 검사 예외를 허용하지 않는 메서드에서 검사 예외가 일어날 때도 유용하다. 해당 검사 예외를 잡아 비검사 예외에 연쇄하면 된다.(이게 무슨말인지 모르겠다.)

미처리 예외와 스택 추적

예외를 어디에서도 잡지 않으면 스택 추적(stack trace)이 표시된다. 스택 추적은 오류 메시지용 스트림인 System.err로 전달된다.

기술 지원 스태프의 조사용 등으로 예외를 다른 곳에 저장하고 싶다면 기본 미처리 예외 핸들러(uncaught exception)를 설정한다.

Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> {
    예외를 기록한다.
})

미처리 예외는 해당 예외가 일어난 스레드를 종료한다. 지금까지 살펴본 프로그램처럼 어플리케이션에 스레드가 한개만 있다면, 프로그램은 미처리 예외 핸들러를 호출한 후 종료한다.

예외를 잡아야 하는데 무엇을 할지 모르겠다면 스택 추적이라도 출력해야한다.

try {
    Class<?> cl = Class.forName(className);
} catch(ClassNotFoundException ex) {
    ex.printStackTrace();
}

예외의 스택 추적 내용을 저장하고 싶을 땐 문자열에 집어넣으면 된다.

ByteArrayOutputStream out = new ByteArrayOutputStream();
ex.printStackTrace(new PrintWriter(out));
String description = out.toString();
Objects.requireNonNull 메서드

Objects 클래스에는 편리한 매개변수 null 검사용 메서드가 있다.

Objects.requireNonNull(direction);

requireNonNull 호출을 문제의 원인으로 보면 무엇을 실수 했는지 바로 알 수 있고, 또 예외에 대응하는 메시지 문자열도 지정할 수 있다.

this.direction = Objects.requireNonNull(direction, "direction must not be null");

변형을 사용하면 예외를 던지지 않고 대체 값을 전달할 수 있다. 메시지 에는 람다를 넣을 수도 있다.

this.direction = Objects.requireNonNullElse(direction, "North");

네트워크 문제 풀기

3장 IP 어드레싱

질문 목록

1. 3계층의 역할에 대해서 설명하시오(127p)

세그먼트 간에 데이터 송수신을 한다.

2. 3계층에서 ‘네트워크’가 무엇인지 설명하고 네트워크를 나누는 이유에 대해서 설명하시오 (131p)

네트워크란 한개의 라우터에 포함된 범위를 네트워크라고 하며, 네트워크를 관리하기 위해 브로드캐스트를 하는데, 한 네트워크에 너무 많은 컴퓨터가 있다면 브로드캐스트로 인한 부하가 크다. 같은 네트워크 내에서만 전달되기 때문에 네트워크를 나눠 문제를 해결한다.

3. 라우팅에 대해서 설명하시오(134p)

최종 목적지까지 어떤 경로로 갈것인지를 결정하는 것.

4. IP 주소의 특징에 대해서 설명하시오 (139 ~ 142p)

논리 주소라고 하며, DHCP를 통해 할당받을 수 있다. 소속된 네트워크에서 유일해야 한다. IPv4에선 32비트이다.

5. 클래스풀 어드레싱이 무엇인지 설명하고 클래스에 대해 설명하시오(147p)

클래스를 나누어 IP주소를 할당하는 방식. 클래스 규모에 따른 대출 IP 주소의 범위

6. 서브넷화란 무엇이고 어떻게 구현하는지 또 서브넷 마스크란 무엇인지 설명하시오 (151p)

서브넷화란 한 네트워크에서 여러 네트워크로 나눠서 관리하기 위한 방법이며, 호스트부를 네트워크부로 사용하여 구현한다. 서브넷 마스크란, 어디까지가 서브넷인지 알기 위해 네트워크부만 1로 표기한 것이며 and 연산자로 네트워크부를 얻을 수 있다.

7. 클래스리스 어드레싱이 무엇이며 어떤 문제를 해결하기 위해 나왔으며 어떻게 구현되는지 설명하시오 (157 ~ 158p)

클래스리스 어드레싱이란 클래스를 사용하지 않고 네트워크를 나누는 방법이며, 클래스로 나눌 경우, A클래스는 255개의 호스트가 존재하고 300개의 호스트가 있을 경우엔 ,B클래스를 사용해야 하다 보니 낭비가 크다. 그래서 나눠서 사용하는 방법이다.

8. DHCP에 대해서 설명하고 어떻게 동작하는지 설명하시오. 또 IP주소에는 대여기간이 있는 이유에 대해 설명하고 DHCP를 통해 설정할 수 있는 것을 나열하시오 (164 ~ 167p)

DHCP란 Dynamic Host Configuration Protocol 이며 MAC 주소를 가진 컴퓨터가 DHCP 요청을 브로드 캐스트 한다. DHCP 서버는 할당되지 않은 IP를 사용하도록 브로드캐스트로? 제안한다. 요청자는 다시 DHCP에 사용하겠다는 메시지를 보내고, 서버는 승낙한다. 만약 IP를 할당 받고 다른 NIC로 변경하게 되면, 할당된 주소는 영원히 사용 불가능하다. 서브넷 마스크, 디폴트 게이트웨이, DNS 서버, 대여기간.

9. ARP에 대해서 설명하고 ARP요청과 응답 과정을 설명하시오. ARP 테이블에 기재된 요소들을 주기적으로 리셋하는 이유를 설명하시오 (170~172p)

ARP란 Address resolve protocol 의 약자이며, IP를 사용하여 MAC 주소를 알아내는 프로토콜이다. 같은 IP라면 ARP 테이블에 IP에 대응하는 MAC 주소가 있는지 확인후 없으면 ARP 요청을 플러딩 하며, 맥주소를 요청한다. 응답이 오면 ARP 테이블에 ip 대응 맥 주소를 저장하여 보낸다. 주기적으로 리셋하는 이유는 만약에 어떤 컴퓨터가 mac주소를 변경하게 되면, IP는 그대로지만 MAC 주소는 변경됨. 존재하지 않는 맥주소에 보내게 될것임. 아니면 gateway로 패킷을 전송한다.(주의해서 보기)

10. DNS에 대해서 설명하시오 (174p)

Domain Name Server로 각 회사마다 한개씩 존재한다. 브라우저에 도메인을 작성하면 도메인 서버로 해당 도메인에 해당한 IP주소를 받을 수 있다.

11. MAC, DHCP, ARP, DNS 들을 사용하여 데이터가 네트워크를 통해 목적지 까지 전송되는 과정을 설명하시오(178p)

NIC 카드에 MAC주소가 존재하며 DHCP 요청으로 IP를 할당받고, DNS로 IP를 돌려받아 목적지 까지 ARP 요청하여 맥주소를 받아 패킷을 전송함.

1. WWW을 구성하는 3가지 핵심 요소를 나열하고 각각에 대하여 설명하시오. (16p)

HTML : Hypter Text Markup Language마크업 언어로 문서를 구성하는데 사용한다. HTTP : Hyper text Trasfer Protocol 약자로 hyper text를 주고받기 위한 프로토콜이다. URI : uniform Resource Identifier

2. http://user:pass@www.example.jp:80/dir/index.htm?uid=1#ch1 과 같은 절대 URI를 구성하는 7가지 구성 요소를 밑줄로 구분해서 설명하시오. (33p)

schema, 사용자 정보, 호스트, 포트, 파일 uri, 쿼리 파라미터, 프래그먼트 식별자

3. 아래 리퀘스트 메시지에서 구성 요소 5가지를 구분하시오. (40p)

POST /form/entry HTTP/1.1 Host: hackr.jp Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 16

name=ueno&age=37

메서드 요청uri http 버전, 리퀘스트 헤더 필드, 엔티티

4. 아래 리스폰스 메시지에서 구성 요소 5가지를 구분하시오. (42p)

HTTP/1.1 200 OK Date: Tue, 10 Jul 2012 06:50:15 GMT Content-Length: 362 Content-Type: text/html

...

http 버전, 상태 코드, 설명, 리퀘스트 응답 헤더, 바디

5. HTTP 지속 연결(keep alive)의 등장 배경과 장점에 대해서 설명하시오. (54~56p)

한 요청에 여러개의 링크가 존재하면, 하나씩 요청 완료 연결 끊기를 반복 해야 하기 때문에 오래걸렸는데, 커넥션을 유지한 채로 요청 응답만 받아 빨라짐.

6. HTTP pipelining이 무엇인지 설명하시오. (57p)

여러개의 요청을 한번에 보낼 수 있도 응답 또한 오는대로 받을 수 있음.

7. HTTP는 stateless 프로토콜이다. stateless 프로토콜의 장점과 단점을 설명하시오. (58p)

서버가 클라의 상태를 서버에 저장할 필요가 없음. 하지만 과거의 상태를 가질 수 없어 인증을 마친 상태를 잊기 때문에 새로운 페이지로 이동할 때마다 재차 로그인 정보를 보내든지 리퀘스트 마다 매개변수나 추가 정보를 붙여서 로그인 해야함.

8. 쿠키의 등장 배경과 쿠키 발행과 클라이언트의 쿠키 사용 과정을 설명하시오. (58~59p)

서버가 클라이언트를 구분해야할 경우를 위해 쿠키를 발행하여 구분 하였음.

9. HTTP 메시지의 구성 요소 3가지를 나열하고 각각에 대하여 설명하시오. (62p)

헤더 개행문자 바디

10. 메시지 바디와 엔티티 바디의 차이점을 설명하시오. (65p)

메시지 바디와 엔티티 바디는 동일하지만 컨텐츠 인코딩을 엔티티 바디는 메시지 바디가 아니게 됨.

11. Content Codings과 Chunked transfer Coding의 차이점을 설명하시오. (66~67p)

컨텐츠 코딩은 컨텐츠를 한번에 압축하는 것이고, 후자는 컨텐츠를 분해하여 전송.

12. HTTP에서 Multipart 전송은 언제 사용하는가? 각각의 엔티티를 구분하기 위해 사용하는 문자열을 무엇이라 하는가? (68~70p)

여러개의 메시지 바디를 전송할 때, 바운더리

13. Content Negotiation에 대하여 설명하시오. (73~74p)

유저 에이전트가 자신이 사용할 수 있는 컨텐츠 타입, 랭귀지, 문자셋을 요구하고 우선순위를 내는것.

5Fs

1. Fact

  • 코어자바 5장을 공부했다.

2.Feelings

  • 시간이 너무 부족하다고 느낀다.
  • 학교가 시작되니까 할일이 더 생겨 시간이 더 부족하다.
  • 피곤하다.

3.Findings

4.Future Action Plan

  • 내일은 코어자바 5장 마저 다 정리하고 문제 풀고
  • 수업 듣는다.

5.FeedBack


Written by@Zero1
This blog is for that I organize what I study and my thinking, feeling and experience.

GitHub