[Java 기초] lambda와 Stream

이진영·2023년 5월 27일
0

JAVA 기초

목록 보기
2/9

오늘은 간단하게 Java개발자라면 많이 쓰고, 유용한 Labda Expression와 Stream에 대해서 알아볼려고 한다.

람다 표현식(Lambda Expression)

메서드를 하나의 식으로 표현한 것이라고 볼 수 있다.

이정도의 말로도 이해가 가능이야 하지만 좀 더 명확하게 코드를 통해서 이해를 해보자

int min(int x, int y) {

    return x < y ? x : y;

}

위 코드를 일반적으로 java라는 언어를 통해서 하나의 메소드를 만들어 보고 이러한 부분을 람다 표현식으로 바꾸면 아래와 같은 코드가 완성이 된다.

(x, y) -> x < y ? x : y;

이렇게 하나의 메소드를 람다 표현식을 통해서 코드를 간결하고 명확하게 만들 수가 있다.

이러한 형태는 매개 변수를 가진 코드블록과 같다. 이러한 코드블록은 런타임 시에 객체 생성과 메소드를 생성하는 형태라고 볼 수 있는데 이러한 형태의 클래스를 익명 클래스라고 볼 수 있다.

또한 이러한 메소드의 표현식은 결과값으로 반환이 가능할 뿐더러 이러한 표현식은 기존 불필요한 코드를 줄여주고, 작성된 코드의 가독성을 높여줍니다.

표현식은 어떻게 작성?

(타입 매개변수) -> { 실행문; ... }

위에서 간단하게 보셨겠지만 다시 한번 짚고 세세하게 알아볼려고 한다.

그렇다면 유의해야 할 사항은 무엇이 있을까?

  1. 매개변수 타입을 추론할 수 있는 경우에는 생략할 수 있다.
  2. 매개변수가 하나인 경우에는 괄호(())를 생략할 수 있다.
  3. 함수 몸체가 하나의 명령문으로 이루어진 경우 중괄호({})를 생략이 가능하며 이때는 세미콜론을 붙이지 않아도 된다.
  4. 함수의 몸체가 하나의 return문으로만 이루어진 경우네는 중괄호({})를 생랼할 수 없다.
  5. return문 대신 표현식을 사용할 수 있으며, 이때 반환값은 표현식의 결과값이 됩니다.

함수형 인터페이스

또한 이러한 람다 표현식을 사용할 때는 편하게 저장해서 사용하는 인터페이스 함수형 인터페이스를 제공합니다.

@FunctionalInterface
interface Calc { // 함수형 인터페이스의 선언

    public int min(int x, int y);

}

하지만 여기서 함수현 인터페이스를 제공할 때는 하나의 추상메소드만 가능합니다.

만약 두 개이상의 추상메소드가 선언이 될 때는 컴파일러에서 오류를 반환합니다.

또한 자바는 java.util.function 패키지를 통해 여러 상활에서 사용할 수 있는 다양한 함수형 인터페이스를 미리 정의하여 제공하고 있습니다.

스트림(Stream)이란?

여러 종류의 데이터를 다양한 방식으로 다룰 수 있도록 제공하는 표준화된 방법

  1. 스트림은 외부 반복을 통해 작업하는 컬렉션과는 달리 내부 반복(internal iteration)을 통해 작업을 수행합니다.
  2. 스트림은 재사용이 가능한 컬렉션과는 달리 단 한 번만 사용할 수 있습니다.
  3. 스트림은 원본 데이터를 변경하지 않습니다.
  4. 스트림의 연산은 필터-맵(filter-map) 기반의 API를 사용하여 지연(lazy) 연산을 통해 성능을 최적화합니다.
  5. 스트림은 parallelStream() 메소드를 통한 손쉬운 병렬 처리를 지원합니다.

스트림 API의 동작 흐름

스트림 API에서는 3가지의 단계를 걸쳐서 동작합니다.

먼저 첫 번째로 데이터 소스를 생성 부분에서는 다양한 데이터 타입을 허용하고 있다.

  • array
  • list
  • file
  • random
  • etc.

두 번째로는 중개연산이라는 구간을 연산하게 된다.
여기서 중개 연산을 통해 또 다른 스트림으로 변환하게 되는데 이러한 중개 연산은 스트림을 전달받아 스트림으로 반환하므로, 중개 연산은 연속으로 연결해서 사용할 수 있습니다.

또한 스트림의 중개 연산은 필터-맵 기밴의 API를 사용함으로 지연연산을 통해 성능을 최적화할 수 있습니다.

filter 연산자

  • 스트림 필터링 : filter(), distinct()
  • 스트림 제한 : limit(), skip()

map 연산자

  • 스트림 변환 : map(), flatMap()
  • 스트림 정렬 : sorted()
  • 스트림 연산 결과 확인 : peek()

세 번째로는 최종 연산
중개 연산을 통해 변환된 스트림은 마지막으로 최종 연산을 통해 각 요소를 소모하여 결과를 표시합니다.

최종 연산 메소드

  • 요소의 출력 : forEach()
  • 요소의 소모 : reduce()
  • 요소의 검색 : findFirst(), findAny()
  • 요소의 검사 : anyMatch(), allMatch(), noneMatch()
  • 요소의 통계 : count(), min(), max()
  • 요소의 연산 : sum(), average()
  • 요소의 수집 : collect()

오늘은 이렇게 알아 보았는데 Java에서는 정말 유요한 기능들을 많이 구성하고 있구나라는 인지하게 됐고 기존에 Stream API를 사용함에 있어서 중개 연산, 최종 연산 구간이 있다는 부분을 모르고 사용했었는데 이제는 알고 쓸 수 있도록 노력해야 할 부분이 있다고 생각이든다. 물론 이러한 람다어느정도 정리가 됐지만 Stream에서는 글에대한 정리가 부족하다고 생각이 든다. 이러한 부분은 추후에 정리를 해나가서 내 것으로 만들필요가 반드시 있다. 그럼 20000 ^^

http://www.tcpschool.com/java/java_lambda_concept
http://www.tcpschool.com/java/java_stream_creation

profile
내가 공부한 것들을 적는 공간

0개의 댓글