Java 8에서 달라진 것

초콜렛빵·2022년 6월 7일
0

TIL

목록 보기
14/27
post-thumbnail

Java 8

주요 변경 사항

  1. Lambda Expression(람다 표현식)
  2. Functional Interface(함수형 인터페이스)
  3. Default Method(디폴트 메서드)
  4. Stream(스트림)
  5. Optional(옵셔널)
  6. 새롭게 추가된 날짜 API
  7. Completable Future(컴플리터블 퓨처)
  8. JVM의 변화

Lambda Expression(람다 표현식)

  • 메서드로 전달할 수 있는 Anonymous Fucntion(익명 함수)를 단순한 문법으로 표기한 것을 지칭
  • 예시 코드
// 익명 클래스로 Runnalbe을 구현
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Start to new thread!");
    }
});

thread.start();


// 람다 표현식으로 단순하게 표현
Thread thread = new Thread(() -> System.out.println("Start to new thread!"));
        
thread.start();

구성

  • 람다 표현식은 파라미터(), 화살표->, 바디함수로 구성
  1. 하나의 파라미터, 리턴 타입 x
    • 타입은 생략이 가능하며, 문맥에 맞게 알맞은 객체를 컴파일러가 선택
    • 파라미터가 한개인 경우에는 괄호도 생략 가능
    (str) -> System.out.println(str);
    str -> System.out.println(str);
  2. 하나의 파라미터, 리턴 타입 o
    • 바디가 짧아 한줄로 끝나면 중괄호, return 생략 가능
    • 두줄 이상인 경우 명시해야함
    (i) -> i + 10;
     (i) -> {
    	int result = i + 10;
    	return result;
    };
  1. 파라미터 x, 리턴 타입 o

    • 파라미터가 없는 경우 빈괄호를 명시적으로 표기
    () -> Integer.MAX_VALUE;
    

장단점

  • 장점
    1. 코드의 간결성
    2. 지연연산 수행
    3. 병렬처리 가능
  • 단점
    1. 람다식 호출 까다로움
    2. 람다 stream 사용 시 단순 for문, while문 사용시 성능 저하
    3. 가독석이 떨어질 수 있음

Functional Interface(함수형 인터페이스)

  • 단 하나의 추상메서드를 갖는 인터페이스를 함수형 인터페이스라고 지칭
  • Runnable 인터페이스의 경우 run() 하나만 존재하므로 함수형 인터페이스라 할 수 있음
  • 컴파일시점에 확인이 가능하도록 @FunctionalInterface 어노테이션 제공(Java 8 이후)

구현

@FunctionalInterface
public Interface Cat {
	String name(String name);
}
  • 위의 Cat 인터페이스의 경우 @FunctionalInterface 를 이용해 명시한 함수형 인터페이스
  • 어노테이션을 통해 컴파일 시점에 검증 가능
Cat cat = new Cat() {
	@Override
    public String name(String name) {
    	return "고양이의 이름은 " + name + "입니다.";
    }
};
  • 기존에 사용하던 인터페이스 구현 방식
Cat cat = (name) -> "고양이의 이름은 " + name + "입니다.";
System.out.println(cat.name("뚱냥이"));
  • 람다 표현식을 이용해 구현한 함수형 인터페이스
  • 람다 표현식은 사실상 함수형 인터페이스를 구현하기 위해 나타난 것으로 봐도 무방

기본 제공하는 함수형 인터페이스

  1. Fucntions
    • 특정 오브젝트를 받아서, 특정 오브젝트를 리턴하는 메소드 시그니쳐
    • Function<T, R> 의 형태가 기본이며, T는 매개변수 타입, R은 리턴 타입을 지칭
    • compose, andThen, identity 가 구현되어 있음
  2. Suppliers
    • 매개변수를 받지않고, 특정 타입의 결과를 리턴
  3. Consumers
    • 매개변수를 받고 리턴은 하지 않음
    • 전달받은 매개변수를 이용해 처리하는 작업을 진행
  4. Predicates
    • 특정 타입의 매개변수를 전달받아 boolean 값 리턴
  5. Operators
    • 하나의 매개변수를 받고, 동일한 타입을 리턴하는 함수형 인터페이스
    • UnaryOperator, BinaryOperator를 이용해 매개변수 개수 구분

Default method(디폴트 메서드)

  • 인터페이스에서 구현된 메서드를 만들 수 있음
public interface Sample {
	String returnHello(String msg);
    default void hello(String msg) {
    	System.out.println("hello " + msg);
    }
}
  • 장점
    • 코드 호환성 유지하며 새로운 기능추가
    • 불필요한 구현부 제거

Stream(스트림)

  • Collection을 편리하게 처리하는 방법을 제공하는 API
  • 병렬처리를 제공하며, 쿼리와 비슷한 직관적인 코드 제공

예시

  • 요구사항 니체가 작성한 책의 ISBN 정보 필요하며, 정렬은 책이름 기준으로 정렬
  • 스트림 미사용시의 코드
books.sort(Comparator.comapring(Book::getName));

List<String> booksWrittenByNietzsche = new ArrayList<>();
for (Book book: books) {
	if (book.getAuthor().equals("Friedrich Nietzsche")) {
    	booksWrittenByNietzsche.add(book.getIsbn());
    }
}
  • 스트림 기능 사용한 코드
List<String> booksWrittenByNietzsche = 
	books.stream()
    	.fillter(book -> book.getAuthor().equals("Friedrich Nietzsche"))
        .sorted(Comparator.comparing(Book::getName))
        .map(Book::getIsbn)
        .collect(Collectors.toList());
  • for문과 if문이 생략되며 간결해짐

특징

  1. 파이프라이닝 지원
    • 메서드 체이닝이 연결됨
    • 연속으로 처리하며 파이프라인이 되어 최종 결과물 반환
  2. 내부 반복 지원
    • 코드 외부에서 for문 사용하지 않고 filter()처럼 내부에서 처리
    • 비즈니스 로직 구현에만 충실한 코드 가능
  3. 1회 탐색
    • 스트림 기능 사용시 이전으로 복귀 불가능
    • 연산 이전의 값은 저장되지 않으며 새로운 값으로 반환
    • 재사용시 변수에 저장해야함
  4. lazy
    • 필요한 시점에 동작하는 방식
    • 중간연산이 복잡해도 종료연산이 없으면 실행되지 않음
  5. 중간 연산과 종료 연산으로 구분
    • Stream<T> 형태로 스트림 반환되면 중간연산, 그렇지 않으면 종료 연산
    • filter(), sorted()는 모두 중간연산

Optional(옵셔널)

  • null의 문제점을 보완하고자 등장
  • Integer나 Double같은 Wrapper class로서 객체호출하는 것이 아닌 Optional 안에서 null 발생을 방지

예시

  1. 기존의 null 처리
public class BookService {
	public String getAuthorName(Book book) {
    	if(book == null) {
        	throw new NullPointerException("this book is null");
        }
        
        Author author = book.getAuthor();
        if (author == null) {
    		throw new NullPointerException("This author is null");
		}
        String authorName = bookService.getAuthorName(book);

        if (authorName == null) {
            throw new NullPointerException("This author name is null");
        }
    }
}
  • null에 대한 조건을 3번에 걸쳐 확인을 해야함
  1. Optional을 활용한 null 처리
public class BookService {
	public Optional<String> getAuthorName(Book book) {
    	return Optional.ofNullable(book)
        	.map(bookObject -> bookObject.getAuthor())
            .map(authorObject -> authorObject.getName());
    }
}
  • 방어적인 코드를 추가하지 않고 Optional<String>을 명시함으로써 빈 결과값이 반환될 수 있음을 인지
  • 간결하게 해당 코드에 대한 이해 가능

새롭게 추가된 날짜 API

  • Date, Calendar 외에 날짜 API가 추가
  • Instant, LocalDate, LocalTime, LocalDateTime이 추가 됨
  • Duration, Period와 같은 날짜와 시간 간격 클래스, DateTimeFormatter와 같은 날짜 포맷 표현하기 위한 클래스도 추가

CompletableFuture(컴플리터블 퓨처)

  • Java의 비동기 프로그래밍의 불편함을 해소하기 위해 추가됨
  • Future를 사용해 Thread를 사용하면 Thread pool 지정, Timeout 설정 등 직관적인 사용이 가능
  • 이를 Java8부터는 CompletableFuture를 이용해 조회가 가능
  • 비동기로 진행하고, 정상 처리 후 자연스럽게 호출하거나, 예외사항 처리도 가능

JVM 변환

  • PermGen이 사라지고 Metaspace영역 생성
  • 실무 영역에서는 -XX:PermSize, -XX:MaxPermSize 삭제 후 XX:MetaspaceSize, -XX:MaxMetaspzceSize 옵션이 추가

변경 사항

  • PermGen은 메타 정보를 관리하는 메모리 공간으로 Heap메모리에 포함됨
  • 이로 해당 정보에 대한 크기 제한
  • 이에 대해 Java8에서는 Metaspace가 생기며 Native영역으로 이동
  • OS가 해당 크기를 자동으로 조정
  • 이를 통해 OOM 발생 여지가 줄어듦

참조
Java8 변경점: https://bbubbush.tistory.com/23
Functional Interface 기본함수: https://futurecreator.github.io/2018/08/02/java-jdk-functional-interfaces-api/

profile
차근차근 기록하고 배우는 개발자

0개의 댓글