콘텐츠로 이동

2021 04 22 Java8

2021-04-21 Java 8 문법

Stream API

  • Stream API가 뭔가요? - 컬렉션, 배열등의 저장요소를 함수형 인터페이스를 적용함으로써 반복적으로 처리할 수 있는 기능 - Collection 클래스에 Stream()이 정의되어 있어, List와 Set에서 사용이 가능합니다. - 배열에는 정적 메서드로 정의되어 있어, 사용이 가능합니다.
  • Stream의 특징에 대해 알려주세요 1. 선언형: 더 간결하고, 가독성이 좋아진다. - 함수형 프로그래밍을 지원하여, 기존의 코드를 어떻게 제어하는지에서, 무엇을 하는지로 시선을 옮길 수 있어요. 2. 조립할 수 있다: 유연성이 좋아져요. - 스트림 API는 여러가지 중간연산/최종연산을 지원해요. - 지원하는 연산들을 조합해, 원하는 대로 데이터를 가공할 수 있어요. 3. 병렬화: 성능의 향상 - 스트림은 병렬화를 손쉽게 적용할 수 있다고 해요. - 아직 병렬 스트림은 사용해 본적이 없지만, 그렇다고 해요. - 아마 함수형 프로그래밍이 side effect가 적기 때문이라고 생각해요. - 처리하려는 값을 외부에서 바꾸지못하고, 내부 반복이 되기 떄문에, 개발자의 의도와 다르게 코드가 동작하는 것을 방지할 수 있어요. - 함수를 여러개를 조합해 원하는 결과를 필터링 하고, 가공된 결과를 얻을 수 있습니다. - 이과정에서 람다를 통해 코드의 양을 줄이고 간결하게 표현이 가능합니다. - 또한 간단하게 병렬처리를 도입할 수 있어, 병렬처리를 통한 빠른 처리가 가능해집니다. - 스트림 인스턴스 생성하기 -> 가공하기(중간연산) -> 최종 결과 만들기(최종연산) 총 3단계로 나뉘는데요 4. 스트림은 지연된 연산이 특징으로, 최종연산이 수행되어야 비로소 스트림의 요소들이 최종 연산에서 소모됩니다.
  • 지연된 연산이 뭐죠? - 참고: https://dororongju.tistory.com/137 - "불필요한 연산을 피하기 위해 연산을 지연"시키는 행태를 말합니다. - 당장 해결해야할 문제들이 차례로 주어지더라도, 마지막 문제를 제공받을 때까지 기다리다가, 마지막 문제를 알게되면 그때 연산을 시작한다. - 예를 들면, 1~10까지의 번호중, filter(i -> i<6).filter(i -> i%2==0).map(i -> i*10).findFirst(); - Eager Evaluation을 한다면, 10개의 원소 돌아서 6보다 작은거 추출, - 추출된 1~5 중에 짝수 추출 - 2, 4를 10을 곱하여 20, 40 만들고 - 앞대가리 20 반환 - Lazy Evaluation을 한다면... - 1 => 6보다 작네? - 1 => 짝수 아니네 => 기각 - 2 => 6보다 작네? - 2 => 짝수네? - 2 => 20댔다 - 20 반환 - 특히 findFirst, findAny등의 연산을 통해 나머지 연산을 피할 수 있음
  • Stream의 forEach와 for-loop을 비교해주세요 - 자바의 Stream은 컬렉션 등의 요소를 하나씩 참조해 함수형 인터페이스를 통한 반복적인 작업의 처리를 가능하게 해줍니다. - 우선 Stream의 forEach는 최종연산 입니다. - 최종연산의 경우 스트림의 종료를 위한 연산을 해주는 곳입니다. - 가령, 출력을 해준다던지, 새로운 Collection으로 변환을 해준다던지의 역할을 하게됩니다. - 로직이 들어간다면, 이는 중간 연산에서 해줄 것이지, 최종에서 할 일은 아닙니다. - Stream.forEach의 경우, 기존의 for-loop에 비해 오버헤드가 크게 발생합니다. - 스트림 객체를 생성하고, 복사하고, 순회하는데 걸리는 시간이 발생하기 떄문입니다.
  • 외부 이터레이터 VS 내부 이터레이터 - 외부 이터레이터: 사용자가 직접 요소를 반복 - 내부 이터레이터: 반복을 알아서 스트림에서 처리
  • Stream을 왜 썼나요?
  • Stream을 쓰면 가독성이 올라가나요? - 음... 저는 케바케라고 봅니다. - for문을 직관적으로 봤을 때 편했던 코드들도 분명히 있었습니다. - 스트림을 사용해서 "How"보다 "What"을 하는지에 초점을 맞춘다고들 많이 합니다. - 근데 무엇을 하는 코드인지, 오히려 어떻게 함으로써 더 쉽게 보이는 코드들이 있었습니다. - 가령 체스미션에서 체스보드 초기화할때 a1, a2, a3 등의 문자열을 캐싱해두고싶었는데, 해당 문자열을 만드는 것은 2중 포문으로 돌리는 것이 훨씬 직관적입니다. - 다만 for문 안에, 조건이 달리고, 그안에 또다른 조건이 달리는 형식의 데이터 처리에는 스트림의 filter 기능을 통해 구현하는 것이 유리하다고 생각합니다.

Stream.forEach vs Collection.forEach

  • Stream.forEach와 Collection.forEach를 비교해주세요 - Collection.forEach 같은 경우, Collection 인터페이스에서 제공하는 메서드입니다. - Iterable 인터페이스를 상속받아 구현됩니다. - Collection의 forEach 같은 경우, synchronized 예약어가 붙어있습니다. 이는 멀티쓰레드 환경에서 안전성을 보장합니다. - Stream.forEach 같은 경우, Collection 인터페이스에서 stream() 객체를 생성한 뒤 호출하게 됩니다. - 사실 단순히 반복이 목적이라면, Collection의 forEach를 사용하는 것이 더 좋습니다. - Stream 객체를 생성하는 것도 비용이기 때문에, 단순 반복을 위한 것이라면 Collection의 forEach 사용이 성능에 더 좋습니다. - 대신 filter, map등의 중간연산들과 버무려서 Stream의 최종연산인 forEach를 사용할 경우, 도입을 고려해보는 것이 좋습니다. - 또한, Stream은 parellelStream()을 사용한 병렬처리가 가능하기에, 이를 사용하는 경우, 도입을 고려해보는 것도 좋습니다.

함수형 인터페이스

  • 일급 객체란? - 일급 객체란, "일반적으로 적용 가능한 연산을 모두 지원하는 객체"를 가르킵니다. - 보통 함수에 매개변수로 넘기기, 리턴값으로 받기, 변수에 할당하기등의 연산을 지원할 때 일급 객체라고 지칭합니다.
  • 함수형 인터페이스란? - 함수형 인터페이스는 "구현해야할 추상 메서드가 하나만 정의된 인터페이스"를 뜻합니다. - 하나의 행위 역시 값으로 할당하고, 넘겨주고, 리턴받을 수 있게 되었다. - 행위에 해당하는 부분도 값으로 취급이 가능해짐 - 코드의 재활용단위가 클래스였던것이 함수단위가 되었음을 뜻함
  • 람다식이란? - 메서드를 하나의 '식'으로 표현한 것으로, 람다식 자체 만으로 메서드의 역할을 대체 - ex. () -> 32; - 하나의 메서드가 선언된 인터페이스를 정의하여 람다식을 다룸 - 이는 함수형 인터페이스라고 합니다.
  • 함수형 프로그래밍? - 기존의 작업을 어떻게 수행할 것인지(HOW)에서, 무엇(WHAT)을 수행하는지에 집중하게 만들었어요. - 대입을 하는 방법이 제공되지 않아, 변수에 값이 할당되면 바꾸지 못하고, 그에따라 side effect를 최소화 한다고 들었어요.
  • 장단점? 왜쓰는지? - 장점 - side effect를 최소화 한다는 것은, 개발자의 의도대로 코드가 잘 작동한다는 뜻인데요. - 이러한 강점은 특히 멀티코어 환경에서 부각됩니다.