자바의 정석 Chapter 14 람다와 스트림

Eunkyung·2021년 11월 17일
0

Java

목록 보기
15/21

1. 람다식

JDK1.8부터 람다식이 도입된 후 자바는 객체지향언어인 동시에 함수형 언어가 되었다.
람다식은 메소드의 이름과 반환값을 생략한 것으로 익명함수라고도 한다.

굳이 메소드 대신 람다식을 쓰는 이유는 뭘까?
메소드는 반드시 클래스 내에 포함되어 있어 객체 생성 후 메소드를 호출할 수 있다. 그러나 람다식은 이러한 과정없이 메소드의 역할을 대신할 수 있기 때문이다.

1.1 람다식 작성하기

메소드에서 이름과 반환타입을 제거하고 매개변수 선언부와 몸통 {} 사이에 ->를 추가한다.

반환타입 메소드이름 (매개변수 선언) -> { 문장들 }

메소드 -> 람다식으로 변환
int max (int a, int b) {
	return a > b ? a : b;
}
(a, b) -> a > b ? a : b;

선언된 매개변수의 타입이 추론 가능한 경우 생략 가능하여 이처럼 간단하게 표현할 수 있다.

1.2 함수형 인터페이스

함수형 인터페이스@FunctionalInterface는 람다식을 다루기 위한 인터페이스로 단 하나의 추상 메소드만 정의되어야 한다.

1.3 java.util.function 패키지

java.util.function 패키지에 일반적으로 자주 쓰이는 형식의 메소드를 함수형 인터페이스로 미리 정의해 놓았다.

함수형 인터페이스메소드설명
java.lang.Runnablevoid run()매개변수도 없고, 반환값도 없음
Supplier<T>T get()매개변수는 없고, 반환값만 있음
Consumer<T>void accept(T t)Supplier와 반대로 매개변수만 있고, 반환값이 없음
Function<T, R>R apply(T t)하나의 매개변수를 받아서 결과 반환
Predicate<T>boolean test(T t)조건식을 표현하는데 사용

1.4 메소드 참조

람다식이 하나의 메소드만 호출하는 경우 클래스 이름::메소드 또는 참조변수::메소드이름으로 바꿀 수 있다.

람다식 -> 메소드 참조
Function<String, Integer> f = (String s) -> Integer.parseInt(s);
Function<String, Integer> f = Integer::parseInt;

2. 스트림

스트림은 데이터 소스를 추상화하고, 자주 사용되는 메소드들을 정의해 놓았다. 그 결과 데이터 소스에 상관없이 같은 방식으로 다룰 수 있게 되었으며 코드의 재사용성이 높아졌다. 스트림을 이용하면 배열이나 컬렉션뿐만 아니라 파일에 저장된 데이터도 모두 같은 방식으로 다룰 수 있다.
이전에 배웠던 배열이나 컬렉션 프레임워크의 경우 List 정렬 시 Collections.sort()를 사용하고 배열 정렬 시 Arrays.sort()를 사용하는 번거로움이 있었는데 스트림은 이러한 문제점을 해결하였다.

배열과 리스트
String[] strArr = {"aaa", "bbb", "ccc"};
List<String> strList = Arrays.asList(strArr);
Arrays.sort(strArr);
Collections.sort(strList);
for (String str : strArr) {
	System.out.println(str);
}
for (String str : strList) {
	System.out.println(str);
}
스트림
String[] strArr = {"aaa", "bbb", "ccc"};
List<String> strList = Arrays.asList(strArr);
// 스트림 생성
Stream<String> strStream1 = strList.stream();
Stream<String> strStream2 = Arrays.stream(strArr);
strStream1.sorted().forEach(System.out::println);
strStream2.sorted().forEach(System.out::println);

둘 다 데이터를 정렬하고 출력하는 코드인데 스트림을 이용할 경우 훨씬 코드가 간결한 것을 확인할 수 있다.

  • 스트림의 특징
    • 스트림은 데이터 소스를 변경하지 않는다. (only read)

    • 스트림은 일회용이다. (Iterator와 비슷)

    • 스트림은 작업을 내부 반복으로 처리한다.

    • 스트림이 제공하는 다양한 연산을 이용해서 복잡한 작업들을 간단히 처리할 수 있는데 중간 연산과 최종 연산으로 분류할 수 있다.

      • 중간 연산 : 연산결과를 스트림으로 반환하기 때문에 중간 연산을 연속해서 연결할 수 있다.
      • 최종 연산 : 스트림의 요소를 소모하면서 연산을 수행하므로 단 한번만 연산이 가능하다.

      stream.distinct().limit(5).sorted().forEach(System.out::println)

    • 스트림은 최종 연산이 수행되기 전까지 중간 연산이 수행되지 않는다.

    • 병렬 스트림은 자동적으로 연산을 병렬로 수행한다.

출처

  • 자바의 정석 - 남궁성 지음
profile
꾸준히 하자

0개의 댓글