Home Java 8 파헤치기
Post
Cancel

Java 8 파헤치기

Java 8 소개


들어가기전에..

2014년, Java의 새로운 버전(1.8)이 공개되었다. Java의 버전 업은 Evolution (기능적인 부분의 개선)과 Revoultion(언어 자체 형태의 변화)으로 나뉘는데, 이번 Java 8 버전 업은 Revolution에 속한다고 한다. Java 8에서 어떠한 기능들이 추가되었는지, 잘 정리된 여러 블로그의 글을 인용해 정리해보려고 한다.

인터페이스에 찾아온 변화


Java 8의 인터페이스는 default methodstatic method를 포함하여 자체 구현을 가지게 되었다. default method 역시 이번 Java 8부터 추가 된 것으로, default 지시자를 이용해 기본 메소드의 정의가 가능하게되어 인터페이스를 구현하는 기존 코드의 변경없이 새 메소드의 추가가 가능해졌다. 원래 객체지향 언어에서 인터페이스는 그 시그너처와 선언이 변하지 않는다는 것을 전제로 하여 다형성(polymophism)을 정의하는 객체간의 규약이었지만, Java 8 인터페이스는 이를 확장하는 개념을 도입하였다. 이로 인해 기존 인터페이스에 비해 애매모호하다는 점과 C++과 같이 다중 상속이라는 두 가지 문제점이 예상된다. 아래는 다중 상속으로 인한 하위 클래스의 문제점을 표현한 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface A {
    default void foo() { … }
}

public interface B {
	default void foo() { … }
}

public class Z implements A, B {
	@Override
    public void foo() {
	    A.super.foo(); // or B.super.foo();
	}
}

람다 표현식 지원


Java 8에 추가된 기능 중 가장 큰 변화라고 생각한다. Java 8 에서는 ‘단 하나의 메서드만 선언된 Interface’만을 람다로 표현할 수 있도록 강제하여 함수형 프로그래밍을 가능하게 한다. 여기서 정의되는 인터페이스를 ‘함수형 인터페이스’라고 정의한다. 람다식을 이용하면 동작과 데이터를 모두 동적으로 설정하는것이 가능해진다. 아래의 예제들은 모두 왼쪽이 입력값이 되고, 오른쪽이 동작에 대한 정의이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Concatenating strings
(String s1, String s2) -> s1+s2;

// Squaring up two integers
(i1, i2) -> i1*i2;

// Summing up the trades quantity
(Trade t1, Trade t2) -> {
  t1.setQuantity(t1.getQuantity() + t2.getQuantity());
  return t1;
};

// Expecting no arguments and invoking another method
() -> doSomething();

람다 표현은 화살표를 중심으로 두 부분으로 나뉘어진다. 왼쪽은 메소드의 인수이고 오른쪽은 이 인수로 할 일인데 예를 들어 비즈니스 로직 같은 것이다. 본문은 하나의 표현식이거나 코드 블록이고 결과값을 반환할 수도 있다.

첫 번째 람다 표현 (String s1, String s2) → s1+s2에서 화살표(→)의 왼편이 메소드의 인수 리스트로 두 개의 문자열로 이루어져 있다. 메소드의 오른편을 보면 이 메소드로 구현하려는 로직을 볼 수 있다.

위의 예는 두 개의 문자열이 주어졌을 때 그 둘을 합치는 것이다. 메소드에 로직을 넣으려면 화살표의 오른쪽에 오면 되는데 앞의 예에서 로직은 두 개의 인수를 더하는 것이다. 오른편에 올 수 있는 것은 문장, 표현식, 코드 블록, 다른 메소드 호출 등이다.

java.util.stream


Java 8은 단순히 람다 표현식을 도입할 뿐 아니라 효과적인 사용 방법을 안내하고 촉진할 수 있도록 기존 API에 람다 표현식을 대폭 적용했다. 그 대표적인 인터페이스가 Stream이다. Stream 인터페이스는 컬랙션(Collection)을 다루는 새로운 방법을 제공한다. 스트림은 컬랙션을 파이프식으로 처리하도록 하면서 고차함수로 그 구조를 추상화한다. 그래서 지연 연산이나 병렬 처리 등이 동일 인터페이스로 제공된다. 좀더 알기쉽게 설명하자면 배열이나 리스트, 맵으로 대표되는 컬랙션을 스트림으로 다룰 수 있게 되었다는 것 이다. 다음은 컬랙션에 대한 스트림화의 예이다.

1
Stream <T> stream = collection.stream ();

이것이 함수형 프로그래밍과 결합하면 다음과 같은 형태가 된다.

1
2
3
   int sumOfWeights = blocks.stream () filter (b -> b.getColor () == RED)
                                  . mapToInt (b -> b.getWeight ())
                                  . sum ();

위의 샘플코드는 stream패키지의 Javadoc에 실린 예로서, stream의 소스로서 blocks라는 Collection을 사용하고 있다. 그 스트림에 대해 filter-map-reduce를 실행하여 붉은색(RED)블록에 대한 무게(weight)의 합(sum)을 구하는 일련의 과정이 한줄의 코드에 집약되어 표현되고 있다.

java.time


새로운 날짜/시간 관련 API가 java.time 패키지에 추가되었다. 과거에 Java에서 날짜/시간 관련해서 Java에서 제공하는 API보다 Joda Time이라는 외부 라이브러리가 더 편리하다는 이야기를 들은 적이 있는데, 아마 이를 개선한 것 같다. 새로운 날짜/시간 클래스는 immutable이며 스레드에 대해 안전하다. 날짜 및 시간 형식으로 Instant, LocalDate, LocalDateTime, ZonedDateTime이 추가되었으며 날짜와 시간 이외의 것으로서 Duration과 Period가 추가되었다. 새로 추가된 값 형식은 Month, DayOfWeek, Year, Month YearMonth, MonthDay, OffsetTime, OffsetDateTime등이 있다. 이런한 새로운 날짜/시간 클래스는 대부분이 JDBC에서 지원됨으로서 RDB연동의 효율적인 구현이 가능하다.

참고 및 인용한 블로그

Java 8 의 모든 기능들은 여기에 정의되어 있다.

This post is licensed under CC BY 4.0 by the author.