본문 바로가기

자바 언어 & 객체지향 지식

자바 스트림 라이브러리에 대하여

출처: https://futurecreator.github.io/2018/08/26/java-8-streams/

스트림의 쓰임 예시: https://coding-factory.tistory.com/574

 

스트림 라이브러리란? 복합타입 자료구조의 집단연산을 내부반복을 통해 계산해 주는 라이브러리로써 자바 8부터 함수형 프로그래밍이 지원되면서부터 함께 제공된 라이브러리다. 즉, 람다표현식과 함께 등장한 라이브러리다.

 

(스트림: 함수형 프로그래밍, 선언적 프로그래밍을 할 수 있게 해주는 라이브러리. 복합타입의 자료구조의 집단연산을 내부반복을 통해 계산해줌.

 ⇒

이에 대한 교수님 설명: 스트림은 주로 집단연산할 때 사용한다는 것입니다. 주로… 중간연산, 최종 연산을 수행하는데, 최종 연산의 기본이 reduce입니다. reduce 대신 collect를 하거나 제시한 것처럼 foreach를 사용하면 집단 연산을 하는 것은 아니지요.)

 

인자로 온 람다표현식은 인터페이스를 구현한 클래스의 객체와 같다. 함수형 인터페이스는 단일 추상 메서드(SAM: Single Abstract Method)를 가지며 함수형 인터페이스 매개변수에 온 함수는 곧 인터페이스를 구현한 객체와 같다. 그래서 이름이 함수형 인터페이스(Functional Interface)인 것이다.

(함수(A)의 인자로 함수(B)가 왔다는 것은 함수(A)의 매개변수의 타입이 함수형 인터페이스라는 것이다.)

 

람다 표현식의 구현: 람다 표현식은 단일메서드를 가진 객체로 변환됨(함수 그 자체가 객체로 변환된다는 것이다. 상당히 혁신적인것).

 

위와 같이 함수를 다른 함수의 인자로 전달할 수 있으면 함수의 기능이 고정되지 않고 전달한 함수에 따라 다양한 기능을 수행할 수 있게됨. 이러한 이유로 함수형 프로그래밍은 범용프로그래밍(하나의 코드로 다수의 코드처리)의 하나가 되는 것.

 

람다 = 익명이라는 뜻임.

클래스에 익명 클래스가 있다면 함수에는 람다 표현식(=익명 함수)이 있음

 람다 표현식=익명 함수(일회성 사용이 목적. 일회적으로 사용할 것이므로 변수에 저장하지 않을 것이고 그렇기 때문에 이름도 없는것. 물론 변수에 저장할 수도 있음. )=함수를 간결하게 정의하는 방법(=함수형 프로그래밍, 선언적 프로그래밍)=함수의 인자로 함수를 전달하고자 할때 사용될 수 있는 수단!

 

스트림 라이브러리와 함수형 프로그래밍이 결합하여 기존의 절차적 지향 프로그래밍이 아닌 선언적 프로그래밍이 가능해 집니다.

 

스트림의 쓰임. 
1. 함수 여러 개를 조합해서 원하는 결과를 필터링하고 가공된 결과를 얻을 수 있음. 또한 람다를 사용하여 코드의 양을 줄이고 간단히 표현할수 있음. 
2. 간단한 병렬처리(multi-threading, parallel processing)가 가능함. 병렬 처리란? 하나의 작업을 둘 이상의 작업으로 잘게 나눠서 동시에 진행하는 것. 

3. 스트림은 배열또는 컬렉션 인스턴스로부터 생성할 수 있음.

 

스트림에 대한 내용은 크게 세 가지:

  1. 생성하기 : 스트림 인스턴스 생성.
  2. 가공하기 : 필터링(filtering) 및 맵핑(mapping) 등 원하는 결과를 만들어가는 중간 작업(intermediate operations).
  3. 결과 만들기 : 최종적으로 결과를 만들어내는 작업(terminal operations)

(Collection 클래스는 기본적으로 저네릭 클래스이므로 reference타입만 구성요소로 들어갈수 있다. 즉, primitive타입을 대상으로 collection클래스를 구성할 수 없으므로 stream라이브러리의 도움을 받아 Wrapper class로 변경(예를들면 boxed메서드)한 후에 collect함수를 사용하여 컬랙션 객체로 바뀔수 있다.)

 

아래는 Collection클래스, stream, (primitive, reference)배열 사이를 왔다갔다 변환연습을 하게 되는데 중요한 것이 stream이라는 것은 항상 colletion클래스와 primitive배열 중간에서 중재자 역할 을 한다는 것이다!!

Collection클래스 <----------------------- stream 라이브러리 ----------------------------------------->primitive배열

 

-Collection클래스를 primitive배열로 바꾸기

int[] primitiveArray=new int[nodeQueue.size()];과 같이 반드시 객체 생성해 주지 않아도 됨

 

-primitive배열을 컬렉션클래스로 바꾸기(primitive와 컬렉션클래스가 나오므로 stream이 사용될 것으로 예측할 수 있음)

//primitive배열을 컬렉션 클래스로 바꾸기

    //Arrays.asList()의 특징
    // - Reference Type(주소값을 가진 타입)만 인자로 받아서 리스트로 반환됨
    //asList는 generic 메서드이기 때문에 reference type 만을 인자로 받는다
    //primitive 배열을 asList로 변환하려고 할 때 배열의 요소가 리스트의 요소로 바뀌어 변환될거라고 착각할 수 있으나,
    //배열도 Reference Type이기 때문에 primitive 배열을 요소로 가지는 리스트가 반환된다
    
    //ex. int[] 을 asList를 이용해서 리스트로 변환하려고 할 때 List<Integer> 가 아닌 List<int[]>이 반환된다
    //int[] intArr = {1,2,3};
    //List<int[]> intArrList = Arrays.asList(intArr);
    //// intArrList.size() = 1
    //// intArrList.get(0) = {int[3]@2579} [1,2,3]
    //List<int[]>list=new LinkedList<>(Arrays.asList(primitiveArray));
}
import java.util.Arrays;
import java.util.List;
 
public class IntArrayConvertToList {
    public static void main(String[] args) {
        
        // int 배열
        int[] arr = { 1, 2, 3 };
 
        // Arrays.asList() 
        List<int[]> intList = Arrays.asList(arr);
 
        // 결과 출력
        System.out.println(intList.size()); // 1
        System.out.println(intList.get(0)); // I@71bb301
        System.out.println(Arrays.toString(intList.get(0)));  // [1, 2, 3]
 
    }
}

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
public class IntArrayConvertToList {
    public static void main(String[] args) {
        
        // int 배열
        int[] arr = { 1, 2, 3 };
 
        // int -> List
        List<Integer> intList 
                = Arrays.stream(arr)
                        .boxed()
                        .collect(Collectors.toList());
        
        // List 출력
        System.out.println(intList.size()); // 3
        System.out.println(intList); // [1, 2, 3]
 
    }
}

 

boxed() 메소드는 Primitive Stream 값들을 Wrapper Class로 바꿈. 그후, collect(Collectors.toList())를 이용하여, 주어진 stream을 List로 변경해 줄 수 있습니다.

 

 

 

 

 

아래와 같이 iteratedStream.forEach(i-> System.out.print(i+" ")); 을 한 후 같은 문장을 또 입력하면 아래와 같은 오류 나옴. 즉, 스트림이라는 것은 일회성! 재사용이 가능하지 않음!