OpenJDK로 Java 언어 개선 주도권이 넘어간 후 Java의 개선 속도가 몰라보게 빨라지고 있습니다. Java를 언어, 런타임, 표준 API로 나눌 때 프로그래머에게 가장 중요하다고 볼 수 있는 언어 관점에서 Java가 앞으로 어떻게 개선될 지, Java의 미래를 알아보려고 합니다.
2. 자기 소개
* 우아한 형제들(배달의 민족) 인프라 서비스실 담당
* 한국스프링사용자모임(KSUG) 고문(이라 쓰고 홍보 담당이라 읽음)
* 페이스북 자바워키(Javawocky) 그룹 운영
https://www.facebook.com/groups/javawocky/
* 자바를 주로 사용하였었고 스칼라를 좋아만함
* 좋은 개발 문화와 개발 기법에 관심이 많음 (애자일, DevOps 관련)
* 연락처
페이스북: https://www.facebook.com/fupfin.geek
이메일: gyumee@gmail.com
6. jAvA - 노동자의 언어
“해롭지 말자”
“Java presents a new viewpoint in the evolution of programming languages--
creation of a small and simple language that's still sufficiently comprehensive to
address a wide variety of software application development.”
Java is a blue collar language. It’s not PhD thesis material but a language for a
job. Java feels very familiar to many different programmers because we preferred
tried-and-tested things - James Gosling, “The Feel of Java"
설계목표 == 단순 & 친숙
8. OpEnJDK::소개
# 설립
*2006/5, 썬이 자바원에서 자바를 오픈소스로 전환한다고 공표
*2006/11/13, JVM(HotSpot)과 컴파일러를 먼저 GPL 라이선스로 공개
*2007/5/8, 자바 클래스 라이브러리 GPL로 공개, 첫 OpenJDK 출시
*2007/6, 레드햇 아이스드티(IcedTea) 프로젝트 시작
*2007/11/5, 레드햇 OpenJDK 참여
*2011/7/28, OpenJDK에서 개발한 첫 자바 버전 OpenJDK 7 발표
*2014/3/18, OpenJDK 8 발표, JDK 8의 기반으로 쓰임
#정의
*오픈소스 자바 SE와 관련 프로젝트를 중심으로 한 커뮤니티
*JCP의 자바 규격 요청서(Java Specification Requests;JSR)와 별도로 JDK
개선 제안(JDK Enhancement-Proposal; JEP) 프로세스 운영
*JCP보다 훨씬 다양한 시도를 폭넓고 빠르게 시도
11. OpEnJDK::개선흐름
# 언어의 현대화
* 표현 간소화 & 함수형 특성 도입
* 다중 코어 시대 대응
* System 자바
# 클라우드
* 시스템 통합;
* 성능 향상, 경량화;
* GC 개선, 관측성 개선
# 다언어용 범용 VM
* 강한 추상화와 시스템 통합을 양 방향으로 동시에 진행
* Macro-instructions (indy), simplified data model (value types)
* Java-on-Java (JSR 292 v2, Panama, Graal , Metropolis)
15. AmbEr::소개
JEPs = {
JEP 286 지역변수 타입 추론,
JEP 301 열거형 개선,
JEP 302 람다식 잔반 처리,
JEP 305 패턴 매칭,
JEP 325 switch 식,
JEP 326 미가공_문자열
}
16. AmbEr::지역변수_타입_추론(JEP-286)
# 지속적으로 확대된 타입 추론
* 자바 5: 제네릭 메서드 타입 추론
List<User> empty = Collections.<User>emptyList();
* 자바 7: 다이아몬드 연산자(<>)
List<User> users = new ArrayList<Users>();
* 자바 8: 람다식
users.stream.filter((User user) -> user.getSurName().equals(“park”)) ……
# 자바 10: 지역변수 타입 추론
var users = VisitorRegister.getVisitors();
17. AmbEr::지역변수_타입_추론(JEP-286)
# 사용법
Collector<UserProfile, ?,
Map<Integer, Map<String, List<UserProfile>>>> groupingCollector =
Collectors.groupingBy(UserProfile::getAge,
Collectors.groupingBy(UserProfile::getCity));
var groupingCollector =
Collectors.groupingBy(UserProfile::getAge,
Collectors.groupingBy(UserProfile::getCity));
# 람다식(JEP 323)
BinaryOperator<Processor, String> op = (var x, var y) -> x.process(y);
BinaryOperator<Processor, String> op =
(@Nonnull var x, @Nullable var y) -> x.process(y)
18. AmbEr::지역변수_타입_추론(JEP-286)
# 제약
// 필드와 메서드의 반환 타입
class MyClass {
var field = 0;
……
public var getAttribute() { …… };
}
// null 값 지정
var model;
model = “Gundam MkII”;
// 두 변수 이상 선언
var i = 0, j = 0;
// 중복 타입 추론
var dict = new HashMap<>();
21. AmbEr::미가공_문자열(JEP-326)
//특수기호 후처리 없는 문자열
// 불필요한 후처리(escaping) 제거
out.println(“this".matches("wwww"));
out.println("this".matches(`wwww`));
// 자바 코드에 타 언어 소스나 틀을 맞춘 문서를 그대로 삽입
String script = "function hello() {n" +
" print('"Hello World"');n" +
"}n" +
"n" +
"hello();n";
String script = `
function hello() {
print('"Hello World"');
}
hello();
`
22. AmbEr::미가공_문자열(JEP-326)
# 특징
- 짝맞춤을 통해 미처리 문자열 내 “`” 문자 허용,
- 개행문자를 제외한 모든 문자를 처리 없이 그대로 사용,
- 후처리를 위한 String 클래스에 escape() 메서드 추가,
- 아직 JEP 처리 상태는 Candidate라 향후 변경 가능성이 큼
# 다양한 사용 예
`"` // a string containing " alone
``can`t`` // a string containing 'c', 'a', 'n', '`' and 't'
`This is a string` // a string containing 16 characters
`n` // a string containing '' and 'n'
`u2022` // a string containing '', 'u', '2', '0', '2' and '2'
`This is a
two-line string` // a single string constant
24. AmbEr::Switch식(JEP-325)
# Switch 문? Switch 식?
* 식 == 연산 후 값 반환
* if 문
if(조건식) { … } else { … }
var result = if(조건식) { … } else { … } //(x)
* 삼항연산자를 사용한 식
var result = 조건식 ? 값1 : 값2; //(0)
* 지금까지 자바에서 swtich는 문이었으나 식으로도 사용 가능
25. AmbEr::Switch식(JEP-325)
//switch 문
int numDays = 0;
switch (month) {
case 1: case 3: case 5:
case 7: case 8: case 10:
case 12:
numDays = 31;
break;
case 4: case 6:
case 9: case 11:
numDays = 30;
break;
case 2:
if (((year % 4 == 0) &&
!(year % 100 == 0))
|| (year % 400 == 0))
numDays = 29;
else
numDays = 28;
break;
}
//switch 식
int numDays = switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> 31;
case 4, 6, 9, 11 -> 30
case 2 ->
(((year % 4 == 0) &&
!(year % 100 == 0))
|| (year % 400 == 0)) ?
29 : 28;
}
간략해진 코드
26. AmbEr::패턴 매칭
JEPs = {
JEP 286 지역변수 타입 추론,
JEP 301 열거형 개선,
JEP 302 람다식 잔반 처리,
JEP 305 패턴 매칭,
JEP 325 switch 식,
JEP 326 미가공_문자열
}
27. AmbEr::패턴 매칭::데이터_클래스
# 자바 객체의 다양한 용도
* “구조체”, // C, 파스칼
* “값”, // Integer, Long, Boolean, Double
* “데이터 전달 객체(DTO)”,
* “객체”, // OOP의 최소 단위, 데이터보다는 행위 기준
* “컴포넌트”
# 구조체/데이터 전달 객체로서의 일반적인 자바 객체
public class Coordinate {
private double lat;
private double lon;
public Coordinate(double lat, double lon) {
this.lat = lat;
this.lon = lon;
}
// Getters/Setters, toString(), equals(), hashCode(), etc. 필요
}
28. AmbEr::패턴 매칭::데이터_클래스
대수적 자료형(algebraic data types)
//스칼라 케이스 클래스
case class Coordinate (lat: Double, lon : Double)
//코틀린 데이터 클래스
data class Coordinate(val lat: Double, val lon: Double)
//자바 데이터 클래스 (안)
record Coordinate(double lat, double lon) {}
//사용 예: 산술식
interface Exp { }
abstract record BinOpExp(Exp left, Exp right) implements Exp {};
abstract record UnOpExp(Exp exp) implements Exp {};
record PlusExp(Exp left, Exp right) extends BinOpExp(left, right) {};
record SubExp(Exp left, Exp right) extends BinOpExp(left, right) {};
record MulExp(Exp left, Exp right) extends BinOpExp(left, right) {};
record DivExp(Exp left, Exp right) extends BinOpExp(left, right) {};
record NegExp(int constant) implements Exp {};
record IntExp(int constant) implements Exp {};
29. AmbEr::패턴매칭
# 패턴매칭 == Switch식 + 타입 비교
interface Shape {};
record Point(int x, int y) implements Shape;
record Circle(Point center, int radius) implements Shape;
……
Canvas newCanvas;
// 기존 if를 사용한 타입 확인 방식
if(shape instanceOf Point) {
Point pt = (Point) shape;
newCanvas = canvas.drawPoint(pt.x, pt.y);
}
else if (shape instanceOf Circle) {
Circle cir = (Circle) shape;
newCanvas = canvas.drawCircle(cir.center.x, cir.center.y, cir.radius);
}
else if (shape instanceOf Rectangle) {
……
}
else if (shape ……
30. AmbEr::패턴매칭
# 패턴매칭 == Switch식 + 타입 비교
// Switch 식을 이용한 타입 확인 방식
Canvas newCanvas =
switch(shape) {
case Point pt -> canvas.drawPoint(pt.x, pt.y);
case Circle cir -> canvas.drawCircle(cir.center.x, cir.center.y,
cir.radius);
case Rectangle rct -> ……
……
default -> canvas;
}
31. AmbEr::패턴매칭
# 패턴매칭 == Switch식 + 타입 비교 + 객체 분해
객체를 분해해서 생성자 인자값을 다시 꺼내서 변수에 할당
interface Exp { }
abstract record BinOpExp(Exp left, Exp right) implements Exp;
record PlusExp(Exp left, Exp right) extends BinOpExp(left, right);
record SubExp(Exp left, Exp right) extends BinOpExp(left, right);
record IntExp(int constant) implements Exp;
……
int eval(Exp e) {
return switch(e) {
case IntExp(var i) -> i;
case PlusExp(var l, var r) -> eval(l) + eval(r);
case SubExp(var l, var r) -> eval(l) - eval(r);
……
}
32. AmbEr::패턴매칭
# 비지터 패턴이었다면...
interface Exp { accept(ExpVisitor visitor); }
record IntExp(int constant) implements Exp { … }
record PlusExp(Exp left, Exp right) implements Exp {
public int accept(ExpVisitor visitor) { return visit(this); }
}
record SubExp(Exp left, Exp right) implements Exp { … }
……
class ExpVisitor {
public int visit(IntExp e) {
return e.constant;
}
public int visit(PlusExp e) {
return e.left.accept(this) + e.right.accept(this);
}
public int visit(SubExp e) { … }
……
}
33. AmbEr::패턴매칭
# 패턴매칭 == Switch식 + 타입 비교 + 객체 분해 + 값 비교
객체를 분해해 얻는 생성자 인자값과 패턴에 주어진 값을 비교
#유클리드 호제법 예제
2개의 자연수(또는 정식) a, b에 대해서 a를 b로 나눈 나머지를 r이라 하면(단, a>b), a와 b의
최대공약수는 b와 r의 최대공약수와 같다.
gcd(a, 0) = a
gcd(a, b) = gcd(b, a mod b)
int gcd(Pair pair) {
return switch(pair) {
case Pair(var a, 0) -> a;
case Pair(var a, var b) -> gcd(Pair.of(b, a % b));
}
34. AmbEr::패턴매칭
# 패턴매칭 == Switch식 + 타입 비교 + 객체 분해 + 값 비교
패턴을 중첩해서 적용할 수 있음
Exp simplify(Exp exp) {
return switch(exp) {
case IntExp -> exp;
case NegExp(var e) -> new NegExp(simplify(e));
case NegExp(NegExp(var e)) -> simplify(e);
case PlusExp(IntExp(0), var e),
PlusExp(var e, IntExp(0)),
SubExp(IntExp(0), var e),
SubExp(var e, IntExp(0)) -> simplify(e);
case PlusExp(var l, var r) -> new PlusExp(simplify(l), simplify(r));
case SubExp(var l, IntExp(0)) -> simplify(l);
case SubExp(var l, var r) -> new SubExp(simplify(l), simplify(r));
};
}
36. vAhAllA::소개
JEPs = {
JEP 169: 값 객체
JEP 218: 원시타입 제네릭(제네릭 특화)
JEP 193: 변수 핸들
}
자바 제네릭의 한계를 극복하고 참조 타입 때문에 발생하는 자바 성능을 개선
37. vAhAllA::기존자바타입
자바의 타입 = {원시 타입, 참조 타입}
원시 타입 = {boolean, byte, char, short, int, long, float, double}
참조 타입 = {모든 객체, 배열}
* 비효율적인 참조 타입에 의존
* 힙 메모리 정리(GC)가 복잡해짐
* 원시 타입을 대응하는 객체로 변환(boxing)/복원(unboxing)하는 비용 발생
변수
데이터
데이터
변수
변수
참조
참조
참조
39. vAhAllA::값타입
“코드는 클래스 같지만 동작은 값처럼”
* 데이터의 일렬, 밀집 배열
* 원시타입과 참조타입의 간극 채움
* 기존 참조타입(L-타입)에 새로운 값 타입(Q-타입)을 JVM에 추가
문법
value class Rational {
final int numer; // 분자
final int denom; // 분모
}
* 작은 구조체에 적합: 복소수, 좌표, 도형, 튜플
* 불변(Immutable)
* 동시성 환경에 유리
* GC에 유리
* 자바 원시 타입 외 시스템 고유의 자료 타입 표현 가능(ex, int128)
40. vAhAllA::자바_제네릭
#참조 타입만 허용하는 자바 제네릭
List<int> primeNums = new ArrayList<>(); // compile error
#타입 소거
* 자바 제네릭은 컴파일러 기술
* 타입 매개변수 값은 소거되어 VM은 정보를 알지 못함 (하위호환성)
ArrayList<String>();
ArrayList<Integer>();
ArrayList<User>();
ArrayList<Point>();
ArrayList.class
ArrayList.class
ArrayList.class
ArrayList.class
소스코드 JVM
컴파일
41. vAhAllA::제네릭_특화
# 값타입에 맞게 동적으로 클래스 변조
ArrayList<int>();
ArrayList<Rational>();
ArrayList<Complex>();
ArrayList${T=int}.class
ArrayList${T=Rational}.class
ArrayList${T=Complex}.class
소스코드 JVM
컴파일
# C++ 템플릿 비교
* C++ 템플릿은 제네릭 특화처럼 매 적용마다 별도 코드를 생성
* 자바 제네릭 특화는 런타임에 동작, C++ 컴파일 시점에 동작
* 자바 제네릭은 타입 매개변수에만 적용
* 참조 타입에는 기존처럼 타입 소거 적용
# 포인터 다형성 vs 표상(representation) 다형성
42. vAhAllA::값_기반_클래스
# 값 기반 클래스(Value Based Class)
* 자바 8에 도입된 클래스 규격
*final이고 값이 변해서는 안됨
*값 변경 가능 객체를 참조할 수는 있음
*equals, hashCode, toString은 상태로만 계산해야 하며 식별자를 써서는 안됨
*equals()로만 동치성을 비교해야 하며 동일성(==)은 보장 안함
*팩토리 메서드를 사용해서만 객체를 생성해야 함
*동치인 두 객체에는 행동이 언제나 동일해야 함
*식별자 기반 작업은 예측할 수 없는 결과 발생 가능 (동기화, 직렬화 등)
//java.util
Optional, OptionalDouble, OptionalLong, OptionalInt
//java.time
Duration, Instant, LocalDate, LocalDateTime, LocalTime, MonthDay, OffsetDateTime, OffsetTime,
Period, Year, YearMonth, ZonedDateTime, ZoneId, ZoneOffset
//java.time.chrono
HijrahDate, JapaneseDate, MinguaDate, ThaiBuddhistDate
43. vAhAllA::최소_값_타입(Minimal Value Type)
# 최소 값 타입
* 발할라(Vahalla) 프로젝트의 첫 가시적 결과, 부분 집합
* indy와 같이 “VM 먼저, 언어는 나중” 접근 방식(언어와 VM의 분리)
* 자바 문법 변화 없음
* 값 가능 클래스: @jdk.incubator.mvt.ValueCapableClass
* JVM 내부적으로만 값 타입 동작 (선택가능)
* 값 기반 클래스를 JVM의 1등급 구성체로 취급
* java -Xverify:none -XX:+EnableMVT <Test>
44. vAhAllA::VCC_&_DVC
# 값 가능 클래스
* 클래스는 final로 상속 불가
* 인터페이스가 아닌 일반 클래스
* Object를 직접 상속해야 함
* 멤버 필드는 모두 final로 변경 불가
* equals, hashCode, toString을 재정의(Override)
* clone과 finalize는 재정의하지 말아야 함
#파생 값 타입
* 값 타입으로 표시됨
* 값 가능 클래스에서 유도된 새 이름이 주어짐
* VCC의 상속 타입은 제거됨
* VCC의 모든 메서드와 생성자는 제거됨
* 멤버필드는 변경 없이 유지
VCC소스코드
VCC클래스파일
DVC메모리의 클래스 VCC메모리의 클래스
컴파일
클래스로더
VCC 값 가능 클래스
DVC 파생 값 클래스
45. vAhAllA::최소_값_타입_성능
# valuetypifier
* 자바 8 코드를 값 타입 관련 opcode로 변경하는 도구
* https://github.com/forax/valuetypify
// 코드
ColorList list = new ColorList();
for(int i = 0; i < 1_000_000; i++) {
list.add(new Color(i, i, i));
}
// 결과 (참조 타입)
Color(2.2517998E7, 2.2517998E7, 2.2517998E7)
creation time 2886.933223 ms
average time 606.217409 ms
// 결과 (값 타입)
Color(2.2517998E7, 2.2517998E7, 2.2517998E7)
creation time 1039.692931 ms
average time 70.152561 ms
47. lOOm::화이버
#컨티뉴에이션(Continuation; 지속, 연속)
* 작업 단위
* 중단 후 재실행 가능
# 화이버(Fiber)
* 자바가 관리하는 경량 쓰레드 (쓰레드는 OS가 관리)
* 쓰레드처럼 동작하지만 쓰레드보다 훨씬 가볍게 동작
* 컨티뉴에이션을 관리
* 서버는 대부분 시간을 IO 응답을 기다리지만 쓰레드는 너무 무거움
* 쓰레드를 추상화해 사용하는 비동기 모델은 복잡함 (액터, 반응형 프로그래
밍 등)
* 동기 방식과 유사하게 확장 가능한 프로그래밍 작성 가능
* 기존 코드를 훨씬 가볍게 돌릴 수 있는 파이버가 필요