자바 기초지식 정리

Roeniss Moon·2020년 11월 14일
9
post-thumbnail

입장글

이 글은 백기선 님이 진행하는 스터디를 팔로업한다.

이 스터디는 (아마도) 아무나 참여할 수 있다. 각 주차 이슈에 딸린 질문들에 대해 블로그에 답을 남기고, 해당 글을 이슈에 링크 다는 식으로 진행된다. 백기선 님 유튜브 채널에서 라이브로 리뷰한다.

그리고 이 글은 누군가에게 보여주기보단 내가 이해하는 선에서 적당히 정리하는 느낌이기 때문에, 그냥 하나의 글에 모든 주차의 내용을 담고자 한다.

1주차 : JVM, Compile, Bytecode

JVM이란 무엇인가

자바 코드의 최종 실행 환경. *.class 파일을 실행하는 런타임 환경


(출처 : https://helloworld-88.tistory.com/16)

컴파일 하는 방법

javac hello.c (javac는 JDK에 있음)

실행하는 방법

java hello or java hello.java

바이트코드란 무엇인가

컴파일의 결과물. "바이트 코드" 아님. "바이트코드"임. (JVM에서 돌아가는 byte-size의 opcode들로 이루어짐)

JIT (Just-in-Time) 컴파일러란 무엇이며 어떻게 동작하는지

"인터프리터 방식과 정적 컴파일 방식을 적절히 조합"

자주 쓰는 코드를 런타임 중 파악하여 네이티브 코드로 변환 후 이를 사용하도록 조정

JVM 구성 요소


(출처 : https://j4bez.tistory.com/14)

JDK와 JRE의 차이

개발은 JDK를, 실행은 JRE를 필요로 함

JRE < JDK

javac 옵션 조사

중요해 보이는 것만 추려봄.

-X~~~ : Non-standard option
-g : 디버깅 정보 생성. "g:{source,lines,vars}" 형태로 특정 정보만 뽑아낼 수도 있음.
-nowarn : 경고 제거
-source $version : 소스파일의 최소 버전을 명시. default가 1.7이기 때문에, java 1.7 미만의 코드를 보기 어려운 듯?
-verbose : verbose output
-Werror : Terminate compilation if warnings occur.
-X : Display information about non-standard options and exit.

그 외

  • 용어 정리 (출처 : https://goddaehee.tistory.com/183)

    • JAVA SE(Java Standard Edition)

      • JVM (Java 가상 머신) 및 API 등

      • Core Java라고도 하며 가장 기본적이고 표준적인 Java 버전

    • JAVA EE(Java Enterprise Edition)

      • "Java SE" + 서버용 확장 표준들
      • Java 2 Platform, Enterprise Edition 또는 J2EE로 알려져 있었다.
    • JRE(Java Runtime Environment)

      • Java 프로그램이 실행되도록 제공되는 환경.
      • JVM, 클래스 라이브러리 및 기타 지원 파일
      • 컴파일러, 디버거 등의 개발 도구 -> (X)
    • JDK(Java SE Development Kit)

      • JRE + 애플리케이션을 개발하기 위해 필요한 프로그램들 (javac, java, javadoc, jdb)

      • 오라클은 JDK라는 단어를 Java SE Development Kit을 말할 때 쓰도록 권장함

  • 라이센스

    (출처 : https://foojay.io/almanac/jdk-11/)

    • 위 사진에서 OracleJDK 빼고는 뭉뚱그려서 OpenJDK라고 부를 수 있다 (백기선 님 피셜)
  • https://stackoverflow.com/questions/52431764/difference-between-openjdk-and-adoptium-adoptopenjdk 에서 관련하여 얘기를 하는데, OpenJDK라는 단어의 역사가 아주 화려하다...

2주차 : 데이터 타입

프리미티브 타입 종류와 값의 범위 그리고 기본 값

byte        1 byte          0
short       2 bytes         0
int         4 bytes         0
long        8 bytes         0L
float       4 bytes         0.0f
double      8 bytes         0.0d
boolean     1 bit	    false
char        2 bytes         '\u0000'

프리미티브 타입과 레퍼런스 타입

"The basic difference is that primitive variables store the actual values, whereas reference variables store the addresses of the objects they refer to."

(출처 : https://stackoverflow.com/a/32049775)

reference type = all type - primitive type

리터럴

"A literal is the source code representation of a fixed value; literals are represented directly in your code without requiring computation. As shown below, it's possible to assign a literal to a variable of a primitive type"

(출처 : https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)

쉽게 말하자면, 자바 코드에 직접 '값'을 명시하면 리터럴로 분류할 수 있다. (컴파일러가 많이 개입함)

변수 선언 및 초기화하는 방법

1) 지역변수 초기화 : 명시적 초기화 (직접 대입), 생성자, 클래스/인스턴스 초기화 블럭

(출처 : https://doublesprogramming.tistory.com/73)

2) 배열 초기화 : 솔직히 매번 볼때마다 까먹을 것 같아서 잘 정리한 링크를 대신 투척 : https://ifuwanna.tistory.com/231

그 외는 평범하게 초기화하면 된다.

todo: LSP는 여기서 언급할 얘기는 아닐 듯.

변수의 스코프와 라이프타임

  • 인스턴스 변수

    • Scope : throughout the class except in static methods
    • Lifetime : until the object stays in memory.
  • 클래스 (스태틱) 변수

    • Scope : throughout the class
    • Lifetime : until the end of the program or as long as the class is loaded in memory.
  • 지역 (로컬) 변수

    • Scope : within the block in which it is declared
    • Lifetime : until the control leaves the block in which it is declared.

(출처 : https://www.tutorialspoint.com/scope-and-lifetime-of-variables-in-java)

todo: 클로저는 여기서 언급할 얘기는 아닐 듯.

타입 변환, 캐스팅 그리고 타입 프로모션

  • Primitive Type 간 : 자유롭게 변환. 일부 데이터 손실 가능성 있음.

  • Reference Type 간 : implicit up-casting, explicit down-casting

(출처 : https://kamang-it.tistory.com/entry/Java-19타입형-변환Type-Casting)

LSP : "서브 타입은 언제나 자신의 기반 타입으로 교체할 수 있어야 한다."

  • 로버트 C 마틴

(출처 : https://sehun-kim.github.io/sehun/solid/)

1차 및 2차 배열 선언하기

위에 언급한 블로그를 보고 따라함.

class Main {
  public static void main(String[] args) {
    int[] a = {1,3,5,7,9};  
    int[][] b = {{2, 5, 3}, {4, 4, 1}, {1, 7, 3}, {3, 4, 5}};

    System.out.println(a[3]); // 7
    System.out.println(b[2][2]); // 3
  }
}

타입 추론, var

var : 자바 10에 추가된 기능. 되는 것과 안되는 것에 대한 짧고 직관적인 예시 : https://johngrib.github.io/wiki/java10-var/

var을 실제 타입으로 치환하는 것은 컴파일 타임

(출처 : http://openjdk.java.net/projects/amber/LVTIFAQ.html)

언제 var를 쓸 것이냐에 대해서는 정론이 따로 없는 듯하다. 적당히 '쓰면 좋을 만한' 위치에 쓰면 되는 것인데 나는 보통 이에 대해서 Project Reactor의 mapping 과정에서 사용하는 듯. Flux.zip()으로 Tuple을 만들었다가 빼내고 다시 합치는 작업의 타입 선언은 고통 그 자체다.

3주차 : 연산자

산술 연산자 (arithmetic)

+ 	- 	/ 	* 	% 	++ 	--

비트 연산자 (bitwise)

& 	| 	^ 	~ 	<< 	>> 	>>>
AND	OR 	XOR	NOT			Zero-fill Rshift

관계 연산자 (relational)

== 	!= 	> 	< 	>= 	<=

논리 연산자

&& 	||	!

(출처 : https://www.tutorialspoint.com/java/java_basic_operators.htm)

instanceof

  • 객체 instanceof 객체타입 == true

  • 자녀객체 instanceof 부모타입 == true

  • 부모객체 instanceof 자녀타입 == false

class Main {
    class Parent { }
    class Child extends Parent { }

    void run() {
        Parent parent = new Parent();
        Child child = new Child();

        System.out.println(parent instanceof Parent);   // true
        System.out.println(child instanceof Child);     // true
        
        System.out.println(child instanceof Parent);    // true
        System.out.println(parent instanceof Child);    // false
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.run();
    }
}

* type ${variable} : primitive types에 사용

assignment(=) operator

= 	+= 	-= 	*= 	/= 	%= 	<<= 	>>= 	&= 	^= 	|=
						|--> bitwise assignment operator <--|

* Comma operator (in for-loop) : left to right (출처 : https://www.cs.umd.edu/~clin/MoreJava/ControlFlow/comma.html)

화살표(->) 연산자

"Lambda Expression" in java 8, 일명 "익명함수"

syntax : (parameter...) -> {expression}

@FunctionalInterface interface와 같이 쓰는 경우가 많다.

(출처 : https://www.w3schools.com/java/java_lambda.asp)

3항 연산자

int answer = condition ? true_value : false_value

연산자 우선 순위

외우기 힘들어서 생략. 내용은 대충 알고 있다.

(optional) Java 13. switch 연산자

https://mkyong.com/java/java-13-switch-expressions/ 예시가 아주 좋음

4주차 : 제어문 (부제 : 과제폭탄)

선택문

https://velog.io/@nunddu/Java-Switch-Expression-in-Java-14 이 분이 너무 잘 설명함

반복문

  • for(init;condition;each-func){ }
  • for(var : array/condition){ } : 레퍼런스를 가져오기 때문에 var 값 변경 불가!
  • while(condition){ }
  • do{func}while(condition){ }
  • Iterator()

과제 0. JUnit 5 학습하세요.

https://github.com/roeniss/java-study-homework/tree/main/src/test/java/Homework4

아래 구현을 전부 테스트 코드로 했다. 하지만 굉장히 맘에 안들고 답답한데, 테스트 코드 보고 백기선님이 훈수좀 해주셨으면...

과제 1. live-study 대시 보드를 만드는 코드를 작성하세요.

  • 깃헙 이슈 1번부터 18번까지 댓글을 순회하며 댓글을 남긴 사용자를 체크 할 것.
  • 참여율을 계산하세요. 총 18회에 중에 몇 %를 참여했는지 소숫점 두자리가지 보여줄 것.

https://github.com/roeniss/java-study-homework/blob/main/src/main/java/Homework4/GithubClient.java

자바에 대해 눈치가 좀 늘은 것 같다. Github 객체를 어떻게 만들지... 하다가 Builder가 있나? 하고 검색해 본다던가 하는...

과제 2. LinkedList에 대해 공부하세요.

  • 정수를 저장하는 ListNode 클래스를 구현하세요.
  • ListNode add(ListNode head, ListNode nodeToAdd, int position)를 구현하세요.
  • ListNode remove(ListNode head, int positionToRemove)를 구현하세요.
  • boolean contains(ListNode head, ListNode nodeTocheck)를 구현하세요.

https://github.com/roeniss/java-study-homework/blob/main/src/main/java/Homework4/ListNode.java

함수 시그니처에 대해서 좀 생각해보다가, static 으로 하는게 맞겠다 판단함

과제 3. Stack을 구현하세요.

  • int 배열을 사용해서 정수를 저장하는 Stack을 구현하세요.
  • void push(int data)를 구현하세요.
  • int pop()을 구현하세요.

https://github.com/roeniss/java-study-homework/blob/main/src/main/java/Homework4/Stack.java

과제 4. 앞서 만든 ListNode를 사용해서 Stack을 구현하세요.

  • ListNode head를 가지고 있는 ListNodeStack 클래스를 구현하세요.
  • void push(int data)를 구현하세요.
  • int pop()을 구현하세요.

https://github.com/roeniss/java-study-homework/blob/main/src/main/java/Homework4/ListNodeStack.java

(optional) 과제 5. Queue를 구현하세요.

  • 배열을 사용해서 한번
  • ListNode를 사용해서 한번

https://github.com/roeniss/java-study-homework/blob/main/src/main/java/Homework4/ArrayQueue.java

https://github.com/roeniss/java-study-homework/blob/main/src/main/java/Homework4/ListNodeQueue.java

5주차 : 클래스

클래스, 메소드, 생성자 정의하는 방법

public class MyObj { 
	public MyObj(){
		
	} 
	
	public Void noop(){
	}
  
}

객체 만드는 방법 (new 키워드 이해하기)

new MyObj();

myObj.clone()

(MyObj) Class.forName("MyObj").newInstance() // only works with non-arg constructor 

(MyObj) Class.forName("MyObj").getConstructors()[0].newInstance();

// Serialize, Deserialize를 사용하는 방법도 있지만 생략

this 키워드 이해하기

자기 자신을 가리키는, 클래스 차원의 키워드인데 나는 https://softwareengineering.stackexchange.com/a/113434 이 설명에 동의하며, this 키워드를 가급적 자제하는 게 좋다는 입장이다.

6주차 : 상속

자바 상속의 특징

자바 상속에 대한 정확한 표현 : "classes can be derived from other classes, thereby inheriting fields and methods from those classes."

  • 특징 1 : Single inheritance (No diamond inheritance)

  • 특징 2 : Object를 제외한 모든 클래스는 암묵적으로 Object의 서브클래스

  • 특징 3 : Multi-level inheritance (상속의 상속의 상속의 ...)

(출처 : https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html)

super 키워드

부모 클래스의 생성자나 메소드를 호출함.

부모 생성자를 호출하는 경우를 특별히 constructor chanining이라고 부름.

만약 자식 클래스의 생성자에서 super()를 명시적으로 사용하지 않으면, 컴파일러가 부모 클래스의 no-arg cstr를 호출하도록 코드를 삽입함. 그런데 만약 부모 클래스에 no-arg constructor가 없다면, 컴파일 에러가 발생한다.

(출처 : https://docs.oracle.com/javase/tutorial/java/IandI/super.html)

메소드 오버라이딩

부모클래스 인스턴스 메소드부모클래스 스태틱 메소드
자식클래스 인스턴스 메소드Overridescompile error
자식클래스 스태틱 메소드compile errorhides

hides : 부모 클래스의 메소드를 부를 수 있음.
overrides : 오버라이딩 된 메소드의 부모메소드를 직접적으로 호출할 수가 없음 (ref : https://stackoverflow.com/a/4595762/8556340)

(출처 : https://docs.oracle.com/javase/tutorial/java/IandI/override.html)

다이나믹 메소드 디스패치 (Dynamic Method Dispatch)

Runtime polymorphism. "같은 클래스를 상속하고 있는 여러 클래스 중 어느 서브클래스를 사용할 것인가"를 런타임 시점까지 미룸으로서, 클래스 재사용성을 높이는 테크닉.

예시 : https://riptutorial.com/java/example/28573/dynamic-method-dispatch---example-code

추상 클래스

public abstract class GraphicObject {
   // declare fields
   // declare non-abstract methods (+ static method)
   abstract void draw();
}

인터페이스 내에 default 또는 static으로 선언되지 않은 메소드는 암묵적으로 abstract로 간주된다.

아래 출처의 본문에서, "interface or abstract class"에 대해서 여러 결정 기준을 잡아주었는데, 그 중 "서로 연관있는 클래스들이 사용하기를 원한다면 abstract"라는 항목이 제일 마음에 든다. (ex. Comparable이나 Cloneable은 서로 관련없는 다양한 클래스에서 사용되며, interface로 구현되었음)

(출처 : https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html)

final 키워드

final method : 오버라이딩 금지

final class : 오버라이딩 금지

final field : 변경 금지. 클래스 변수 (즉, static 필드)에 사용

(출처 : https://docs.oracle.com/javase/tutorial/java/IandI/final.html)

Object 클래스

  • clone() : 만약 HashMap처럼 external object에 대한 reference가 객체에 포함되어 있다면, Cloneable 인터페이스를 implements 했더라도 제대로 clone이 안될 수 있으니 clone 자체를 override 해야함

  • equals() : primitive data에 대해선 값을 잘 비교함. 왜냐면 ==를 사용해서 비교하기 때문. 하지만 Object들을 비교할 때는 제대로 동작하지 않음. 왜냐면, Object 두개에 ==를 사용하면 "같은 레퍼런스인가"를 확인하기 때문. (실제로 확인해야 하는 건 대개 그렇지 않으므로..) 이때 사용되는 것이 equivalency라는 개념인데, 'same information' 정도로 해석할 수 있음. 결과적으로, equals를 override 해야된다는 것임.

  • hashCode() : 정의에 따르면 "if 'equals' true, hashcode must be true" 따라서 equals를 오버라이딩 할 경우 (기존의 hashcode가 no longer valid 하므로) hashcode 또한 오버라이딩 해야된다. 참고로 이걸 안하면 HashMap 등에서 값이 꼬인다.

  • toString() : 항상 재정의 권장. lombok이 당신을 도와줄거야! ^오^

  • finalize() : "Don't do it" (그럼에도 왜 존재하는가에 대해선 그 위의 답변들을 참고)

  • getClass() : final 메소드이기 때문에 상속할 수 없다. reflection에 사용됨

7주차 : 패키지

package 키워드, 접근지시자

자바 클래스들의 디렉토리 개념. 폴더랑 마찬가지인데, '하위 폴더는 그냥 다른 패키지일 뿐이다'!

접근 제어자랑 맞물려 작동한다. 말나온 김에 재정리..

publicprotecteddefaultprivate
자유로움동일 패키지 or 상속받았을 때동일 패키지본인 클래스 내에서만

import 키워드

특정 패키지의 특정 클래스만 가져올 수도 있지만 (import xxx.xxxx.*) intelliJ가 알아서 해주는 편...

클래스패스

하나의 클래스는 하나의 클래스 파일이 된다. (package 기준 X)

각 클래스의 위치를 지정해줘서, JVM을 구동할 때 클래스들을 찾아오게 할 때 사용하는 것이 바로 classpath.

  • CLASSPATH 환경변수
  • -classpath 실행인자

두 가지 방법으로 적용 가능하다.

8주차 : 인터페이스

인터페이스 정의 및 구현 방법

class 선언할 때의 class 자리에 interface 입력

메서드를 선언하거나, 시그니처만 기록

이를 클래스에서 implements 해서 사용

인터페이스 레퍼런스를 통해 구현체를 사용하는 방법

INTERFACE obj = new CLASS_IMPLEMENTING_INTERFACE();

// 후에 구현체가 바뀌어도, `INTERFACE`를 implements 했다면 lvalue 를 유지할 수 있음

인터페이스 상속


interface A extends B, C {}

인터페이스의 기본 메소드 (Default Method), 자바 8

java 8부터 인터페이스에 메서드를 "구현"할 수 있다

인터페이스의 static 메소드, 자바 8

그리고 static도 된다. 당연히 구현 까지 말하는 것임

인터페이스의 private 메소드, 자바 9

위에서 말한 두 가지 케이스를 지원하기 위해 추가되었다.

9주차 : 예외처리

자바에서 예외 처리 방법 (try, catch, throw, throws, finally)

try {
	// code
    throw new ErrorClass() // 특정 에러 유발
} catch (ErrorClass e){
	// 특정 에러 캐치
} catch (Exception e) {
	// 모든 에러 캐치
} finally {
	// catch에 걸리던 안걸리던 무조건 try 후에 실행된다
}

throws : 메서드 시그니처에 입력. "이 메서드는 이러이러한 예외가 발생할 수 있으니 caller에서 처리하십시오"

자바가 제공하는 예외 계층 구조

(reference : https://www.geeksforgeeks.org/exceptions-in-java/)

Exception과 Error의 차이는?

  • Error : 애플리케이션 꺼지는게 정상 (ex. 메모리부족)
  • Exception : application-layer problem. "catchable"

checked vs unchecked : 이러저러한 기준이 있지만... 2021년에 찾아볼 수 있는 논쟁들은 다음과 같다.

  1. checked exception은 OOP 5대원칙(SOLID) 중 하나인 OCP를 위배한다. 해당 예외가 들어있는 메서드를 수정했을 때 이를 사용하는 (즉 시그니처에 throws가 포함된) 모든 메서드의 시그니처가 수정되어야 하기 때문.

  2. '복구 불가능한' 코드는 Unchecked로 감싸서 (ex. RuntimeException) 던지는 게 낫다. 어차피 caller도 도와줄 수 없다면 왜 굳이 catch하게 유도하는가?

2-1. 그럼에도 불구하고, 현실 세계에서 (혹은, application-layer에서) 복구 불가능한 에러는 사실상 전무하다시피 한다. 예를 들어 디비에 insert 중 에러가 났다면 (1) 재시도를 하거나 (2) 클라이언트에게 실패했다고 안내를 보내는 등 다양한 방법이 존재한다.

(reference :
https://softwareengineering.stackexchange.com/questions/121328/is-it-good-practice-to-catch-a-checked-exception-and-throw-a-runtimeexception)

"유니크해야 하는 이메일 값이 중복돼서 SQLException이 발생하는 경우 어떻게 복구 전략을 가질 수 있을까요? 유저가 압력을 가했던 이메일 + 난수를 입력해서 insert 시키면 가능은 하겠지만 현실에서는 그냥 RuntimeException을 발생시키고 입력을 다시 유도하는 것이 현실적입니다.

여기서 중요한 것은 해당 Exception을 발생시킬 때 명확하게 어떤 예외가 발생해서 Exception이 발생했는지 정보를 전달해주는 것입니다. 위 같은 경우에는 DuplicateEmailException (Unchecked Exception)을 발생 시는 것이 바람직합니다.

Checked Exception을 만나면 더 구체적인 Unchecked Exception을 발생시켜 정확한 정보를 전달하고 로직의 흐름을 끊어야 합니다. 우리는 JPA에 구현체를 가져다 사용하더라도 Checked Exception을 직접 처리하지 않고 있는 이유도 다 적절한 RuntimeException으로 예외를 던져주고 있기 때문입니다."

(reference : https://cheese10yun.github.io/checked-exception/)

+) 스프링의 에러/예외 처리 전략 (주의해야겠다..)

Spring의 Transaction rollback이 일어나는 조건은 스프링 에러처리 전략에 따라 다음과 같습니다.

Error, Unchecked Exception: 트랜잭션 롤백
Checked Exception: 트랜잭션 커밋

또한, 트랜잭션 전파 속성을 PROPAGATION_REQUIRED(Default)로 준 경우 내부에서 UncheckedException을 유발하는 메소드가 UncheckedException을 발생시키면, try-catch로 해당 예외를 처리했다한들 이미 rollback-only속성이 마킹되어 최종적으로 트랜잭션 완료를 할 때, rollback을 수행합니다.

(reference : https://velog.io/@dion/도대체-Checked-Exception이랑-Unchecked-Exception은-언제쓰는거야)

나의 결론 : "스프링을 쓸 때는" 웬만하면 RuntimeException을 활용하자. 하지만 Checked Exception을 사용할 수도 있음을 잊지 말자.

RuntimeException과 RE가 아닌 것의 차이는?

스프링이라면 '트랜잭션 롤백'에 차이가 있을거고,

좀 더 제너럴하게는, 'throws 요구 여부'에 차이가 있다.

커스텀한 예외 만드는 방법

public class MyException extends Exception {
	// 생성자로 super 활용 가능
}

10주차 : 멀티쓰레드 프로그래밍

Thread 클래스와 Runnable 인터페이스

"위의 예제 코드를 보시면 Thread 클래스를 확장하는 것이 실행 방법이 미세하게 더 간단하다는 것을 볼 수 있습니다. 하지만 자바에서는 다중 상속을 하용하지 않기 때문에, Thread 클래스를 확장하는 클래스는 다른 클래스를 상속받을 수 없습니다. 반면에 Runnable 인터페이스를 구현했을 경우에는 다른 인터페이스를 구현할 수 있을 뿐만 아니라, 다른 클래스도 상속받을 수 있습니다. 따라서 해당 클래스의 확장성이 중요한 상황이라면 Runnable 인터페이스를 구현하는 것이 더 바람직할 것입니다. 실제로 많은 개발자들이 대부분의 상황에서 Thread 클래스를 확장하기보다는 Runnable 클래스를 구현하는 것을 선호합니다."

(reference : https://www.daleseo.com/java-thread-runnable/)

추가로, Runnable은 Functional Interface라서 lambda expression이 가능함.

쓰레드의 상태

아래 그림은 적절하지 않다.

(reference : https://www.javatpoint.com/life-cycle-of-a-thread)

아래 그림이 더 적절한 표현이다.

(reference : https://d2.naver.com/helloworld/10963)

(공식 docs도 그렇게 말하고 있다)

  • NEW: 새로운 쓰레드로 아직 시작되지 않음
  • RUNNABLE: JVM이 동작중. 이는 항상 동작하고 있다는 것은 아님. 리소스 획득을 위해서 잠시 대기 중일 수 있다.
  • BLOCKED: 쓰레드가 synchronized block 혹은 method에 진입하기 위해 대기.
  • WAITING: 대기 상태로 다른 쓰레드가 작업 중임을 의미. 이는 Object.wait 메소드 호출 후에도 진입되는 상태
  • TIMED_WAITING: 쓰레드가 특정 시간을 대기함을의미. 이는 Thread.sleep(), Object.wait()로 시간 인자가 들어간 메소드가 호출될때 진입되는 상태. 혹은 LockSupport, ParkNanos, LockSupport, ParkUntil 메소드도 동일
  • TERMINATED: run 메소드에서 빠져나온 경우 또는 예외가 발생하여 빠져나온 경우

(reference : https://ospace.tistory.com/109)

BLOCKED, WAITING, TIMED_WAITING 같은 상태는 monitor를 획득하는 것과 밀접한 관계가 있다. 모니터를 획득한다는 말은 synchronized 안에 해당 쓰레드가 들어와서 활동을 개시하게 되었다 ~ 정도로 이해하면 될 듯 하다.

(reference : https://stackoverflow.com/questions/32978574/monitor-in-java-threads)

쓰레드의 우선순위

쓰레드에 우선순위를 지정할 수 있다. 숫자에 반비례(1 = 낮음, 10 = 높음)

Main 쓰레드

main 함수가 실행되면 기본적으로 쓰레드가 하나 돈다. 나머지 chile threads는 main thread에서 "spawned" 되는 것이다.

동기화

https://parkcheolu.tistory.com/15

이 블로그의 설명이 너무나도 훌륭하다.

글 말미에서 설명하는 Concurrency API를 찾아보니, 뭔가 Thread/Runnable보다는 java.util.concurrent의 API를 쓰는게 더 나은 것처럼 설명하는데... Future 등의 API를 말하는 것 같으니 일단 염두에 두면 될 것 같다.

데드락

서로 같은 자원 가지려고 기다리느라 아무도 움직이지 않는 상태. 언뜻 생각해도, 디버깅하기 어려울 듯 하다.

11주차 : Enum (열거형)

enum 정의하는 방법

enum Day { // 기본으로 부여되는 ordinal 값(0 ~ )은 사용하지 않는 것을 권장함
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; 
}

정수 외의 값을 부여할 수도 있다.

	public enum JuSik {
        SAMSUNG(85600, -1.27),
        APPLE(158450, 0.17),
        TESLA(977313, -1.74),
        AMD(104817, -3.48),
        INTEL(61102, -0.91);

        private final double closingPrice;
        private final double fluctuationRate;

        JuSik(double closingPrice, double fluctuationRate) {
            this.closingPrice = closingPrice;
            this.fluctuationRate = fluctuationRate;
        }

        public double getCP() {
            return closingPrice;
        }
        public double getFR() {
            return fluctuationRate;
        }
    }

(reference : https://yadon079.github.io/2021/java%20study%20halle/week-11)

enum이 제공하는 메소드 (values()와 valueOf())

public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) : 특정 열거형 타입에서 특정 name을 지닌 enumtype을 리턴.
public static T[] values() : 해당 열거형의 모든 상수를 배열에 담아 반환한다. valueOf()는 이 배열을 이용해 타입을 찾는다.

java.lang.Enum

enum은 클래스이며, java.lang.Enum 클래스를 상속받고 있다. 그래서 별도의 상속은 안되고, 인터페이스를 이용해 확장할 수 있다. https://johngrib.github.io/wiki/java-enum/ 를 참고할 것.

EnumSet

"As a rule of thumb, EnumSet should always be preferred over any other Set implementation when we are storing enum values."
Enum을 쓸 땐 EnumSet을 쓸 것.

(reference : https://www.baeldung.com/java-enumset)

12주차 : 어노테이션

애노테이션 정의하는 방법

public @interface MyInterface {
}

@retention

어노테이션이 언제까지 코드에 살아있느냐를 결정함. SOURCE / CLASS / RUNTIME

용도

  • SOURCE : "annotations used by the compiler". (ex) @Override
  • CLASS : "compile 된 코드에 남아있음". 하지만 쓸모가 없음. "It would only be useful if you wanted to read the bytecode programmatically"
  • RUNTIME : "런타임 시에 유지되고 활용됨".

(reference : https://stackoverflow.com/a/5971247/8556340)

@target

어디에 사용할 수 있는지를 지정

(reference : https://b-programmer.tistory.com/264)

@documented

javadoc api 를 쓸 때 어노테이션 설명을 포함하도록 지정

애노테이션 프로세서

"Annotation processing is a tool build in javac for scanning and processing annotations at compile time."

"An important thing to note is the limitation of the annotation processing API — it can only be used to generate new files, not to change existing ones.

The notable exception is the Lombok library which uses annotation processing as a bootstrapping mechanism to include itself into the compilation process and modify the AST via some internal compiler APIs. This hacky technique has nothing to do with the intended purpose of annotation processing and therefore is not discussed in this article."

컴파일 타임의 어노테이션 프로세싱이 어떻게 이뤄지는지는 이 영상 설명이 간략하고 쉽다.

반면, 런타임 시엔 Reflection API 를 통해서 어노테이션을 사용할 수 있다. (https://stackoverflow.com/a/35960810/8556340 의 예시 참고)

profile
기능이 아니라 버그예요

0개의 댓글