본문 바로가기
  • 기업가 장준영
Java_2

Java 7_1

by 장준영 2020. 6. 10.

 

 

Java 7

 

많은 변화가 있다

 

이 변화에 대해 정리가 되어있는 문서는 "JSR 336"

JSR는 Java Specification Requirement

앞으로 자바에서 사용할 기술들을 나열한 문서라고 보면 된다

구글에서 JSR 336으로 검색하면 관련 자료를 다운로드 할 수 있다

 

 

 

Java 7의 변화는 변경된 부분과 추가된 부분으로 나누어 볼 수 있다

 

변경된 사항들부터 살펴보자, 대표적인 변경 사항들은 다음과 같다

  • 숫자 표시 방법 보완
  • switch 문에서 String 사용
  • 제네릭을 쉽게 사용할 수 있는 Diamond
  • 에외 처리시 다중 처리 가능

 

 

 

 

 

달라진 숫자 표현법

 

숫자를 표현할 때 아무런 접두사를 숫자 앞에 넣지 않으면 10진수로 인식한다

0을 숫자 앞에 넣어주면 8진수, 0x를 숫자 앞에 넣어주면 16진수로 인식한다

 

Java 7부터는 2진수 표현이 추가되었다

2진수로 나타내기 위해서는 0b를 숫자 앞에 추가해 주면 된다

 

여기서 끝이 아니다

돈 단위나 숫자 단위를 표시할 때에 1000단위에 쉼표를 붙인다

백만의 경우는 1,000,000과 같이 표시를 한다

지금까지 코딩할 때 자바에서는 눈이 빠지게 0의 개수를 따져서 제대로 개발자가 입력했는지를 확인해야만 했다

하지만 이제는 _ 를 사용할 수 있다

_를 붙이면 훨씬 가독성이 좋아진다

이 _를 사용할 때에 유의해야하는 것이 있는데

_의 위치이다 _를 사용할 때에는 반드시 "숫자 사이에만" 넣어주어야 한다

 

 

 

 

 

 

 

 

 

switch 문장도 확장되었다

 

Java 6까지는 switch - case 문장에 정수형만 사용할 수 있었다

 

Java 7부터는 switch 문장에 String도 사용할 수 있다

 

 

지금까지는 이렇게 숫자로만 switch - case 문을 사용할 수 있었다

보통은 이렇게 숫자를 지정하는 것보다는 상수를 선언하여 사용하거나 enum을 사용한다

 

하지만 Java 7부터는 이러한 작업을 String을 switch - case에 사용함으로써 매우 간편해졌다

switch - case에서 String 문자열을 바로 사용할 수 있기 때문에 보다 편리해졌다

 

한 가지 유의할 점은 switch - case에 사용하는 String이 null일 경우

NullpointerException이 발생하니 switch - case에서 사용하는 문자열이 null인지

null 체크를 꼭 해야한다

 

 

 

 

 

 

 

제네릭은 다이아몬드를 쓰면 편하다

 

제네릭을 사용할 때 다음과 같이 생성자에도 해당 타입들을 상세하게 명시했어야했다

HashMap<String, Integer> map = new HashMap<String,Integer>();

Map<String, List<String>> map2 = new HashMap<String, List<String>>();

 

하지만 Java 7부터는 이와 같이 생기는 생성자에는 일일이 타입들을 명시해 줄 필요가 없다

HashMap<String, Integer> map = new HashMap<>();

Map<String, List<String>> map2 = new HashMap<>();

 

<>로 표시한 것을 다이아몬드라 명명하며

이렇게 다이아몬드를 사용하면 컴파일러에서 알아서 해당 생성자의 타입을 지정해버린다

 

다이아몬드는 편한 만큼 제약이 따르며, 다음과 같은 제약들이 있다

  • 다이아몬드 미 지정시 컴파일 경고 발생
  • 다이아몬드 생성시 유의 사항 1 - 메소드 내에서 객체 생성시
  • 다이아몬드 생성시 유의 사항 2 - 제네릭하면서도 제네릭하지 않은 객체 생성시

 

다이아몬드 생성시 유의 사항  - 제네릭하면서도 제네릭하지 않은 객체 생성시

 

다음과 같은 제네릭 클래스가 있다

 

이 클래스의 객체를 생성하는 다음의 클래스를 살펴보자

결과는 다음과 같다

T type = java.lang.String

X type = java.lang.Integer

 

선언한 대로 타입들이 지정된 것을 볼 수 있다

 

다음을 보자

이번에는 생성자에 다이아몬드가 없다

컴파일시 경고가 발생하긴 하지만, 실행하는 데는 큰 문제가 없다

 

이번에는 다이아몬드를 안 쓰고 명시적으로 지정할 때를 살펴보자

컴파일 실행 모두 잘 된다

 

마지막으로 다음과 같이 X타입을 다이아몬드로 선언해보자

 

그냥 보기에는 아무런 이상 없이 컴파일이 될 것 같지만, 실제로는 컴파일러가 혼동을 일으키게 된다

 

이렇게 타입 T에 대해서 선언한 상태에서 타입 X에 대해서는 다이아몬드로 선언하여 컴파일러에게 맡겨 버리면

컴파일이 정상적으로 되지않는다

 

생성자에 있는 new와 클래스 이름 사이에 타입 이름을 명시적으로 두려면, 다이아 몬드를 사용하면 안 된다라는것을 기억해두자 

 

 

 

 

 

 

 

Non reifiable varargs 타입

 

제네릭을 사용하면서 발생 가능한 문제 중 하나가

 

non reifiable varargs type이다

이 문제는 자바에서 제네릭을 사용하지 않는 버전과의 호환성을 위해서 제공했던 기능 때문에 발생한다

 

reifiable은 실행시에도 타입 정보가 남아있는 타입을 의미하고, non reifiable은 컴파일시 타입 정보가 손실되는 타입을 말한다. 참고로 이 단어는 사전에 없다

 

Collection 클래스에 addAll() 메소드가 다음과 같이 선언되어 있다

public staitc <T> boolean addAll(Collection<? super T> c, T ... elements)

 

이 메소드를 활용하는 다음과 같은 예제가 있다

 

addData() 메소드를 살펴보자

 

그냥 보기에는 큰 문제는 없어 보인다

하지만 Java 6에서 컴파일하면 경고가 나타난다

 

안전하지 못하다는 경고와 함께 옵션을 추가해서 다시 컴파일해서 보라는 메시지가 나타난다

옵션을 추가해서 다시 컴파일해보면

 

Collection 의 addAll() 메소드에서 뭔가 위험하다는 메시지가 나타났다

경고는 있지만 컴파일하고 실행해 봐도 큰 문제는 없다

 

왜 이러한 경고가 나타나는 것일까?

 

실제 API에 있는 addAll() 메소드의 선언을 다시보자

public staitc <T> boolean addAll(Collection<? super T> c, T ... elements)

 

여러분들이 가변 매개 변수를 사용할 경우 실제로 내부적으로는 다음과 같이 Object의 배열로 처리된다

public staitc <T> boolean addAll(Collection<? super T> c, java.lang.Object[] elements)

 

이렇게 Object의 배열로 처리되면, 큰 문제는 발생하지는 않지만 잠재적으로 문제가 발생할 수도 있다

따라서 이러한 경고를 없애기 위해서는 @SafeVarargs라는 어노테이션을 메소드 선언부에 추가하면 된다

 

이 Collection 클래스의 addAll() 메소드에도 Java 7부터는 이 어노테이션이 추가되어 있다

해당 어노테이션은 다음의 경우에만 사용 가능하다

  • 가변 매개 변수를 사용하고
  • final이나 static으로 선언되어 있어야 된다

그리고, 해당 어노테이션은

  • 가변 매개 변수가 reifialbe 타입이고
  • 메소드 내에서 매개 변수를 다른 변수에 대입하는 작업을 하는 경우

에는 컴파일러에서 경고가 발생하게 된다

 

 

 

 

 

 

 

예외도 보완 되었다

 

Java 7의 변경 사항에 대한 마지막 예외에 대해 살펴보자

 

지금까지는 예외를 처리하기 위해 여러 개의 catch로 잡아주는 코드의 가독성이 떨어지는 작업을 많이 했다

 

다음과 같은 try - catch가 있다고 생각해보자

 

Scanner 클래스의 생성자에 대해 살펴보면 

첫 번째 매개 변수는 읽을 파일 이름이고

두 번째 매개 변수는 파일의 인코딩 타입이다

이 경우에 인코딩 타입이 존재하지 않을 경우 IllegalArgumentException

파일이 존재하지 않을 경우 FileNotFoundExcepiton

파일 명이나 인코딩 타입이 null일 경우 NullPointerException이 발생한다

 

그래서 이 부분을 처리할 때 일일이 각각의 catch 블록을 만들어서 처리하거나

Exception 클래스하나로 catch를 해 줬었다

 

Java 7부터는 위처럼 catch 블록에서 처리하는 방식이 동일하다면 다음과 같이 간단하게 처리할 수가 있다

 

Exception을 조건식에서 or을 나타내는 파이프로 연결하여 이처럼 간단히 처리해 버릴 수도 있다

 

 

 

추가된 것이 하나 더 있다 "리소스와 함께 처리하는 try문장"인데

 

try - with - resource라고 이야기한다

 

Java 7에서는 AutoCloseable이라는 인터페이스가 추가되었다try - with - resource를 사용할 때에

이 인터페이스를 구현한 클래스는 별도로 close()를 호출해 줄 필요가 없다

 

즉, finally 문장에서 close()를 처리하기 위해서 코드의 가독성을 떨어지게 할 필요는 없다는 것이다

앞서 사용한 예제는 다음과 같이 보다 더 간단하게 처리할 수 있다

 

AutoCloseable 을 implements하고 close할 객체를 try앞의 괄호안에 생성하면 자동으로 close()해준다

 

만약 try의 소괄호 내에서 두 개의 객체를 생성할 필요가 있을 때에는 당황할 필요 없이 ";" 세미콜론으로 구분하여 두 객체를 생성해 주면 된다

 

 

 

 

 

 

Java 7부터는 꼭 안 닫아도 되는 애들이 있다

 

Java 5부터 추가된 java.io.Closeable이라는 인터페이스가 있다

 

이 인터페이스를 구현한 클래스들은 명시적으로 close() 메소드를 사용하여 닫아주어야만 했었다

 

Java 7부터는 해당 인터페이스는 다음과 같이 선언되어 있다

public interface Closeable extends AutoCloseable

 

AutoCloseable이라는 인터페이스를 상속받은 것을 볼 수 있으며

이 인터페이스를 구현한 클래스는 앞 절에서 살펴본 try - with - resource 문장에서 사용할 수 있다

 

AutoCloseable

관련된 클래스를 살펴보려면 java.lang 패키지에 선언된 AutoCloseable 인터페이스의 API를 확인해 보기 바란다

 

 

'Java_2' 카테고리의 다른 글

Java 8_1  (0) 2020.06.22
Java 7_2  (0) 2020.06.17
Java_2_7  (0) 2020.06.02
Java_2_6  (0) 2020.05.28
Java_2_5  (0) 2020.05.26

댓글