개발자

“멈추지 않고 계속 전진한다” 자바가 여전히 힙한 11가지 이유

Peter Wayner | InfoWorld 2024.01.18
자바는 이제 구닥다리 언어일까? 깜박이는 표시등이 있는 전면 패널과 플로피 디스크 시절을 이야기하는 낡은 사람의 프로그래밍 언어? 아니면 향상된 기능을 통해 직관적인 코딩과 강력한 성능을 갖춘 여전히 '힙'한 언어일까? 아마 그 중간쯤, 성숙하지만 마음은 젊은 언어라고 하는 것이 더 정확할 것 같다.
 
ⓒ Getty Image Bank

자바는 약 30년 전인 1995년 5월 23일 공식적으로 세상에 등장했다. 자바의 시작은 썬 마이크로시스템즈(Sun Microsystems)가 금방이라도 미국의 거실을 점령할 것이라고 호언장담했던, 셋톱박스를 위한 "오크(Oak)"라는 기술이었다. 이 계획은 처음엔 마음대로 되지 않았다. 그러나 점점 더 성장해서 초소형 센서 칩부터 대형 서버 박스에 이르기까지 온갖 곳에서 실행되는 현대 소프트웨어의 핵심 기반 중 하나가 됐다. 

이후 자바의 개념은 크게 바뀌었다. 썬과 오라클은 자바의 핵심 기능을 크게 손상하지 않으면서도 신선한 언어라는 느낌을 유지하기 위한 기능을 접목하는 데 있어 탁월한 성과를 거뒀다. 결과적으로 자바는 멈추지 않고 계속 전진하는 언어 중 하나라고 할 수 있다. 

한 가지 확실한 것은 "자바"로 불리는 큰 텐트 안에 포함된 기능 중 상당수는 최초 구상됐던 것과는 다르며, 어떤 것은 매우 근본적으로 다르다는 사실이다. 지금 프로그래머가 만드는 자바 코드는 1995년, 2005년, 심지어 2015년의 사람들도 알아보기 힘들 수 있지만, 오래된 코드도 여전히 실행이 된다. 2010년 썬을 인수한 오라클은 현재 정기적으로 새 버전을 제공하고 자바 언어의 매력을 유지하기 위한 기능을 추가하고 있다. 

자바가 지난 시간 동안 변화해 온 11가지 큰 특징을 정리했다. 다행히 대부분은 더 나은 방향으로의 변화다. 
 

가상 스레드 

최초의 자바 버전에서는 개발자가 자신만의 Thread 객체를 만들고 멀티스레드 및 멀티코어 환경에서의 코드 실행을 제어할 수 있었다. 아무것도 없는 것보다는 나았지만 얼마 지나지 않아 프로그래머들은 Thread 객체가 크고, 생성과 삭제에 너무 많은 시간이 걸린다는 사실을 알게 됐다. 프로그램을 시작할 때 영구 스레드 풀을 생성하는 것이 번거로운 스레드에 대한 일반적인 해결 방법이 됐다. 자바 19에 이르러 가상 스레드가 등장하면서 이 모든 상황이 바뀌었다. 이제는 자바 프로그램에서 시스템 리소스를 분배하는 작업의 대부분을 JVM이 맡아 처리한다. 프로그래머가 병렬 처리를 사용할 수 있는 시점을 지정하면 런타임 JVM은 가능한 부분에서 코드를 동시에 실행한다. 가상 스레드는 더 쉽게 개발하고 지원할 수 있는 마이크로서비스와 같은 현대적 아키텍처에 매우 유용하다. 
 

구조화된 동시성 

가벼워진 스레드는 시작에 불과하다. 자바는 프로그래머와 JVM에서 더 쉽게 동시에 워크로드를 처리할 수 있게 해주는 병렬 처리용 추상 모델을 추가하고 있다. 새로운 구조화된 동시성 모델을 통해 프로그래머는 자바 워크로드를 작업(task)으로 분할할 수 있고, 이렇게 분할된 작업은 범위(scope)로 그룹화된다. 범위는 같은 스레드에서 함께 작동하는 파이버(fiber)로 수집된다. 최종 목표는 자바 개발자에게 병렬 프로그램을 구축하기 위한 표준 상용구 모델을 제공해 매번 심층적으로 추론할 필요가 없도록 하는 것이다. 또한 구조화된 동시성은 가상머신이 더 쉽게 동시 실행 기회를 감지해 프로세서 코어에 매핑할 수 있게 해준다. 
 

불변성 데이터 

String은 처음부터 불변성을 갖고 태어났다. 일단 String이 만들어지면 변경이 불가능했다. toLowerCase와 같은 함수를 호출하면 완전히 새로운 String이 생성됐다. 덕분에 JVM이 Thread 전반에서 보안과 동기화를 관리하기가 더 편해졌다. 이제 자바 프로그래머는 "레코드"를 통해 이와 같은 불변성 규칙을 자체 객체에도 지정할 수 있다. 이렇게 하면 멀티스레드 안전성, 캐싱, 동기화가 간소화된다. 코드는 필드의 이름과 형식을 나열하고 나머지 작업은 JVM이 처리한다. equals, hashCode, toString과 같은 일반적인 메서드는 자동으로 생성된다. JVM은 레코드의 불변성을 보장해서 많은 프로그램 세부 사항을 간소화하고 실행 중인 코드의 속도를 높인다.
 

가비지 수집 

자바는 항상 메모리 할당과 회수의 많은 세부 사항을 처리해 왔으며 많은 프로그래머가 기꺼이 이 기능을 JVM에 위임했다. 그러나 최초의 가비지 수집기는 사용자가 성능 저하를 체감할 만큼 긴 시간 동안 동작을 멈추는 경우가 종종 있었다. 이제 프로그래머들은 다양한 가비지 수집 알고리즘을 사용하며, 서로 다른 유형의 애플리케이션에 특화된 다음 4가지 가비지 수집기 중 선택할 수 있다. 
 
  • 가비지 퍼스트(Garbage First :G1) 가비지 수집기는 기본 선택 옵션으로, 처리량이 많고 중단 시간은 짧다. G1은 가장 큰 블록 섞기, 자주 변경되는 작은 객체의 세밀한 인식 등 이전의 자바 가비지 수집 반복에서 얻은 교훈을 바탕으로 발전된 기법을 사용한다. 
  •  Z 가비지 수집기(Z Garbage Collector)는 웹 서버, 스트리밍 서비스 및 기타 실시간 데이터 작업의 요구사항인 매우 낮은 지연시간을 제공하도록 설계됐다. 또한 16TB RAM까지 확장 가능하도록 설계됐으므로 매우 큰 힙에서도 잘 작동한다. 
  • 동시 가비지 수집기(Concurrent Garbage Collector)는 애플리케이션을 멈추는 일 없이 백그라운드에서 실행된다. 중단이 발생하면 안 되는 인터랙티브 애플리케이션 같은 작업에서 최선의 선택이지만 효율성은 떨어질 수 있다. 
  • 마지막으로 병렬 수집기(Parallel Collector)는 여러 스레드를 사용해 더 빠르게 데이터를 수집하지만 중단을 예측하기가 어렵다는 단점이 있다. 

개발자는 한 가지 가비지 수집 방법에 얽매일 필요가 없고, 객체를 재사용해 자체 메모리 관리를 시뮬레이션하는 등 다른 해결책을 선택할 필요도 없다. 이제는 각각 더 많은 튜닝과 실험을 위한 옵션을 제공하는 4가지의 선택지가 있기 때문이다.
 

switch를 사용한 패턴 매칭 

자바 개발팀은 가장 낮은 몇몇 구문 수준에서도 언어를 개선해 개발자가 더 깔끔하고 표현력이 우수한 로직을 작성할 수 있는 옵션을 제공해왔다. 예를 들면, if-then-else  조건문 스택을 만드는 데 사용되는 switch 키워드는 이제 패턴 매칭을 제공한다. 즉, 다양한 케이스를 지정하기 위한 로직이 equals와 같은 기본 식에 제한되지 않는다. 이런 패턴을 사용해 작성된 자바 코드는 매우 간결하며 데이터의 값뿐만 아니라 객체 유형도 구분할 수 있다. 모든 참조 유형과 널 포인터를 사용할 수 있다. 물론 폴스루(fall-through) 의미 체계를 사용하는 전통적인 로직도 여전히 지원하므로 이전의 코드도 계속 원활하게 실행된다. 
 

능률적인 구문 

초기의 자바 작성은 C 또는 C++ 코드를 쓰는 것과 크게 다르지 않았다. 자바와 C에서 중괄호와 세미콜론의 역할은 대부분 같았고 루프 구조는 전통적인 3부분 형식으로 만들어졌다. 내부는 리스프(Lisp)와 깊이 연결돼 있지만 자바의 기본 구문은 C 구문과 크게 다르지 않았다. 그러나 최근에 추가된 요소는 모두 루비, 파이썬과 같은 스크립팅 언어의 단순성을 차용했다. 이제 for 루프에서 모든 세부 사항을 나열할 필요가 없다. 목록 또는 배열을 루프로 순환할 때 컴파일러가 이를 직관적으로 알 수 있기 때문이다. 익명 함수와 람다 식 역시 키 입력을 줄이고자 하는 프로그래머에게 좋은 선택이다. C의 장황함과 과도한 구두점은 아직 일부 남아 있지만 지금의 자바 프로그래머는 더 적은 문자로 복잡한 구조를 표현할 수 있다. 
 

봉인 클래스 

JVM은 애초부터 프로그래머가 실수로 남겨둘 가능성이 있는 많은 일반적인 보안 허점을 방지하도록 설계됐다. 최신 버전에는 더욱 많은 옵션이 추가됐다. 예를 들어 봉인 클래스(sealed class)를 통해 클래스 작성자는 정확히 어떤 클래스가 해당 클래스를 확장할 수 있는지 지정할 수 있다. 이렇게 하면 라이브러리를 사용하는 다른 사람이 클래스를 확장해 기능을 추가하거나 원래 기능의 일부를 오버라이딩하는 것을 방지할 수 있다. 또한 봉인 클래스는 더 적극적인 최적화와 인라이닝을 허용하므로 기존 클래스보다 실행 속도가 조금 더 빠르다. 메서드 디스패치도 간소화할 수 있다. 
 

외래 함수와 메모리 

자바 가상머신은 울타리로 둘러싸인 정원, 또는 형식 안전 샌드박스로 설계됐다. 가상머신은 코드를 보호하고, 코드가 네이티브로 실행될 때 발생할 수 있는 많은 일반적인 공격을 차단한다. 원래의 자바 네이티브 인터페이스(JNI)는 일종의 백도어였다. 자바 개발팀은 다른 언어로 작성된 라이브러리와 스택을 연결해야 하는 개발자가 종종 있다는 점과, 일부 시스템 호출이 필수적이라는 점을 알고 있었다. 그래서 사용 시의 위험에 대한 간단한 경고와 함께 JVM 갑옷에 구멍을 냈다. 

이제는 외래 함수 및 메모리 API가 있다(현재 JEP 세 번째 프리뷰). 이 API를 사용하면 더 쉽고 안전하게 외부와 연결할 수 있다. 훨씬 더 많은 작업을 순수 자바로 작성할 수 있고, 자바 개발자가 일반 시스템 메모리에 연결할 수 있다. 또한 심각한 잠재적 오버플로우 공격을 차단하기 위해 형식 검사와 같은 더 강력한 보호 수단도 추가로 제공한다. 이 API는 자바 코드가 시스템 코딩에서 더 저수준의 작업 및 데이터 처리를 맡을 수 있게 해준다. 자바 프로그래머가 샌드박스에서 더 안전하게 나올 수 있는 방법이다.
 

벡터 API 

많은 베테랑 자바 프로그래머들이 아는 원래의 Vector 클래스는 수학적 도구보다는 데이터 구조에 가까웠다. 객체를 넣어두기 위한 유연하고 동기화된 솔루션으로, List와 크게 다르지 않았다. 새로운 벡터 API는 훨씬 더 범위가 넓다. 인공지능 알고리즘에서 행렬과 벡터를 사용하는 방식이 물리학자와 수학자가 사용하는 방식과 비슷해지면서 점점 더 일반화되고 있는, 일종의 수학적 데이터 처리 도구다. 개별 요소는 프리미티브 형식일 수 있으며 내적(dot product)과 같은 많은 기본 수학 연산이 지원한다. 

Vector 클래스와 API의 차이점을 확인하는 좋은 방법은 add 메서드가 수행하는 작업을 보는 것이다. 원래의 클래스에서는 다른 모든 Collections 클래스와 마찬가지로 데이터 구조의 끝에 객체를 붙였다. API의 경우 개별 요소를 수학적으로 추가하는 데 사용된다. 엔지니어의 생각에 더 부합하는 방식이다. 또한 벡터 API를 이용하면 최신 SIMD 프로세서의 강력한 연산 성능을 활용해 자바 프로그래머가 다수의 긴 벡터를 처리하는 코드를 작성할 수 있다. 
 

널 처리 개선 

이 객체는 널 포인터인가? 자바 코드에서는 객체를 검사하고, 두 번 검사하고, 세 번 검사하기 위한 코드가 많은 부분을 차지한다. 코드를 간소화하고 속도를 높이기 위해 자바는 더 매끄럽게 널 포인터를 처리하기 위한 기능을 천천히 추가해 왔다. 예를 들어 스트림(Stream) API는 긴 데이터 스트림을 처리할 수 있으며 이따금 널 값이 나타나도 멈추지 않는다. Optional 클래스 래퍼는 실제 객체를 저장할 수도, 저장하지 않을 수도 있으므로 코드가 원활하게 흐르게 된다. 여전히 널을 검사하고 싶다면 매우 간결한 방식으로 널을 테스트하는 널 안전 연산자(?.)를 사용하면 된다. 
 

무료인데 유료 라이선스? 

자바는 적어도 프로그래머에게는 항상 무료나 다름없었다. 처음부터 썬은 무료 툴과 하드웨어로 개발자를 유인하고자 했고 1997년에는 자바 언어와 가상머신의 많은 부분을 오픈소스화하는 과감한 조치도 취했다. 최근까지도 개발자는 아무런 비용도 지불하지 않고 한 번 작성한 코드를 어디서나 실행할 수 있었다. 

지금은 상황이 점점 혼탁해지고 있다. 오라클의 많은 자바 버전은 무료지만 일부는 이상한 조건의 라이선스를 가졌다. 오라클은 프로그래머가 금전적인 제약 없이 자유로운 창작을 즐기기를 원하지만, 동시에 자바를 통해 상당한 수준의 장기적인 이익을 얻는 기업으로부터 일종의 세금 또는 임대료를 받아내고 싶어 하는 것 같다. 오라클이 '구독 기능'이라고 부르는 것에 요금을 부과한다는 이야기다. 결국 자바는 여전히 무료지만, 상업적 용도로 업그레이드하려면 돈을 내야 한다. 
editor@itworld.co.kr
 Tags 자바 Java
Sponsored

회사명 : 한국IDG | 제호: ITWorld | 주소 : 서울시 중구 세종대로 23, 4층 우)04512
| 등록번호 : 서울 아00743 등록발행일자 : 2009년 01월 19일

발행인 : 박형미 | 편집인 : 박재곤 | 청소년보호책임자 : 한정규
| 사업자 등록번호 : 214-87-22467 Tel : 02-558-6950

Copyright © 2024 International Data Group. All rights reserved.