티스토리 뷰
Java 8 변경사항
2014년에 발표된 Java SE(Standard Edition) 8 버전에서는 다음과 같은 주요 변경사항이 있습니다.
- 람다 표현식 (Lambda expression): 함수형 프로그래밍이 가능하게 됨
- 스트림 API (Stream API): 데이터를 추상화하여 다룰 수 있게 됨
- java.time 패키지: 더 직관적이고 개선된 Date, Time API를 제공
- 나즈혼 (Nashorn): 자바스크립트의 새로운 엔진을 도입
각 변경사항들의 특징에 대해서 살펴보겠습니다.
람다 표현식 (Lambda Expression)
람다 표현식(Lambda Expression)이란?
람다 표현식이란 익명 클래스의 한 개의 메소드를 식으로 표현한 것입니다. 여기서 익명 클래스란 말 그대로 이름이 없는 클래스로써, 단 한 개의 객체만을 생성할 수 있는 일회용 클래스입니다. (자바는 클래스의 선언과 동시에 객체를 생성하기 때문에 이름이 없으면 선언되는 그 순간에만 사용될 수 있습니다.)
- 익명 클래스의 예
new Object()
{
int min(int x, int y)
{
return x < y ? x : y;
}
}
- 람다 표현식의 예
(x, y) -> x < y ? x : y;
이러한 람다 표현식은 매개변수로 전달될 수도 있으며, 메소드의 결괏값으로 반환될 수도 있습니다. 따라서 람다 표현식을 사용하면 기존의 불필요한 코드를 줄여주고, 작성된 코드의 가독성을 높여줍니다. Java SE 8부터는 이러한 람다 표현식을 사용하여 자바에서도 함수형 프로그래밍을 할 수 있게 되었습니다.
람다 표현식 작성법
자바에서는 화살표(->) 기호를 사용하여 람다 표현식을 작성할 수 있습니다. 문법은 다음과 같습니다.
(매개변수 목록) -> {함수 몸체}
자바에서 람다 표현식을 사용할 때 주의할 점은 다음과 같습니다.
- 매개변수가 한 개인 경우 ()를 생략할 수 있습니다.
- 함수 몸체가 한 개의 명령문으로만 이루어진 경우에는 {}를 생략할 수 있습니다.
- 함수 몸체가 한 개의 return 문으로만 이루어진 경우에는 {}를 생략할 수 없습니다.
다음은 전통적인 스레드 생성 방식과 람다 표현식을 사용한 스레드 생성 방식을 비교하는 예제입니다.
new Thread(new Runnable()
{
public void run()
{
System.out.println("전통적인 방식의 스레드 생성");
}
}).start();
new Thread(()->{
System.out.println("람다 표현식을 사용한 스레드 생성");
}).start();
위의 예제에서 볼 수 있듯이, 매개변수로 정의된 Runnable() 인터페이스와 run() 추상 메소드를 람다 표현식을 사용하여 더 간결하게 구현한 것을 알 수 있습니다.
함수형 인터페이스 (Functional Interface)
함수형 인터페이스란 람다 표현식을 하나의 변수에 대입할 때 사용하는 참조 변수의 타입을 의미합니다. 함수형 인터페이스는 추상 클래스와 달리 단 한 개의 추상 메소드만을 가져야 합니다. 또, 다음과 같은 어노테이션(annotation)을 사용하여 함수형 인터페이스임을 명시할 수 있습니다.
@FunctionalInterface
위와 같은 어노테이션을 인터페이스의 선언 위에 붙이면, 컴파일러는 해당 인터페이스를 함수형 인터페이스로 인식합니다.
다음은 함수형 인터페이스의 예제입니다.
// 함수형 인터페이스 구현
@FunctionalInterface
interface ExampleInterface
{
public int doSomething(int x, int y);
}
public class test
{
public static void main(String[] args)
{
ExampleInterface implemented = (x, y) -> x + y; // 추상 메소드 구현
System.out.println(implemented.doSomething(10, 11)); // 21을 출력함
}
}
위의 예제에서 볼 수 있듯이, implemented 변수는 람다 표현식으로 구현된 객체를 가리키고 있습니다. implemented 변수는 구현된 함수형 인터페이스 내의 doSomething() 메소드를 실행할 때마다, 람다 표현식으로 구현한 추상 메소드를 실행합니다.
스트림 API (Stream API)
스트림 API(Stream API)란?
자바에서는 여러 개의 데이터를 저장하기 위해서 배열이나 컬렉션을 사용합니다. 그리고 이렇게 저장된 데이터에 접근하기 위해서는 반복문이나 반복자(iterator)를 사용하여 매번 코드를 작성해야 했습니다.
하지만 이렇게 작성된 코드는 길이가 길고 가독성도 떨어지며, 코드의 재사용이 거의 불가능합니다. 또한, 정형화된 처리 패턴을 가지지 못했기 때문에 데이터마다 다른 방법으로 접근해야만 했습니다.
이러한 문제점을 극복하기 위해서 도입된 방법이 스트림 API입니다. 스트림 API는 데이터를 추상화해서 다루므로, 다양한 형태로 저장된 데이터를 위한 공통된 방법을 제공합니다. 따라서 스트림 API를 사용하면 배열이나 컬렉션 뿐만아니라 파일에 저장된 데이터도 모두 같은 방법으로 다룰 수 있습니다.
스트림 API의 특징
스트림 API는 다음과 같은 특징을 가집니다.
- 스트림은 외부 반복을 통해 작업하는 컬렉션과는 다르게 내부 반복을 통해 작업을 수행합니다.
- 스트림은 단 한번만 사용할 수 있습니다. (= 재사용이 불가능합니다.)
- 스트림은 원본 데이터를 변경하지 않습니다.
- 스트림의 연산은 필터-맵(filter-map) 기반의 API를 사용하여 lazy 연산을 통해 성능을 최적화합니다.
- 스트림은 parallelStream() 메소드를 통해 간단한 병렬처리를 지원합니다.
다음은 스트림 API의 예제입니다.
// 정수형 배열에서 스트림 생성
Integer[] arr1 = new Integer[] {1, 5, 11, 13, 20, 52};
Stream stream1 = Arrays.stream(arr1);
stream1.map(i -> i * 2);
stream1.filter(i -> i % 2 == 0); // 재사용이 불가능하기 때문에 에러 발생!
// 정수형 배열에서 스트림 생성
Integer[] arr2 = new Integer[] {1, 5, 11, 13, 20, 52};
Stream stream2;
stream2 = Arrays.stream(arr2)
.filter(i -> i % 2 != 0) // {1, 5, 11, 13}
.map(i -> i * 2); // {2, 10, 22, 26}
스트림 API는 다음과 같이 세 가지 단계에 걸쳐서 동작합니다.
- 스트림 생성
- 스트림 중개 연산 (filter)
- 스트림 최종 연산 (map)
위의 예제에서 필터-맵이 동작하는 순서는 다음과 같습니다.
java.time 패키지
JDK 1.0에서는 Date 클래스를 사용하여 날짜에 관한 연산을 수행했습니다. 하지만 현재는 Date 클래스의 대부분의 메소드는 사용을 권장하지 않습니다. (deprecated) JDK 1.1부터 제공된 Calendar 클래스는 날짜와 시간에 대한 정보를 쉽게 얻을 수 있었습니다. 하지만 Calendar 클래스는 다음과 같은 문제점을 가지고 있습니다.
- Calendar 인스턴스는 immutable object가 아니라서 값이 수정될 수 있습니다.
- 윤초(leap second)와 같은 특별한 상황을 고려하지 않습니다.
- Calendar 클래스에서는 월(month)을 나타낼 때 1~12가 아닌 0~11로 표현해야합니다.
따라서 많은 개발자들은 Calendar 클래스뿐만 아니라 더 나은 성능의 Joda-Time이라는 라이브러리를 함께 사용해왔습니다. Java SE 8 버전에서는 이러한 Joda-Time 라이브러리를 발전시킨 새로운 날짜/시간 API인 java.time 패키지를 제공합니다. java.time 패키지는 위와 같은 문제점을 모두 해결했으며, 다양한 기능을 지원하는 하위 패키지를 포함하고 있습니다.
다음은 java.date 패키지의 예입니다.
LocalDate today = LocalDate.now();
System.out.println("올해는" + today.getYear() + "년입니다.");
LocalDate otherDay = today.withYear(1982);
System.out.println("올해는" + otherDay.getYear() + "년입니다.");
나즈혼 (Nashorn)
지금까지 자바스크립트의 기본 엔진으로는 모질라의 라이노 (Rhino)가 사용되어 왔습니다. 하지만 세월이 흐르면서 자바의 최신 개선 사항 등을 제대로 활용하지 못하는 등 노후화 된 모습을 보여주게 됩니다.
따라서 Java SE 8 버전부터는 자바스크립트의 새로운 엔진으로 오라클의 나즈혼 (Nashorn)을 도입하게 됩니다. 나즈혼은 기존에 사용되어 온 라이노에 비해 성능과 메모리 관리 측면에서 크게 개선된 스크립트 엔진입니다.
'프로그래밍 언어 > Java' 카테고리의 다른 글
[Java] JVM이란? (0) | 2020.01.30 |
---|---|
[Java] Java란? (0) | 2020.01.29 |
- Total
- Today
- Yesterday