티스토리 뷰

JAVA/정리

Stream 요소처리

란텔 2024. 12. 10. 20:30

Java8 부터는 컬렉션이나 배열(이하 전부 설명시 컬렉션이라고 함.)의 요소 처리를 위해서 Stream을 사용할 수 있다.

 

기존 방식은 for문이나 Iterator같은 반복문을 통해서 컬렉션을 외부에서 접근했다.

Stream은 요소(컬렉션의 각각의요소)의 처리를 Stream에 집어넣어 내부에서 반복처리한다. 

  • Stream은 내부에서 반복처리 된다. 
  • 람다식으로 다양한 컬렉션 요소의 처리를 정의할 수 있다.
  • Stream중간처리메서드최종처리 메서드를 가지고 있으며, 마지막에 최종처리 메서드를 선언하지 않으면 그 전에 선언한 중간처리 메서드도 수행하지 않는다.
  • 다시말해  중간 연산들이 실제로 실행되지 않고, 최종 연산이 호출될 때 모든 연산이 한 번에 실행된다.
  • 최종연산이 끝난 후 해당 Stream은 다시 사용할 수 없다.

 

컬렉션, 배열의 Stream 객체를 얻는 방법

 

  • 배열 대상 Stream객체 얻기
		Stream<Integer> arraysStream = Arrays.stream(new Integer[] {1,2,3,4,5});
		arraysStream.forEach(System.out::println);

위와 같이 사용하면 Stream은 해당 배열의 각 인덱스에 위치한 정수를 요소로 다룬다.

 

  • 컬렉션 대상 Stream객체 얻기
		//컬렉션타입 대상으로 stream() 메서드 사용
		Stream<Staff> stream = StaffList.getStaffList().stream();
		stream.forEach(x -> System.out.println(x));

위와 같이 사용하면 Stream은 List의 각 요소인 Staff객체를 반복하여 요소를 다룬다.

 

  • 컬렉션 및 배열대상 Stream객체 얻기
		//Stream객체의 of메서드 사용하여 매개변수에 컬렉션타입이나 배열타입 지정
		Stream<List<Staff>> ofStream = Stream.of(StaffList.getStaffList());
		ofStream.forEach(s -> System.out.println(s));

**위 두가지 방식과 Stream.of(컬렉션or배열)의 다른점**

Stream.of(컬렉션) 사용 시 : Staff를 각각의 요소로 생각하지 않고 해당 컬렉션타입인 List를 하나의 요소처럼 다룬다.

Stream.of(배열) 사용 시 : Arrays.stream(배열)과 똑같이 각 인덱스의 요소를 Stream의 요소로 다룬다.

 

 

만약 Stream.of(컬렉션)을 사용하면서 List의 각각의 요소인 Staff에 접근하고 싶다면 아래와 같이 사용하면 된다.

		//각 요소객체인 Staff에 접근하기 위해 flatMap(Collection::stream)사용
		Stream<List<Staff>> ofStream1 = Stream.of(StaffList.getStaffList());
		ofStream1.flatMap(Collection::stream).forEach(s -> System.out.println(s));

 

 

숫자 범위로 Stream객체를 얻는 방법

 

아래는 1부터 10까지 범위의 int형 정수를 각 요소로 가지는 IntStream을 얻는다.

- IntStream.range(시작, 끝-1)  : 이 메서드는 끝값을 포함하지 않기 때문에 끝-1이다. 

- IntStream.rangeClosed(시작,끝)

		//IntStream객체의 range(시작, 끝-1), rangeClosed(시작,끝)을 호출
        	IntStream is1 = IntStream.range(1, 11);
		IntStream is2 = IntStream.rangeClosed(1, 10);
		is1.forEach(n->System.out.printf("%d,",n));
		System.out.println();
		is2.forEach(n->System.out.printf("%d,",n));

 

 

 

필터(걸러내는) 중간처리 메서드 distinct, filter

 

- distinct() : Stream요소의 중복을 제거. Stream의 요소가 객체일 경우 equals비교 했을 때 true시 동일요소로 간주. 숫자일 경우는 그대로 값을 비교해서 중복제거.

아래는 Staff를 요소로 가지는 Stream에서 월급의 중복을 제거하는 코드

		Stream<Staff> s1 = StaffList.getStaffList().stream();
		s1.mapToInt(s->s.getSalary()).distinct().forEach(System.out::println);

 

- filter(Predicate T) : 조건을 필터링하는 메서드. true를 반환하면 해당 요소는 포함되고 false반환시 요소에서 제외 된다.

아래는 개발부에 속한 직원만 출력하는 코드

		Stream<Staff> ss1 = StaffList.getStaffList().stream();
		ss1
		.filter(s->s.getDepartment().equals("개발"))
		.forEach(System.out::println);

 

 

 

 

요소변환 중간처리 메서드

 

  • Stream요소의 타입을 다른타입으로 변환하는 중간처리 메서드

- map, mapToInt, mapToDouble, mapToLong과 같은 메서드가 존재

위에서 distinct() 사용 시 mapToInt를 사용했었다

s1.mapToInt(s->s.getSalary()).distinct().forEach(System.out::println);

s라는 변수가 해당 반복의 요소객체를 가리키므로 즉 Staff객체이다. 하지만 mapToInt를 사용함으로써 salary값을 만을 요소로 가지는 스트림으로 변환된다.

 

 

 

요소 정렬 중간처리 메서드 sorted()

 

  • Stream의 요소를 오름차순, 내림차순으로 정렬하는 메서드다.

- 요소가 숫자타입이거나 String타입이면 sort() 메서드를 사용했을 때 기본으로 오름차순 정렬된다.

Stream<String> sstream = Arrays.stream(new String[] {"c","a","z","d"});
sstream.sorted().forEach(s->System.out.println(s));
        
-----------------결과-----------------
a
c
d
z

 

 

- 만약 요소가 객체 타입이라면 해당 요소객체 해당 클래스에 Comparable 인터페이스를 구현해주거나

- 요소 객체클래스가 아닌 곳에서 정의하려면 Comparator를 구현하여야 한다. 안하면 에러 발생!

아래는 Staff클래스에 name필드를 대상으로 Comparable을 구현한 코드이다.

오버라이딩 메서드 compareTo(Staff s) 안에서 name대상으로 compareTo를 다시 호출했는데 compareTo메서드는 기본적으로 숫자와 String타입을 대상으로 정렬해주기 때문에 이렇게 사용한다.

아래는 오름차순 정렬이고 만약에 내림차순 정렬을 해야 한다면 this.name과 s.name의 위치만 바꾸면 된다.

class Staff implements Comparable<Staff>{
	private String name;
    ....
    ....
	@Override
	public int compareTo(Staff s) {
		return this.name.compareTo(s.name);
	}
    
}

이제 Staff객체를 각 요소로 가지는 Stream에서 sorted()를 호출하면 name순으로 오름차순 정렬된다.

Stream<Staff> staffStream = StaffList.getStaffList().stream();
staffStream.sorted().forEach(s->System.out.println(s));

-------결과------------------
[영희, 28, 디자인, 280]
[주희, 34, 개발, 350]
[철수, 37, 개발, 350]
[홍길동, 26, 기획, 250]

 

sorted(Comparator) 처럼 매개변수에 Comparator타입의 구현체를 지정할 수 있다.

public static void main(String[] args) {
		
		
    //1. Comparator추상클래스 익명클래스 선언 (나이 오름차순)
    Comparator<Staff> c = new Comparator<>() {
        @Override
        public int compare(Staff s1, Staff s2) {
            return Integer.compare(s1.getAge(), s2.getAge());
        }
    };
    //1에서 Comparator타입의 참조변수c를 메서드 매개변수로 대입
    Stream<Staff> staffStream = StaffList.getStaffList().stream();
    staffStream.sorted(c).forEach(s->System.out.println(s));

    System.out.println("-----------------------------------");

    //2. 직접 람다식으로 Comparator 처리 (나이 내림차순)
    Stream<Staff> staffStream1 = StaffList.getStaffList().stream();
    staffStream1.sorted((s1, s2) -> {
        return Integer.compare(s2.getAge(), s1.getAge());
    }).forEach(s->System.out.println(s));
		
}
    
    
    
--------------결과------------------
[홍길동, 26, 기획, 250]
[영희, 28, 디자인, 280]
[주희, 34, 개발, 350]
[철수, 37, 개발, 400]
[덕수, 40, 기획, 350]
-----------------------------------
[홍길동, 26, 기획, 250]
[영희, 28, 디자인, 280]
[주희, 34, 개발, 350]
[철수, 37, 개발, 400]
[덕수, 40, 기획, 350]
Comments
최근에 올라온 글
최근에 달린 댓글
TAG
more
Total
Today
Yesterday