[Java] 스트림
스트림
컬렉션 및 배열에 저장된 요소를 반복 처리하기 위해서는 for 문을 이용하거나 Iterator(반복자)를 이용했다.
List<String> list = ....;
for(int i=0; i<list.size(); i++){
String item = list.get(i);
//item 처리
}
그리고 Set에서 요소를 하나씩 처리하기 위해 Iterator를 다음과 같이 사용했다.
Set<String> set = ...;
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
String item = iterator.next();
//요소 처리
}
Java 8부터는 또 다른 방법으로 컬렉션 및 배열의 요소를 반복 처리하기 위해 스트림을 사용할 수 있다. 스트림은 요소들이 하나씩 흘러가면서 처리된다는 의미를 가지고 있다.
Stream<String> stream = list.stream();
stream.forEach(item -> //item 처리);
package ch17.sec01.exam01;
import java.util.stream.Stream;
import java.util.*;
public class StreamExample {
public static void main(String[] args) {
//Set 컬렉션 생성
Set<String> set = new HashSet<>();
set.add("홍길동");
set.add("신용권");
set.add("감자바");
//Stream을 이용한 요소 반복 처리
Stream<String> stream = set.stream();
stream.forEach(name-> System.out.println(name));
}
}
Stream은 Iterator와 비슷한 반복자이지만, 다음과 같은 차이점을 가지고 있다. 1) 내부 반복자이므로 처리 속도가 빠르고 병렬 처리에 효율적이다. 2) 람다식으로 다양한 요소 처리를 정의할 수 있다. 3) 중간 처리와 최종 처리를 수행하도록 파이프 라인을 형성할 수 있다.
컬렉션으로부터 스트림 얻기
java.util.Collection 인터페이스는 스트림과 parallelStream() 메소드를 가지고 있기 때문에 자식 인터페이스인 List와 Set 인터페이스를 구현한 모든 컬렉션에서 객체 스트림을 얻을 수 있다.
package ch17.sec04.exam01;
public class Product {
private int pno;
private String name;
private String company;
private int price;
public Product(int pno, String name, String company, int price){
this.pno = pno;
this.name = name;
this.company = company;
this.price = price;
}
public int getPno() {return pno;}
public String getName() {return name;}
public String getCompany() {return company;}
public int getPrice() {return price;}
@Override
public String toString(){
return new StringBuilder()
.append("{")
.append("pno: "+pno+", ")
.append("name: "+name+", ")
.append("company: "+company+", ")
.append("price: "+price)
.append("}")
.toString();
}
}
package ch17.sec04.exam01;
import java.util.*;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
//List 컬렉션 생성
List<Product> list = new ArrayList<>();
for(int i=1; i<=5; i++){
Product product = new Product(i, "상품"+i, "멋진 회사 ",
(int)(10000*Math.random()));
list.add(product);
}
//객체 스트림 얻기
Stream<Product> stream = list.stream();
stream.forEach(p -> System.out.println(p));
}
}
배열로부터 스트림 얻기
java.util.Arrays 클래스를 이용하면 다양한 종류의 배열로부터 스트림을 얻을 수 있다.
package ch17.sec04.exam02;
import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
String[] strArray = {"홍길동", "신용권", "김미나"};
Stream<String> strStream = Arrays.stream(strArray);
strStream.forEach(item -> System.out.print(item+","));
System.out.println();
int[] intArray = {1, 2, 3, 4, 5};
IntStream intStream = Arrays.stream(intArray);
intStream.forEach(item -> System.out.print(item+","));
System.out.println();
}
}
숫자 범위로부터 스트림 얻기
IntStream 또는 LongStream의 정적 메소드인 range()와 rangeClosed() 메소드를 이용하면 특정 범위의 정수 스트림을 얻을 수 있다. 첫 번째 매개값은 시작 수이고 두 번째 매개값은 끝 수인데, 끝 수를 포함하지 않으면 range(), 포함하면 rangeClosed()를 사용한다.
package ch17.sec04.exam03;
import java.util.stream.IntStream;
public class StreamExample {
public static int sum;
public static void main(String[] args) {
IntStream stream = IntStream.rangeClosed(1,100);
stream.forEach(a -> sum+=a);
System.out.println("총합 : "+sum);
}
}
요소 걸러내기(필터링)
필터링은 요소를 걸러내는 중간 처리 기능이다. 필터링 메소드에는 다음과 같이 distinct()와 filter()가 있다.
dinstinct() 메소드는 요소의 중복을 제거한다. 객체 스트림(Stream)일 경우, equals() 메소드의 리턴값이 true이면 동일한 요소로 판단한다. IntStream, LongStream, DoubleStream은 같은 값일 경우 중복을 제거한다.
Predicate는 함수형 인터페이스로, 다음과 같은 종류가 있다.
Predicate
T -> {... return true}
또는
T -> true; //return 문만 있을 경우 중괄호와 return 키워드 생략 가능
package ch17.sec05;
import java.util.*;
public class FilteringExample {
public static void main(String[] args) {
//List 컬렉션 생성
List<String> list = new ArrayList<>();
list.add("홍길동");
list.add("신용권");
list.add("감자바");
list.add("신용권");
list.add("신민철");
//중복 요소 제거
list.stream()
.distinct()
.forEach(n-> System.out.println(n));
System.out.println();
//신으로 시작하는 요소만 필터링
list.stream()
.filter(n->n.startsWith("신"))
.forEach(n-> System.out.println(n));
System.out.println();
//중복 요소를 먼저 제거하고, 신으로 시작하는 요소만 필터링
list.stream()
.distinct()
.filter(n->n.startsWith("신"))
.forEach(n-> System.out.println(n));
}
}
요소 정렬
정렬은 요소를 오름차순 또는 내림차순으로 정렬하는 중간 처리 기능이다.
리턴 타입 | 메소드(매개변수) | 설명 |
---|---|---|
Stream |
sorted() | Comparable 요소를 정렬한 새로운 스트림 생성 |
Stream |
sorted(Comparator |
요소를 Comparator에 따라 정렬한 새 스트림 생성 |
Doublestream | sorted() | double 요소를 올림차순으로 정렬 |
IntStream | sorted | int 요소를 올림차순으로 정렬 |
LongStream | sorted | long 요소를 올림차순으로 정렬 |
Comparable 구현 객체의 정렬
스트림의 요소가 객체일 경우 객체가 Comparable을 구현하고 있어야만 sorted() 메소드를 사용하여 정렬할 수 있다.
List<Xxx> list = new ArrayList<>();
Stream<Xxx> stream = list.stream();
Stream<Xxx> orderedStream = stream.sorted();
만약 내림차순으로 정렬하고 싶다면 다음과 같이 Comparator.reverseOrder() 메소드가 리턴하는 Comparator를 매개값으로 제공하면 된다.
Stream<Xxx> reverseOrderedStream = stream.sorted(Comparator.reverseOrder());
package ch17.sec07.exam01;
import java.util.*;
public class Student implements Comparable<Student>{
private String name;
private int score;
public Student(String name, int score){
this.name = name;
this.score = score;
}
public String getName() {return name;}
public int getScore() {return score;}
@Override
public int compareTo(Student o){
return Integer.compare(score, o.score);
}
}
package ch17.sec07.exam01;
import java.util.*;
public class SortingExample {
public static void main(String[] args) {
//List 컬렉션 생성
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("홍길동", 30));
studentList.add(new Student("신용권", 10));
studentList.add(new Student("유미선", 20));
//점수를 기준으로 오름차순으로 정렬한 새 스트림 얻기
studentList.stream()
.sorted()
.forEach(s -> System.out.println(s.getName()+": "+s.getScore()));
System.out.println();
//점수를 기준으로 내림차순으로 정렬한 새 스트림 얻기
studentList.stream()
.sorted(Comparator.reverseOrder())
.forEach(s-> System.out.println(s.getName()+": "+s.getScore()));
}
}
Comparator를 이용한 정렬
요소 객체가 Comparable을 구현하고 있지 않다면, 비교자를 제공하면 요소를 정렬시킬 수 있다. 비교자는 Comparator 인터페이스를 구현한 객체를 말하는데 다음과 같이 간단하게 람다식으로 작성할 수도 있다.
sorted((o1, o2)->{...})
중괄호 안에는 o1이 o2보다 작으면 음수, 같으면 0, 크면 양수를 리턴하도록 작성하면 된다. o1과 o2가 정수일 경우에는 Integer.compare(o1, o2)를, 실수일 경우에는 Double.compare(o1, o2)를 호출해서 리턴값을 리턴해도 좋다.
package ch17.sec07.exam02;
public class Student {
private String name;
private int score;
public Student(String name, int score){
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
}
package ch17.sec07.exam02;
import java.util.*;
public class SortingExample {
public static void main(String[] args) {
//List 컬렉션 생성
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("홍길동",30));
studentList.add(new Student("신용권",10));
studentList.add(new Student("유미선",20));
//점수를 기준으로 오름차순으로 정렬한 새 스트림 얻기
studentList.stream()
.sorted((s1, s2)-> Integer.compare(s1.getScore(), s2.getScore()))
.forEach(s -> System.out.println(s.getName()+": "+s.getScore()));
//점수를 기준으로 내림차순으로 정렬한 새 스트림 얻기
studentList.stream()
.sorted((s1, s2)->Integer.compare(s2.getScore(), s1.getScore()))
.forEach(s-> System.out.println(s.getName()+": "+s.getScore()));
}
}
- 출처: 이것이 자바다
댓글남기기