JVM 은 Java 코드 및 Application을 동작시킬 수 있도록 런타임 환경을 제공해주는 Java Engine 이다.

 

JVM 은 JRE의 일부분이며 Java 개발자로서 JVM 의 동작을 이해하는 것은 Java 구동 환경과 JRE(Java Runtime Environment) 을 이해하는 데 있어서 아주 중요한 부분이다.

 

Java 가 추구하는 가치는 WORA(Write Once Run Anywhere) 이며, 이는 모든 자바의 코드는 JVM 이라는 환경 위에서 동작하면서 어느곳이든 이식이 가능하다는 뜻을 포함하고 있다.

 

먼저 JVM 의 아키텍처는 다음과 같다.

 

하나하나 동작을 살펴보도록 하자.

 

Java Application 의 동작은 다음과 같은 순서로 이루어진다.

 

 

(1) Java JIT Compiler 가 Java 코드를 해석한다. Java Compiler 는 해석한 .java 코드를 .class 파일 형태로 해석결과로 만든다.

 

(2) 클래스 로더에 의해 .class 파일들은 다음 단계들을 거치며 해석된다.

 - Loading : 클래스 파일에서 클래스 이름, 상속관계, 클래스의 타입(class, interface, enum) 정보, 메소드 & 생성자 & 멤버변수 정보, 상수 등에 대한 정보를 로딩해서 Binary 데이터로 변경한다.

 

 - Linking : Verification 과 Preparation, Resolution 단계를 거치면서 바이트코드를 검증하고 필요한 만큼의 메모리를 할당한다. Resolution 과정에서는 Symbolic Reference 를 Direct Reference 등으로 바꿔준다.

 

 - Initialization : static block 의 초기화 및 static 데이터들을 할당한다. Top->Bottom 방식으로 클래스들을 해석한다.

참조 : (https://jins-dev.tistory.com/entry/Java-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A1%9C%EB%8D%94ClassLoader%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%ED%95%B4)

 

(3) 컴파일된 바이트코드는 Execution Engine 에 의해 머신별로 해석된다. 이제 Host System 과 Java Source 는 Byte Code 를 이용해 중계된다. JVM 이 할당된 메모리 영역을 관리하게 된다.

Execution Engine 은 3가지 파트로 구성된다.

 

 - Interpreter : 바이트코드를 Line by Line 으로 해석하고 실행시킨다. 동일 메서드가 여러번 Call 되더라도 매번 Interperter 가 호출된다.

 

 - JIT compiler(Just In Time Compiler) : Interpreter 의 효율성을 증가시켜준다. 모든 Byte 코드를 한번에 Compile 해놓고 Direct 로 변환할 수 있게 해줌으로써 Re-interpret 의 발생을 낮춰준다.

 

 - Garbage Collector : Un-referenced Object 들을 제거해주는 가비지 컬렉팅을 수행한다.

 

 

이처럼 일반적인 C 프로그램과 다르게 Java 는 ByteCode 로 해석하고 변환하는 단계가 있기 때문에 느릴 수 밖에 없다.

- Dynamic Linking : Java 의 Linking 은 런타임에 동적으로 일어난다.

- Run-time Interpreter : Byte Code 의 머신코드로의 컨버팅 역시 Runtime 에 일어난다. 

 

물론 최신 Java 버전은 병목현상을 효과적으로 제거했기 때문에 구버전의 자바와는 비교가 안될정도의 퍼포먼스를 갖는다. :)

 

참조 : https://www.guru99.com/java-virtual-machine-jvm.html

 

Java Virtual Machine (JVM) & its Architecture

Java String has three types of Replace method replace replaceAll replaceFirst. With the help of...

www.guru99.com

https://www.geeksforgeeks.org/jvm-works-jvm-architecture/

 

How JVM Works - JVM Architecture? - GeeksforGeeks

JVM(Java Virtual Machine) acts as a run-time engine to run Java applications. JVM is the one that actually calls the main method present in a… Read More »

www.geeksforgeeks.org

 

 

Javascript 의 클로저는 보통 Scope 와 같이 기술되는 특징적인 개념이다.

그 이유는 Closure 라는 개념이 Javascript 의 특징적인 Nested Scope 개념을 이용하기 때문이다.

 

다음 예제를 확인해보자.

 

위의 예제에서 함수 foo 는 innerFoo 의 실행 결과를 반환한다. outerFoo() 함수가 nestedFunction 을 return 해주고 있기 때문이다. 

이런 방식의 호출을 클로저(Closure) 라고 하며, 클로저로 정의된 innerFoo 함수는 외부 함수인 outerFoo 의 변수에 접근할 수 있기 때문에 Side effect 관리가 용이하며 정보 은닉(Private) 의 특성을 지닌다.

 

아울러 이렇게 정의된 outerFoo 는 innerFoo 를 위한 언어적 환경(Lexical environment) 를 제공하게 되기 때문에, 디자인 패턴적으로 높은 유연도를 가질 수 있게 된다. 

 

가령, outerFoo 를 innerFoo 를 위한 Factory 처럼 사용하거나 outerFoo 에 Parameter 를 받아 "독립적인 객체" 와 같은 환경을 만들거나 Singleton 처럼 사용할 수도 있다.

 

클로저의 중요한 특징 중 하나는 Scope Chain 을 이해하는 것이다.

근본적으로 Nested Scope 로 정의되는 Closure 는 3가지 종류의 Scope 를 가질 수 있으며 이를 순차적으로(Chaining) 접근하게 된다.

 

코드를 위와 같이 조금 변경해보았다.

 

(1) Local scope

 

(2) Outer function scope

 

(3) Global scope

 

위의 코드에서 Closure 는 위와 같은 3가지의 Scope 를 전부 가질 수 있으며,

동일한 이름의 변수에 대해서는 우선순위에 따라 다른 Scope 의 변수를 가리는(Hide) 모습을 볼 수 있다.

 

위와 같이 Closure 함수의 실행은 Scope 에서 Scope 로 전이되며 Scope 내에서 Scope 를 다시 선언하는 Scope chain 을 생성하는 과정이라 할 수 있다.

 

클로저를 이해하는 건 어렵지않으며, 중요한 것은 Scope chaining 을 이해하는 것이다.

 

주로 Javascript 의 유사한 동작을 패턴화 시키고, 그에 따른 독립적인 환경의 격리(private)가 필요할 때 사용하곤 한다.

 

 

다른 언어들과 마찬가지로 Javascript 역시 Scope 를 갖고 있으며, 이를 기본적으로 이해하는 것이 아주 중요하다.

 

Javascript 의 Scope 에는 다음 2가지가 있다.

 

(1) Local scope

지역 스코프를 말하며, Braclet({}) 안에서 정의되는 항목으로 정의된 해당 범위 내에서만 변수의 사용을 허용한다.

다른 범위에서 참조가 불가능하다.

 

(2) Global scope

전역 스코프를 말하며, 바닐라 자바스크립트에서 일반적으로 Braclet({}) 에 포함되지 않도록 정의된다.

전역으로 선언된 변수는 Window 객체로 포함되어 웹페이지 내에서 어디서든 참조가 가능하다.

 

그리고 응용된 Scope 로 Javascript 에서는 Nested Scope 라는 개념을 가질 수 있다.

 

(3) Nested Scope

Scope 내에서 별도의 Scope 를 정의한 경우 바깥쪽 Scope 에서 안쪽 Scope 에 접근이 불가능하지만 안쪽 Scope 에서는 바깥쪽 Scope 의 변수에 접근이 가능하다. 가령 다음과 같은 경우를 보자.

 

outerFoo() 함수의 출력 결과는 함수 내에서 innerFoo를 호출하기 때문에 70이 된다. innerFoo 함수에서 outerFoo 의 변수에 접근해서 곱하고 있는 모습이다. Nested Scope 에 의해 그 역은 성립되지 않는다.

이를 Lexical Scope 라고 하는데, 이는 변수나 함수가 문맥적으로 정의된 곳(Callee) 의 Context 를 참조한다는 일종의 원칙이다.

(이에 대한 대칭점으로 오래된 언어들에는 Dynamic Scope 라는 개념이 있고, 이는 변수나 함수가 불려진 곳(Caller) 의 Context 를 참조하는 개념이다.)

 

 

Javascript 의 Scope 는 기본적인 개념이라 익숙하면서도 자바스크립트의 특징적인 개념 중 하나이며, 중요한 개념인 Closure 를 이해하는 데 필수적이므로 잘 익혀두도록 하자.

 

 

Frontend 에 익숙하지않은 많은 개발자들이 과제 이상의 어느정도 규모있는 Frontend 를 작업하게 되면 HTML 과 CSS 의 구조에 대해 놀라는 경향이 있다.

 

HTML 과 CSS 는 생각보다 정교한 구조를 이루고 있고, 초보 수준 이상의 Frontend 실력을 갖기 위해서는 필수적으로 구조에 대해 이해하고 어떻게 브라우저가 웹(Web)을 스타일링하는 지 알아야 한다.

 

이해해야할 잘 갖춰진 Frontend 의 특징 중 하나로, "HTML 문서의 모든 프로퍼티(properties) 들은 상속가능하다" 는 점이 있다.

 

계층적으로 구조화된 DOM 모델에서 한 Element 는 Parent Element 의 속성을 지니며, 모든 element 들의 root parent 는 <html> 이 된다.

HTML 태그의 DOM 모델들 간 상속은 다른 포스팅에서 다루도록 하고, 본 포스팅에서는 CSS 의 상속에 대해 다루기로 한다.

 

복잡한 종류의 UI 를 구조할 때, 비슷한 CSS 스타일링을 중복해서 사용하게 되는 경우가 많이 있다.

가령, 웹페이지 전체의 UI 는 어느정도 일관성이 있어야 하기 때문에, 검색을 위한 검색바(Bar)와 검색 추천을 위한 표시바(Bar) 가 있는데 이 둘의 스타일을 비슷하게 가져가되 하이라이트 컬러 정도만 바꾸고자 한다고 해보자.

 

이 때, 세세하게 작업된 모든 디자인 스타일을 복사해서 사용하는 것은 비효율적인 일이다.

 

이럴 때에는 다음과 같이 CSS 상속을 이용해 쉽게 해결할 수 있다.

 

위의 코드에서 bar-focus 라는 CSS 스타일은 bar 스타일을 차용하되 background-color 에 특징을 입힌다.

위의 마크업은 다음과 같은 페이지를 나타내게 된다.

 

색배합이 끔찍하지만, 스타일을 재활용할 수 있다는 점정도는 쉽게 알 수 있다.

 

쉽지않은가? 이런식으로 스타일의 재활용을 통해 노가다로 여겨질 수 있는 Frontend 의 디자인 코드를 확연하게 정리할 수 있다.

 

하지만 CSS 의 상속과 관련되어 알아야할 성질들은 조금 더 있다.

 

먼저 브라우저가 상속을 처리하는 순서이다.

브라우저는 CSS 상속을 Inline > Internal > External 순서로 처리한다.

 

여기서 Inline, Internal, External 은 CSS를 정의하는 방법에 대한 분류를 말하며, 다음과 같다.

 - Inline : 해당 태그 안에 style=”” 속성을 통해 정의

 - Internal : 해당 파일 안에 <css> </css> 태그를 작성하고 해당 Scope 내에 정의

 - External : 별도의 파일로 CSS 를 분리하고 해당 파일을 HTML 에서 import

 

즉, CSS를 적용할 때에 위의 순서를 유의해야 해당 스타일이 반영될 수 있다.

 

또 당신이 프론트엔드 개발자라면 주의해야할 사항으로 태그의 속성 관리 부분이 있다.

 

만약, CSS 가 적용된 태그의 속성이 "float" 을 가지고 있는 경우 해당 DOM 은 상속관계 및 레이아웃에 영향을 받지않는 붕-뜬 상태가 된다. 

해당 요소에 상속성을 적용시키기 위해서는 overflow 속성의 적용이 필요하다.

 

 

Lazy Evaluation 이란 프로그래밍이 동작하는 데 사용되는 계산 전략의 한 종류를 말한다.

 

일반적인 프로그래밍에서 계산식이 즉발적으로 수행되는데 비해 Lazy Evaluation 은 해당 계산식의 실제 수행을 필요할 때까지 늦춘다.

이렇게 되면 장점으로는 필요하지 않은 시점에서 해당 식의 "불필요한 수행" 을 막을 수 있으며 어떤 경우에는 실제 수행되는 시점에조차 수행 과정에서의 불필요한 동작들을 최적화시킬 수 있다.

다음의 예시를 확인해보자.

 

위의 코드에서 일반적인 수행이라면 checked 의 값은 무조건 먼저 계산이 된다.

foo 함수가 얼마만큼의 비용을 수반하더라도, foo(val) 의 Return 값이 checked 가 가져야할 값이므로 일반적인 수행에서 checked 값은 foo 함수의 결과를 저장하며 그에 따라 아래의 조건식을 수행하게 된다.

 

만약 위의 코드가 Lazy 하게 동작한다면 흐름은 조금 다르다.

먼저 변수 checked 는 foo 메서드가 val 을 argument 로 전달받아서 수행하게된 "어떤 값" 이라고 간주되고, 이를 이후 필요한 시점, 즉 조건문을 체크하는 아래 로직에서 실제로 사용하게 된다.

 

첫번째 조건문인 if(true && checked) 조건문에서 foo 함수는 호출되게 된다. checked 가 true 여야지만 해당 조건이 참이되기 때문이다.

하지만 두번째 조건문에서는 foo 함수는 호출되지 않는다. 알다시피 true 가 이미 or 의 조건문에 포함되어 있기 때문에 compiler 는 최적화를 통해 이를 수행하지 않는다.

 

<참고로 위의 예제코드는 이해를 돕기 위해 작성한 것일 뿐 실제로 Lazy 하게 동작하지 않음을 주의한다.>

 

이러한 Lazy Evaluation 은 프로그래밍에서 종종 사용되는 개념이며 실제로 많은 경우에 퍼포먼스의 향상을 가져올 수 있다.

 

Java에서도 Lazy Evaluation 을 사용할 수 있으며 보통 Java8 의 Lambda 를 이용해 이를 지원한다.

 

이제 위의 메서드를 Lambda 식을 이용해서 Lazy Evaluation 형태로 바꾸어 보고 비교해보자.

 

 

위의 예제를 변형한 코드이다.

코드에서는 Lazy Evaluation 을 함수형 인터페이스의 Supplier 메서드를 이용해 구현한 모습으로,

위의 main 동작에서 가장 마지막 조건문의 수행 시, foo 함수는 호출되지 않는다.

 

이와 같은 Lazy Evaluation 을 이용하면 사소한 부분이지만 만약 foo 함수의 비용이 막대한 경우에 큰 성능 상 이점을 가져올 수 있다.

 

특히 Lambda 가 대중화되고 Lazy Evaluation 과 같은 처리가 익숙해진 최근의 추세에서 확실히 개념을 이해하고 사용하는 것이 중요하겠다.

 




웹 페이지를 구성하는 DOM Element 노드들은 트리 모양의 계층 구조를 갖고 있으며 DOM Element 와 연결된 Javascript 내부 동작 역시 이 구조에 대한 로직이 고려되어 있다.


이벤트 버블링과 캡쳐링은 Javascript 에서 주로 사용되는 Event Delegation Pattern 을 이해하는 기본적인 개념이다.


- 이벤트 버블링(Event Bubbling) 


웹페이지 내의 한 엘리먼트에서 이벤트가 감지되었을 때, 해당 엘리먼트의 계층구조를 따라 올라가면서 Root Element 까지 이벤트가 전달되는 것을 Event Bubbling 이라 한다.


이해를 돕기 위해 다음 코드를 확인해보자.


<div class="col-sm-1" onclick="alert('c')">
<div onclick="alert('b')">
<div onclick="alert('a')">
HELLO
</div>
</div>
</div>


위의 코드를 웹 페이지에서 확인해보면, HELLO 를 감싸고 있는 DOM 엘리먼트를 클릭하면 a - b - c 순서대로 3개의 Alert 창을 확인해볼 수 있다.


이처럼 이벤트 버블링(Bubbling)이란, 이벤트가 발생하는 가장 안쪽부터 바깥쪽, 하위 노드에서 상위노드로 이벤트가 전파(Propagation)되는 과정인 것이다.


하위 DOM Element 부터 전파되는 이벤트는 최종적으로 Document 객체까지 전달되며, 상위 Element 에서 이벤트 핸들러를 재정의해서 전파를 제어할 수 있다.


가령, 다음과 같은 코드에서 이벤트는 두번째 div 이상으로 전파되지 않는다.



<div class="col-sm-1" onclick="alert('c')">
<div onclick="event.stopPropagation()">
<div onclick="alert('a')">
HELLO
</div>
</div>
</div>


전파되지 않는 이유는 이벤트가 발생한 target Element 의 상위 Element 에서 onclick 메서드를 재구현하는데, event.stopPropagation() 함수를 이용해서 전파를 중단했기 때문이다.


이렇게 전파를 제어하는 것을 Stop Bubbling 이라고 한다.



- 이벤트 캡쳐링(Event Capturing)


이벤트 캡쳐링은 이벤트 버블링과 반대방향으로 이벤트가 전달된다.


다음 코드를 통해 이해해보자.


<div id="parent">
<div id="child">
HELLO
</div>
</div>
<script>
var parent = document.querySelector('#parent');
var child = document.querySelector('#child');
parent.addEventListener('click', function(){
alert("Parent clicked");
},true);
child.addEventListener('click', function(){
alert("Child clicked");
});
</script>


똑같이 계층 구조로 Element 들이 배치되어 있지만 이번에는 Parent 노드부터 이벤트가 전달된다.


이처럼 이벤트 캡쳐링(Event Capturing)이란, 상위노드부터 하위노드로 이벤트가 전달되는 형태를 말한다.


이 경우에 이벤트는 window 객체부터 차례로 아래 노드로 전파되며 addEventListener 의 3번째 인자로 capture 플래그를 두어 탐색 방향을 맞출 수 있다.


이벤트 캡쳐링의 경우 버블링보다는 덜 사용된다.



이벤트 버블링(Event Bubbling) 과 이벤트 캡쳐링(Event Capturing) 의 개념은 간단하지만, 이해하고 있지 않으면 은근히 프론트엔드 개발 시 삽질을 할 수 있는 부분이다.


잘 이해해두어 복잡한 UI 이벤트 처리 시에 헷갈리는 일이 없도록 하자.





본 포스팅에서는 현직 개발자에게도 생소하기 쉬운 쓰로틀링(Throttling)과 디바운싱(Debouncing) 테크닉에 대해 설명하고자 한다.


본래 Throttling 이란 주로 모바일 기기에서 많이 사용되는 용어로 성능을 위한 오버클럭(Overclock)이 디바이스에 무리를 주는 것을 방지하기 위해 고의로 성능을 낮추는 조절 방식을 말한다.


소프트웨어 적인 의미로도 Throttling 은 언급이 되곤 한다.


이 때에는 주로 트랜잭션을 처리하는 Middleware 나 네트워크 트래픽을 제어하는 ISP 에서 언급이 되며 UI 처리를 담당하는 프론트엔드(Frontend)에서도 사용된다.


프론트엔드(Frontend) 에서 쓰로틀링과 디바운싱은 어떤 경우에 사용될까?


가령 웹페이지를 구성하는데 해당 사이트는 다시 방문시 사용자가 읽던 포스트의 위치를 기억하고 그 페이지를 보여준다고 생각해보자.

페이지를 나눌 단위가 없으므로 스크롤 단위로 페이지 좌표를 서버에 기록하고자 한다면, 가장 단순한 방법은 Javascript 의 Scroll 이벤트를 이용해서 좌표를 저장하고 기록하는 방식이다.


이 경우 사용자의 스크롤링마다 이벤트를 발생시키면... 서버에도 클라이언트에도 매우 큰 부하가 발생되게 된다.

최악의 경우 페이지의 세로 좌표만큼 이벤트가 발생될 것이다.


예시는 최악의 구조와 최악의 경우를 가정한 것이지만, 중요한 점은 "이벤트의 오버클럭(Overclock)이 소프트웨어에 손상을 가져온다는 점" 이다.


이런 경우의 처리를 위해서도 쓰로틀링과 디바운싱 이라는 개념이 똑같이 적용되어 사용된다.


먼저 쓰로틀링(Throttling) 테크닉을 알아보자

쓰로틀링(Throttling) 을 이용하면 발생되는 이벤트 중간에 Delay 를 포함시킨다.


즉, Delay 이내로 연속적으로 발생된 이벤트에 대해서는 무시한다.


다음 코드를 보면 쉽게 이해될 것이다.




이런 종류의 테크닉은 특히 애니메이션을 구현하는 코드 등에서 많이 확인해볼 수 있다.


다음으로 디바운싱(Debouncing) 역시 쓰로틀링과 비슷하게 소프트웨어적인 오버클럭을 조절하는 테크닉이다.


하지만 쓰로틀링(Throttling) 과는 조금 다른 방법을 사용하는데, 쓰로틀링이 필터링(Filtering)의 방법을 사용한다면,


디바운싱(Debouncing)은 그루핑(Grouping)의 방법을 사용한다.


즉, 이벤트 핸들러가 주기적으로 여러 개의 발생한 이벤트를 하나로 묶어서 처리하는 방식이다.


이때, 먼저 발생한 이벤트가 처리를 대기하며, 대기하는 도중 새 이벤트가 발생하면 이전 이벤트의 대기를 취소(Cancel)하고, 해당 이벤트를 기준으로 다시 처리(Process)를 대기한다.

이렇게 특정 시간 동안 처리(Process)는 대기하게 되며 결과적으로는 일정한 시간 동안 연속적으로 발생한 이벤트는 마지막으로 발생한 이벤트 기준으로 처리된다.


여기서 Leading Edge 라는 디바운싱 테크닉을 이용하면 이 처리를 앞의 이벤트 기준으로 변경할 수 있으며 이 경우엔 쓰로틀링과 유사하게 동작하게 된다.

(나중에 발생하는 이벤트를 무시하는 방식은 같지만 첫 이벤트 처리가 딜레이 된다.)


다음 코드를 참조해보자.



쓰로틀링과 디바운싱은 생소하지만 알고보면 많은 이벤트 처리에 사용되고 있는 테크닉이다.

특히 UI를 처리하는 부분은 입력의 오버클럭을 감당하기 위해 없어서는 안되며 많은 라이브러리나 프레임워크에 이미 내장된 경우가 많으므로 잘 숙지해두는 것이 좋다.



좀 더 자세한 예시는 다음 링크가 가장 잘 되어 있는 듯 하다.

 : https://css-tricks.com/debouncing-throttling-explained-examples/


추가로 본 포스팅에선 이해를 돕기 위해 간단한 파이썬 코드로 예시를 작성했지만 실제 Javascript 에서 사용되는 코드의 예시는 다음을 참조해보자.

 : https://codeburst.io/throttling-and-debouncing-in-javascript-646d076d0a44




Java9 에서 새로 추가된 JShell 을 이용하면 마치 Java를 파이썬을 사용하듯이 손쉽게 프로토타이핑할 수 있다.


JShell 이란 Command Line Interface 로 제공되는 자바 코드 작성을 위한 도구이다.


당연히 복잡한 종류의 모듈을 JShell 을 이용해 제작하는 건 무리지만, 간단히 자바 코드를 실행하고, 모듈을 작성해보거나, 


Java Library 의 기능을 테스트해보아야 한다면 실무에서도 유용한 도구이다.



JShell 을 이용하는 방법은 다음과 같다.


1. Java9 를 설치한다.



2. 환경변수 Path 에 설치된 경로를 지정한다.




3. 커맨드 라인에서 Jshell 을 실행한다.




Jshell 을 이용하면, 커맨드라인에서 즉시 자바 명령어를 실행할 수 있으며, 다음과 같이 모듈의 Import 및 사용 역시 가능하다.


이렇게 실행하는 Java Statements, Definition, Expression 등을 스니펫(Snippet) 이라고 하며, 스니펫을 실행하면 JShell 에서 즉각적인 피드백(Feedback)을 제공해준다.






또한 JShell 은 위의 그림에 마지막에 작성된 스니펫인 /edit 을 이용하면, 별도의 Edit pad 를 제공하는데, 


이를 이용하면 JShell 만을 이용해서도 마치 IDE 를 사용하는 듯 하게 에디터를 이용해 작업을 해볼 수 있다.





실행시킨 Jshell 은 /exit 명령어를 이용해서 종료할 수도 있다.


실무에서도 JShell 은 간단한 코드를 프로젝트 수정없이 테스트할 경우 굉장히 유용하며, 본인은 때때로 알고리즘을 테스트할 때 JShell 을 이용하기도 한다.


따라서... 이제는 더 이상 간단한 자바 코드의 Prototyping 을 위해 이클립스를 켜지 않아도 된다!


이처럼 Java 는 버전을 올려감에 따라서 함수형 언어의 특징을 받아들이면서 좀 더 Modern 한 언어의 특징을 위해 업그레이드되어 가고 있다.


좀 더 자세한 사용은 아래 블로그에 잘 정리되어있으니 참고해보는 것도 좋을 듯 하다.


http://taewan.kim/post/trans_jshell/




Java 에서 사용하는 Thread Local 이란 간단히 설명해서 쓰레드 지역 변수이다.


즉, Thread Local 로 정의된 객체는 같은 Thread 라는 Scope 내에서 공유되어 사용될 수 있는 값으로 다른 쓰레드에서 공유변수를 접근할 시 발생할 수 있는 동시성 문제의 예방을 위해 만들어졌다.


한 쓰레드 내에서만 사용되는 변수라더라도 전역변수처럼 State 값을 부여해서 사용하게 되므로 가능한 가공이 없는 참조용 객체의 경우가 사용되며, 지나친 사용은 재사용성을 떨어트리고 부작용을 발생시킬 수 있다.


아래의 그림을 보자.




위의 그림에서 Thread A 와 Thread B는 각 쓰레드 내부에서 사용되는 ThreadLocal 을 갖고 있으며 이 객체는 해당 Thread 내에서 일정하며 다른 Thread 로부터 격리되어 있다.


Java 에서는 이 값을 Set 하고 Get 함으로써 전역변수처럼 사용이 가능하다.


(1) Thread Local 객체 생성


(2) Set 을 통해 Thread Local 에 값 세팅


(3) Get 을 통해 Thread Local 로부터 값 조회


(4) Remove 를 통해 Thread Local 의 값 해제



주로 쓰레드 로컬은 서버에서 클라이언트 요청들에 대해 각 쓰레드에서 처리하게 될 경우, 해당 유저의 인증 및 세션정보나 참조 데이터를 저장하는 데 사용된다.


이런 경우 Spring 등에서는 Interceptor 를 이용해서 쓰레드 로컬의 작업을 제어하는 경우가 많고, 그에 따라 처리할 수 있는 정보와 처리할 수 없는 정보로 디자인을 나누는 것이 중요하다.

실무에서 Use case 를 통해 활용 방법을 학습하는 것이 중요하다.





Java 11 이 나오는 와중에 아직 Java9 와 Java10을 정리하지 못했다.(반성;;)

본 포스팅에서는 Java8 에 비해 달라진 Java9 의 Feature 들에 대해 정리해보았다.


1. Java Platform Module System (Jigsaw Project)

Java8 의 주특징이 Lambda 와 Stream 을 중심의 함수형 프로그래밍 도구들이었다면, Java9 의 가장 특징적인 부분 중 하나는 모듈(Module) 의 등장이다.


Java9 부터 사용할 수 있는 모듈은 Class 나 Interface, Package 등을 포함할 수 있는 캡슐화 도구이다.


가령 모듈은 다음과 같이 정의할 수 있다.



module sample {
    exports com.myproject.module;
    requires commons;
}

module commons {
    requires java.base;
    requires java.xml;
}



위의 예시에서 module sample 은 commons 모듈을 import 하고, commons 모듈은 java.base 모듈과 java.xml 모듈을 import 하면서 com.myproject.module 로 export 되게 된다.


여기서 requires 로 지정된 모듈 각각은 서로 dependency 를 가진다. commons 모듈을 통해 java.base 모듈과 java.xml 모듈을 import할 수 있다.


모듈이 등장한 이유는 그 이전까지의 Java 버전이 사용했던 JAR 배포에 있다. 


JAR 파일은 JVM 에 의해 로딩되는 File Archive 로 dependency 에 대한 컨셉을 갖고있지 않다.

Module 은 이를 개선하려 하며, 로딩하는 과정에서 Dependency 를 정의하고자 한다.


또한 Module 은 JAR 파일이 지원하지않는 Encapsulation 에 대한 메커니즘을 지원한다. 포함된 package 의 컬렉션 각각에 대해 필요한 곳과 불필요한 곳을 적절히 정의하고 분류하며


Java의 모듈들을 보기 위해서는 CMD를 이용해서 다음 커맨드를 사용하면 된다.


> java --list-modules



2. JShell 의 지원


이제 Java를 별도의 컴파일 과정이나 main 함수 작성을 위한 Project Structure 의 구성없이 작동시킬 수 있는 REPL 도구인 JShell 이 제공된다.


REPL(Read - Eval - Print - Loop)이란 대화식 언어도구로, JShell 은 이를 지원하는 콘솔로 보면 된다.


대략 다음과 같이 JShell 을 이용할 수 있다.


<예시>


마치 Python 의 Shell 을 흉내낸듯한 CLI 를 통해 보다 쉽게 Java 언어를 구현하고 테스트해볼 수 있다.



3. JavaDoc 이 업그레이드되었다.


JavaDoc 을 사용하면 HTML 형식의 API Document 를 작성할 수 있는데, HTML5 가 지원되도록 추가되었다.

추가로 Java Lint 기능과 Module 에 대한 지원도 되었다.



4. Stream 및 Optional API 지원이 강화되었다.


몇몇 쓰기 불편했던 Java8 의 Stream API 들이 개선되었고, Optional 에 대한 상호 지원이 추가되었다.


iterate(), takeWhile(), dropWhile() 등과 같은 Stream 연산자들은 이제 Stream 의 Laziness 를 강화하며, 이를 이용하면 마치 Python 의 Yield 처럼의 동작도 구현 가능하다.


가령 takeWhile() 연산을 이용하면 스트림을 해당 조건을 만족하는 부분까지 Process 한 후 멈춰둘 수 있다. 이는 Stream Pipeline 을 좀 더 유연하게 사용할 수 있는 흘륭한 도구이다.


가령 Stream 에 Optional에 대한 지원이 추가됨으로써 Nullable 한 상황에 대한 Stream 레벨에서 핸들링이 가능해졌다. 

이전까지 ifPresent 로 조건 체크만 가능했다면, ifPresentOrElse() 와 같은 메서드는 Stream 내에서 Optional 을 지원함으로써 흐름의 분기도 구현이 가능하다.


마찬가지로 Optional 에도 Stream 지원이 추가되어 보다 복잡한 Stream Pipeline 을 구성할 수 있게 되었다.



5. Collection Factory methods


각종 Java Collection 들을 기존까지는 "생성 후 add" 방식으로 이용했다면, 이제는 Factory Method 로 손쉽게 초기화가 가능하다.


가령 다음과 같이 하면 손쉽게 Collection 을 만들 수 있다.



List<String> texts = List.of("hello", "world");



6. Private Interface method


Java 의 인터페이스가 private 메서드를 제공한다. 이제 Interface 구현시에도 외부에 공개할 필요없는 method 를 생성함으로써 캡슐화를 유지할 수 있다.


단, Private method 의 default 구현은 public 이기 때문에 사용에 있어 주의하자.



7. 익명클래스에 대한 Diamond Operator


이제는 <>(Diamond Operator) 가 허용되며, 제약없이도 익명클래스의 사용이 가능하다.



8. HTTP/2 


Java 의 HTTPURLConnection 이 HTTP/2 와 Websocket 등을 지원한다.

또한 Multiplexing 을 통한 다중 요청 처리 후 순서에 따른 응답이 가능해졌고, Push 기능을 지원한다.


그 외에도 JAR 의 다중 Release 가 가능해져서 프로젝트 관리가 쉬워진 부분, Language 지원, 시스템 프로세스 접근의 용이성을 위한 Process API 의 지원 등 기능이 추가되었다.



+ Recent posts