Java 기초부터 다시 - interface Stream<T>
이전에 정리한 모든 자바 기본 함수형 인터페이스들(Function<T,R> , Consumer<T> ... 등등)은 사실 해당 Stream, Optional 인터페이스를 사용하기 위함이다.(개인적인 생각...)
그럼 먼저 자바8버전 이후의 핵심 Stream에 대해서 먼저 정리해 보자.
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> filter(Predicate<? super T> predicate);
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
....
<stream에서 가장 많이 쓰이는 filter, map 추상 메소드>
Stream은 자바8 이전 for, foreach, sort 등을 사용하여 리스트 관리를 해온것을 좀더 간결하고 직관적(쉽게 말해 람다로 표현 하도록) 도와주는 인터페이스 이다.
예제
예제로 알아 보기전 예제로 사용할 기본적인 클래스를 먼저 정의 해보겠다.
public class Vehicle {
public enum Type {
SUV,
SEDAN,
TRUCK
}
private Type type;
private String vendor;
private String modelName;
private String color;
private int price;
}
Vehicle vehicle1 = new Vehicle(Vehicle.Type.SUV, "BMW", "L3", "white", 250000);
Vehicle vehicle2 = new Vehicle(Vehicle.Type.TRUCK, "HYUNDAI", "Q3", "black", 150000);
Vehicle vehicle3 = new Vehicle(Vehicle.Type.SEDAN, "HONDA", "W3", "white", 550000);
Vehicle vehicle4 = new Vehicle(Vehicle.Type.SUV, "BMW", "R3", "black", 23000);
Vehicle vehicle5 = new Vehicle(Vehicle.Type.SUV, "HYUNDAI", "N3", "blue", 125000);
Vehicle vehicle6 = new Vehicle(Vehicle.Type.TRUCK, "HYUNDAI", "V3", "blue", 951000);
Vehicle vehicle7 = new Vehicle(Vehicle.Type.SEDAN, "KIA", "Z3", "red", 123000);
vehicleList = Arrays.asList(vehicle1,vehicle2,vehicle3,vehicle4,vehicle5,vehicle6,vehicle7);
Collection Type(Collection, List , Set 등)을 Stream으로 사용하기 위해서는 자바8 이후 추가된 Default Method인 stream()을 사용하면 된다.
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
1. <R> Stream<R> map(Function<? super T, ? extends R> mapper)
[Vehicle 리스트의 stream에서 map 매소드 호출 시 매개변수 및 반환값]
매개변수 : Function<Vehicle, R>
반환값 : Stream<R>
말로 풀어 보면 Vehicle객체받아 R을 반환하는 Function 인터페이스를 사용하여 반환된 R타입의 Stream을 반환 한다.
즉 Stream의 MAP은 기존의 Stream을 변경 및 새롭게 생성을 하는 역할을 한다.
List<String> vehicleColors_V1 = vehicleList.stream().map(new Function<Vehicle, String>() {
@Override
public String apply(Vehicle vehicle) {
return vehicle.getColor();
}
}).toList();
// Vehicle들의 Color 리스트
[vehicle stream을 각각의 vehicle들의 색상 stream(String type)으로 변경]
해당 표현방식은 Lamda로 표현이 가능하다.
List<String> vehicleColors = vehicleList.stream().map(vehicle1 -> vehicle1.getColor()).toList();
//또는
List<String> vehicleColors = vehicleList.stream().map(Vehicle::getColor).toList();
2. Stream<T> filter(Predicate<? super T> predicate)
[Vehicle 리스트의 stream에서 filter매소드 호출 시 매개변수 및 반환값]
매개변수 : Predicate<Vehicle>
반환값 : Stream<Vehicle>
말로 풀어 보면 Vehicle객체를 받는 Predicate 인터페스를 통해 True/False를 판단하고, True인 Vehicle들의 Stream을 반환한다.
즉 Stream의 Filter는 기존의 Stream에서 Predicate를 사용하여 알맞는 객체들만 필터링 후, 자신과 동일한 형태의 Stream을 반환하는 역할을 한다.
List<Vehicle> blackVehicles = vehicleList.stream().filter(new Predicate<Vehicle>() {
@Override
public boolean test(Vehicle vehicle) {
if (vehicle.getColor().equals("black")) return true;
else return false;
}
}).toList();
Map과 동일하게 해당 Lamda로 표현이 가능하다.
List<Vehicle> blackVehicles = vehicleList.stream().filter(v -> v.getColor().equals("black")).toList();
3. 마무리
기본적으로 Stream은 Map과 Filter만으로도 리스트를 다양하게 원하는 형태로 바꾸는 것이 가능하다.
//EXAMPLE
List<String> stringList2 = vehicleList2.stream().filter(v -> v.getColor().equals("blue")).map(v -> v.getVendor()).toList();
이 외에도 Stream은 flatMap, foreach, sorted등 다양한 기능을 제공한다. 필요에 따라서 구글링을 통해 자기가 필요한 기능을 찾아가면서 사용한다면 확실히 기존보다 편하게 리스트를 관리할 수 있다.