[java] Java 에서 Stream 사용하기

[java] Java 에서 Stream 사용하기

반응형

오늘은 Stream 을 사용하는 방법에 대해 쭉 정리를 해보고자 한다.

Stream 생성하기

stream 은 두가지 방법으로 생성이 가능하다.

Collection 으로 생성하기

// Collection(List) 로부터 스트림 생성 List collection = Arrays.asList("a", "b", "c", "e", "f"); Stream collectionStream = collection.stream();

Array로 생성하기

// 배열로부터 스트림을 생성 Stream arrayStream1 = Stream.of("a", "b", "c"); //가변인자 Stream arrayStream2 = Stream.of(new String[]{"a", "b", "c"}); Stream arrayStream3 = Arrays.stream(new String[]{"a", "b", "c"}); Stream arrayStream4 = Arrays.stream(new String[]{"a", "b", "c"}, 0, 2);

스트림을 리스트로

역으로 리스트를 스트림으로 바꾸는것도 가능하다.

//스트림을 리스트로 List changeList = arrayStream2.collect(Collectors.toList());

원시 스트림 생성

Stream 은 int, long, double 같은 원시 자료형을 위한 스트림이 존재한다. int나 long 같은 경우는 range 함수로 for문을 대체하여 사용이 가능하다.

// 원시 스트림 생성 LongStream longStream = LongStream.range(3l, 10l);

Stream 중간연산 (객체요소 가공하기)

생성된 Stream 은 반환되기전 중간의 연산과정을 거칠수 있다. 각 연산 방법을 정리해보겠다.

Filter

filter는 말그대로 조건에 맞춰 필터링하여 컬렉션을 만들어내는 방식이다.

// 필터 사용 List list = new ArrayList<>(); list.add("aa"); list.add("ab"); list.add("bb"); Stream streamFilter = list.stream().filter(s -> s.contains("a"));

Map

Map 은 기존에 Stream 에 있던 데이터를 변경하여 새로운 Stream을 만들어 내는 연산 방식이다.

// 맵 사용 List numList = new ArrayList<>(); numList.add(1); numList.add(2); numList.add(3); Stream streamMap = numList.stream().map(n -> n*3);

map 에서는 메서드 참조도 자주 이용하여 사용하므로 방법을 익혀두면 좋을듯하다.

// 맵에서 메서드 참조 사용 Stream fileStream = Stream.of(new File("file1.txt"), new File("file2.txt"), new File("file3.txt")); Stream streamMapMethodRef = fileStream.map(File::getName);

Sort

stream 에 있는 요소는 sorted 함수를 통해 정렬이 가능하다.

// 정렬 기능 // 오름차순 정렬 List notSortedList = Arrays.asList(3,5,2,4,1,7); Stream streamAsc = notSortedList.stream().sorted(); // 내림차순 정렬 Stream streamDesc = notSortedList.stream().sorted(Comparator.reverseOrder());

Distinct

stream 에 있는 요소 중 중복된 요소를 distinct 를 이용하여 제거할 수 있다.

distinct 를 제대로 쓰기 위해서는 사용하고자하는 객체의 equals 와 hashCode를 오버라이드 해야 제대로 사용이 가능하다. 예시로 한 클래스에 대하여 오버라이딩을 해보았다.

class Person { private String name; public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name); } }

그리고 이 클래스를 통해 객체를 만들고 distinct를 써보면 아래와 같다.

// 중복제거 Person p1 = new Person("kang"); Person p2 = new Person("kim"); Person p3 = new Person("kang"); List people = new ArrayList<>(); people.add(p1); people.add(p2); people.add(p3); Stream peopleStream = people.stream().distinct();

peek

peek 은 stream에 특정 영향을 미치지않고 단순하게 확인을 위한 함수라고 생각하면된다.

// 데이터 확인하기 (peek) IntStream.of(1,2,3,4,5).peek(System.out::println);

Stream 결과 연산

최대,최소,평균 연산

최대, 최소 , 평균 연산의 경우 Stream의 데이턱다 Null 인경우에 대한 이슈(Optional)가 있어 별도로 처리해줄 필요가 있다. (없을경우에 대한 값을 세팅해줘야함)

// Max. Min, Avg OptionalInt max = IntStream.of().max(); int min =IntStream.of(1,2,3,4,5).min().orElse(0); double average = IntStream.of(1,2,3,4,5).average().orElse(0);

합, 카운트

총합이나 카운팅을 하는 경우에는 비어있으면 0이 반환되어 Null 이슈가 없다.

// Count , Sum long count = IntStream.of(1,2,3,4,5).count(); int sum = IntStream.of(1,2,3,4,5).sum();

데이터 수집 연산 (Collect) 처리

toList

스트림을 리스트로 변환하여 반환한다.

//toList List nameList = people.stream() .map(Person::getName) .collect(Collectors.toList());

joining

결과를 이어붙일 때사용한다. 파라미터가 순차적으로 세개가 올수 있는데 요소를 구분시켜주는 구분자(delimiter), 요소 맨앞에 올 문자 (prefix), 요소 맨뒤에 올 문자(suffix) 가 파라미터로 올 수 있다.

//joining String joining = people.stream() .map(Person::getName) .collect(Collectors.joining(" "));

averaging, summing

collect 에서도 합이나 평균을 구할 수 있다.

// averaging, summing List fruitList = Arrays.asList( new Fruit("apple", 9), new Fruit("banana", 13), new Fruit("mango", 8), new Fruit("peach", 9), new Fruit("melon",16)); Double collectAverage = fruitList.stream().collect(Collectors.averagingInt(Fruit::getAmount)); Integer collectSum = fruitList.stream().collect(Collectors.summingInt(Fruit::getAmount));

summarizing

요약기능을 통해 최대값, 최소값, 평균값, 갯수, 합을 구할 수 있다.

//summarize IntSummaryStatistics collectStatics = fruitList.stream().collect(Collectors.summarizingInt(Fruit::getAmount)); int fruitMax = collectStatics.getMax(); int fruitMin = collectStatics.getMin(); double fruitAverage = collectStatics.getAverage(); long fruitCount = collectStatics.getCount(); long fruitSum = collectStatics.getSum();

partitioningBy

partitioningBy 를 이용하여 특정 조건에 대한 구분을 지을수 있다. 예를 들어 과일의 갯수가 10보다 작다라는 조건을 주면 10보다 작으면 true 크거나 같으면 false 가 주어질 수 있다.

// partitioningBy Map> collectPartitioningBy = fruitList.stream().collect(Collectors.partitioningBy(c -> c.getAmount() < 10));

groupingBy

groupingBy를 이용하여 특정 그룹으로 데이터를 묶을 수 있다. 예를 들어 과일의 갯수를 기준으로 그룹을 묶을수 있다.

// groupingBy Map> collectGroupingBy = fruitList.stream().collect(Collectors.groupingBy(Fruit::getAmount));

특정 조건 검사

match

match 를 이용하여 특정 조건을 검사할 수 있다. anyMatch는 1개 요소라도 만족하는지, allMatch 는 모든 요소가 만족하는지, nonMatch는 모든 요소가 조건을 만족하지 않는지를 검사한다.

// match boolean anyMatch = fruitList.stream().map(Fruit::getName).anyMatch(name -> name.contains("a")); boolean allMatch = fruitList.stream().map(Fruit::getName).allMatch(name -> name.length() > 1); boolean nonMatch = fruitList.stream().map(Fruit::getName).noneMatch(name -> name.equals("fruit"));

반복문

forEach

각 데이터를 순차적으로 처리하기 위해 forEach를 활용할 수 있다.

//forEach nameList.stream().forEach(System.out::println);

끝.

반응형

from http://devkingdom.tistory.com/293 by ccl(A) rewrite - 2021-11-10 18:27:40