본문 바로가기

Language/Java

[JAVA] Stream

1. Stream 이란?

(0) 뜻 

배열이나 컬렉션 프레임워크 안에 저장된 요소들을 하나씩 순회 하면서 코드를 실행할 수 있는 기능을 말함.

내부에 반복자가 따로 존재함.

 

Java 8부터 추가 되었고, 그 이전 시절에는 배열이나 컬렉션에 대한 순회 연산을 할 때는 for, foreach를 써야 하거나 Iterator 써야해서 코드 수가 많아지고 지저분 했음. 하지만 Stream 덕에 코드가 간편해지고 가독성이 좋아짐.

(1) 생성

 

a. 기본 자료형 배열에 대한 Stream 생성

**참고: 배열(a,b)는 배열에 대한 다양한 매소드가 저장되어 있는 Arrays 클래스를 이용하여 Stream 작성 

// int 배열 생성
int[] scores = {100, 95,90,85,80};

// Arrays.stream(배열이름)을 통해 int 배열에 대한 스트림을 생성함. 
// Arrays.stream 안에도 똑같이 100~80까지의 값이 들어 있음.
//이를 이용하기 위해 Stream 객체에 집어 넣음. 기본 자료형은 기본 자료형 별로 Stream 클래스가 존재
// ex) IntStream, DoubleStream ... 
IntStream scoreStream = Arrays.stream(scores);


// 스트림 안에 배열의 부분만 넣을 수 있음
// Arrays.stream(배열이름, 시작부분 index, 끝부분 index)
// 시작 부분은 스트림에 들어가나 끝 부분은 포함 되지 않음!

int[] num = {1,2,3,4,5};
Intstream numStream = Arrays.stream(num,1,3);
//numStream = {2,3}; 과 같은 말

b. 참조 자료형 배열에 대한 Stream 생성

// 참조 변수 자료형인 배열은 재네릭 클래스로 이루어진 스트림 클래스 이용하여 객체 생성 후 거기다  스트림 값 넣음.  
String[] langs = {"python", "java", "javascript","c","c++","c#"};
Stream<String> langStream = Arrays.stream(langs);

// 스트림 안에 배열의 부분만 넣을 경우
Stream<String> langStream = Arrays.stream(langs, 1, 3);
// langStream = {"java", "javascript"}; 랑 같은 말

c. 컬렉션 프레임워크에 대한 Stream 생성 

**참고: 컬렉션 프레임워크 클래스는 stream()라는 스트림 만드는 매소드를 가지고 있음.

// ArrayList 생성 
List<String> langList = new ArrayList<>();

langList.add("python");
langList.add("java");
langList.add("javascript");
langList.add("c");
langList.add("c++");
langList.add("c#");

// 스트림 생성해서, 스트림 객체에 넣기
Stream<String> langListStream = langList.stream();

d. 배열, 프레임워크 없이 직통으로 스트림 생성

//컬렉션 프레임워크, 배열 없이 직통으로 개설하는 법
//Stream.of (넣을 요소들 나열...)
Stream<String> LangListOfStream = Stream.of("python", "java", "javascript", "c", "c++", "c#");

2. Stream API 사용법

(1) 형태

// 스트림_생성.중개_연산()...종료_연산();
// 스트림_생성 형태는 배열, 컬렉션 프레임 워크 마다 나타내는 방식이 상이할 수 있음.

(2) 특징

a. 전체 특징

스트림은 중개 연산, 종료 연산을 통해 필터링 하게 되면 안의 데이터를 소진하기 때문에 재사용할 수가 없다. 

(따라서 같은 배열에 대한 다른 연산을 할 경우, 스트림을 한번 더 만들어서 수행 해야 한다.)

b. 중개 연산

ㄱ. 하나의 스트림에 대해 여러 개를 쓸 수 있다.

ㄴ. 종료 연산으로 끝맺음을 하지 않으면 작동하지 않는다.

ㄷ. 중개 연산 할 때마다 필터링된 스트림을 반환한다. 

(ex-

filter, map, sorted, distinct, skip

)

c. 종료 연산

ㄱ. 스트림 연산 하나당 딱 한 번만 쓸 수 있다. 

ㄴ. 스트림을 반환하지 않는다. (매소드처럼 특정 자료형에 대한 반환값이 있거나, 반환값 없이 코드 수행만 한다.)

(ex-

count, min, max, sum, forEach, anyMatch

)

 

**참고** ArrayList를 생성함과 동시에 여러 개의 값을 처리 하는 방법 

ArrayList는 안에 저장 요소 추가할 때, .add(~~)로 하나씩 추가해야 해서 배열보다 초기화가 번거롭다. 

ArrayList를 배열처럼 생성과 동시에 한번에 초기화 시켜주는 매소드가 있다. 

Arrays 클래스의 .asList() 매소드 이다.  

List<String> langList = Arrays.asList("python", "java", "javascript","c","c++","c#");

하지만 해당 매소드는 큰 단점이 있다.  배열 클래스의 매소드로 Arraylist를 생성 및 초기화 했기 때문에 list의 크기가 고정되어버린다. 값을 자유롭게 추가할 수 있던 ArrayList의 장점이 사라져 버리는 것이다.

일괄 초기화의 장점을 가지면서 해당 단점을 피해 가려면, 다음과 같이 선언 및 초기화 해야한다.

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList("1","2","3","4","5"));

이것은 ArrayList 선언 후에 그 안에다가 asList 매소드로 값을 추가했다. ArrayList로 매소드를 감쌌기 때문에 값 추가도 자유롭게 이루어진다.

3. 코드 리뷰

//90점 이상인 점수만 출력
// 위의 int인 scores 배열에 대한 필터링
Arrays.stream(scores).filter(x -> x>=90).forEach(x -> System.out.println(x));

// 클래스명, 매소드 명을 콜론으로 구분해서 적게 되면, 
// 앞에서 넘어온 데이터가 자동으로 인수로 받아져서 위의 sout println문과 똑같은 동작을 한다.
// 위와 똑같은 표현
//Arrays.stream(scores).filter(x -> x>=90).forEach(System.out::println);
//90점 이상인 사람의 수
//count 매소드는 반환형이 long 이라 long으로 변수 만듦
//(int로 받고 싶으면 스트림 앞에 형변환이 필요)

long count = Arrays.stream(scores).filter(x -> x>=90).count();
System.out.println(count);
System.out.println("------------------------------------------");
// 90점 이상인 점수들의 합
int sum = Arrays.stream(scores).filter(x -> x>=90).sum();
System.out.println(sum);
System.out.println("-----------------------------------------");


// 90점 이상인 점수들을 정렬
Arrays.stream(scores).filter(x -> x>=90).sorted().forEach(System.out::println);
System.out.println("-----------------------------------------");

4. 스스로 해보기 

package WorkOut_Myself;

import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamBasic_Myself {
    public static void main(String[] args) {
        // 기본 자료형, 참조형, 컬렉션 별로 스트림 생성해서 스트림 객체에 넣기
        // 기본 자료형 이용해서 값 계산. 중개 연산과 종료 연산은 뭐 있는지 찾아서 직접 넣어보기.

        int[] num = {1,2,3,4,5,6,7,8,9,10};
        IntStream numStream = Arrays.stream(num, 0,9);

        String[] name = {"John", "Sam", "Smith", "황재성", "골리니" };
        Stream<String> nameStream = Arrays.stream(name);

        ArrayList<Integer> score = new ArrayList<>(Arrays.asList(10,9,10,20,30,40,50,10));
        Stream<Integer> scoreStream = score.stream();

        HashMap<String, Integer> goal = new HashMap<>();
        goal.put("박지성",24);
        goal.put("손흥민",99);
        goal.put("기성용",18);
        goal.put("황희찬",5);
        goal.put("김보경",0);
        goal.put("조원희",0);

        Stream<Map.Entry<String,Integer>> Entry = goal.entrySet().stream();
        Stream<String> players = goal.keySet().stream();
        Stream<Integer> number = goal.values().stream();

        System.out.println("득점이 10점 이상인 사람만 걸러 내기");
        goal.entrySet().stream().filter(entry -> entry.getValue()>10).forEach(System.out::println);

        //map(x -> x ~~) 인수들로 한 계산의 반환 값들로 새로운 스트림 반환
        OptionalDouble a = Arrays.stream(num).map(x -> x+100).average();
        System.out.println(a);

    }
}

 

'Language > Java' 카테고리의 다른 글

Run-Time(런타임) 오류와 예외 처리  (0) 2023.02.23
[JAVA] Stream 실습  (0) 2023.02.19
[JAVA] 람다식과 함수형 인터페이스  (0) 2023.02.16
[JAVA] 익명 클래스  (0) 2023.02.15
[JAVA] Iterator  (0) 2023.02.15