자바 스트림 요소 처리

BRINCE·2022년 9월 20일
0

자바 스터디

목록 보기
8/10

스트림이란?

스트림은 요소들이 하나씩 흘러가면서 처리된다는 의미를 가지고 있다.

Stream<String> stream = list.stream();
stream.forEach(System.out::println); //요소 출력

패션쇼 같다고 생각하면 쉽다. 요소들이 모델들이라고 생각하고 첫번째 워킹부터 마지막 피날레까지 보여준다고 생각하자 ~ 🤔

보통은 람다식으로 처리를 하기 때문에 필드가 굉장히 간결해진다.
(람다식을 익히고 싶으면 람다식 예제를 들여다보지 말고 스트림을 활용해보자 !)

중간 처리를 위한 메소드와 최종 처리를 위한 메소드가 따로 있고, 이것들로 파이프 라인을 형성할 수 있다.

중간 처리와 최종 처리

스트림이 연결되어 있는 것을 스트림 파이프라인 이라고 하고 , 그것을 이루는게 중간 처리 메소드와 최종 처리 메소드라고 생각하면 쉽다.
(쉽게 말해 중간 처리 메소드는 마지막에 올 수 없고, 최종 처리 메소드가 있어야만 파이프라인이 완성된다고 생각하자! 😁)

중간 스트림들은 최종 처리를 위해 요소를 걸러내거나 변환시키거나 정렬하는 작업을 수행한다.
최종 처리는 중간 처리에서 정제된 요소들을 반복하거나, 집계 작업을 수행한다.

                double avg = list.stream()
                .mapToInt(Student::getScore) //값을 정수값으로 가져와줌
                        .average() //평균 내는 메소드
                        .getAsDouble(); //double 로 타입 변환
                System.out.println("평균 점수:" + avg);

이 코드들을 보면 , 중간에 들어간 .average() 가 중간처리, .getAsDouble() 이 최종처리이다. 딱 간결하게 얘기하면 중간처리는 생산, 최종처리는 검수 ? 라고 생각하면 쉽다 ㅎ 😗
🤦‍♂️파이프 라인의 맨 끝에는 반드시 최종 처리 부분이 있어야 한다. 없으면 동작하지 않아요..🤦‍♂️

리소스로부터 스트림 얻기

컬렉션으로부터 스트림 얻기

List<Models> list = new ArrayList<>(); //리스트 생성
           for(int i=1;i<=5;i++){
           Models model = new Models(i,"i번모델,"i번째 옷");//객체 생성
           list.add(model); //객체 대입
                }
         Stream<Models> stream = list.stream(); //객체스트림 생성
         stream.forEach(p->System.out.println(p)); //람다식으로 출력

이렇게 리스트 컬렉션에 객체를 대입해 리스트로부터 스트림을 얻어서 출력이 가능하다.
쉽게 말하자면 처음에 언급했던 패션쇼에 모델들을 추가해서 쇼를 세운다고 생각하면 쉽다.

배열로부터 스트림 얻기

java.util.Arrays 클래스를 이용해서 스트림을 얻을 수도 있다.

String[] students = {"김민수","김민희","김희철}; //배열 생성
Stream<String> stream = Arrays.stream(students); //스트림 얻기
stream.forEach(n -> System.out.println(n));

이렇게 출력하면 for문을 이용하지 않고 모든 내용물을 출력할 수 있다.

숫자 범위로부터 스트림 얻기

range(), rangeClosed() 메소드를 이용해서 특정 범위의 정수 스트림을 얻을 수 있다.
끝수를 포함하지 않으면 range(), 포함할때 rangeClosed() 를 사용한다.

 int sum;
 IntStream stream = IntStream.rangeClosed(1,1000); //정수 1에서 1000까지
 sum = stream.sum(); //스트림속 모든 수 합
 System.out.println(sum);

굳이 for문으로 sum+= 로 총합을 구할 필요 없이 .sum 메소드를 사용하면 간단하게 알아서 다 더해준다. 굳

필터링

말그래도 원하는 결과물을 가져와준다.
필터링 메소드에는 중복을 제거해주는 distinct() 와 조건을 부여해줄 filter() 메소드가 있다.

int[] intarr = {1,2,3,2,3,4,5};
int total = Arrays.stream(intarr)
			.distinct()
            .filter(a->a%2==0) //2의 배수만 쏙 골라와줌
            .peek(System.out::println) //중간처리 출력메소드(forEach의 중간처리버전)
            .sum();

거의 모든 메소드를 람다식으로 처리하기 때문에 확실하게 이해하고 가면 좋다.

요소 변환 (매핑)

double avg = list.stream()
             .mapToInt(Student::getScore) //값을 정수값으로 가져와줌
             .average() //평균 내는 메소드
             .getAsDouble(); //double 로 타입 변환

여기 위에 보이는 mapToInt 가 요소변환 메소드이다. 저 메소드가 없었다면, 출력을 했을때 student.name student.score 이렇게 이름과 점수가 같이 나올것이다.

하지만 요소를 Int 요소로 확실하게 지정해줌으로써 원하는 값이 출력되거나 그 값으로 중간처리를 할 수 있다. :)

요소를 복수 개의 요소로 변환

flatMapXxx() 메소드를 사용하여 하나의 요소를 복수 개의 요소들로 변환한 새로운 스트림을 리턴할 수 있다.
StringTokenizer 과 비슷하다 생각하면 좋다.
하나의 문자열 "안녕 난 김자바야"를 추가한 배열에 flatMap메소드를 사용해 Arrays.stream(data.split(" ")) 으로 안녕/난/감자바야 라는 스트림을 출력할 수 있다.

요소 정렬

스트림은 오름차순 또는 내림차순으로 정렬이 가능하다.

List<Student> list = Arrays.asList(
                    new Student("김","남",99),
                    new Student("님","여",100),
                    new Student("딤","남",50),
                    new Student("림","여",60));
                list.stream() //점수별로 정렬
                 .sorted((s1,s2)-> Integer.compare(s2.getScore(),s1.getScore())) // 내림차순
                 .forEach(s->System.out.println(s));

이렇게 sorted 로 내림차순 혹은 오름차순으로 정렬이 가능하다.
저건 내림차순 정렬인데, 단순히 오름차순을 하고 싶다면 s1.getScore 과 s2.getScore 의 순서를 반대로 하면 된다.

루핑

루핑에는 중간처리 메소드인 peek() 과 최종처리 메소드인 forEach() 가 있다.
peek() 같은 경우에는 최종 처리가 뒤에 붙지 않으면 동작을 하지 않는다.

매칭

매칭에는 boolean 을 리턴하는 allMatch(), anyMatch(), noneMatch() 메소드가 있다.
filter 는 내가 적어놓은 조건에 맞는 요소들을 리턴해준다면, 매치 메소드는 boolean 을 리턴해준다.
filter 와 비슷하게 allMatch(s-> s%2==0); 이런식으로 사용하면 참거짓을 리턴해준다.

요소 기본 집계

집계는 최종 처리 기능으로 카운팅, 합계, 평균값, 최대값, 최소값등과 같이 하나의 값으로 산출하는 것을 말한다.
filter와 자주 같이 쓰이는것 같다.
보통 필터 메소드로 조건을 내걸은 후에 count() 라던가 sum, average 같은 중간처리 메소드로 최종적으로 하나의 값을 리턴한다.

Optional 클래스

만약에 필터를 걸어서 값을 얻어야 하거나 얻은 값으로 집계를 하려고 할때 요소가 존재하지 않는다면? 예외가 발생할것이다.
우리가 예외처리를 try-catch-finally 로 하는 것처럼 스트림은 Optional 클래스로 예외처리를 할 수 있다.

  • isPresent() : 메소드가 true 를 리턴할때만 집계값을 얻는다. (if 문으로 사용한다.)
  • orElse(0) : 아니면 이거~ 집계값이 없을때 매개변수 값(예제로 0)을 출력한다.
  • ifPresent() : 집계값이 있을 경우에만 동작하는 함수를 제공한다.

요소 수집

필요한 요소만 컬렉션에 담고 요소들을 그룹핑한 후에 집계도 할 수 있다.

List<Student> list = list.stream()
					.filter(s-> s.getSex().equals("남")
                   	.collect(Collectors.toList()); //성별이 남자인 학생들 리스트

Map 으로도 그룹핑 할 수 있다.

Map<String,List<Student>> map = list.stream()
							.collect(
                            Collectors.groupingBy(
                            s-> s.getSex())
                            );

이렇게 성별별로 그룹을 나눠서 성별을 키, 리스트를 값으로 하여

List<Student> maleList = map.get("남");
			maleList.stream().forEach(System.out::println);

이런식으로 성별이 남자인 학생의 리스트만 불러올 수 있다.

마치며

stream 같은 경우엔 개인적으로 엑셀의 기능들과 비슷하다는 생각이 들었다.
알고리즘 풀이에 굉장히 유용할것 같은 기능이라는 생각도 든다.
끝~

profile
자스코드훔쳐보는변태

0개의 댓글