Java 스트림(Stream)

Codren·2021년 6월 5일
0

Section 1. 스트림(Stream)

1. 스트림(Stream)

배열, 컬렉션 등의 요소를 하나씩 참조하여 동일한 연산을 반복적으로 수행하는 기능 (클래스)

  • 보통 함수형 인터페이스(람다식)의 연산을 수행함
  • 스트림 연산은 중간 연산과 최종 연산으로 구분 됨
  • 한번 생성하고 사용한 스트림은 재사용 할 수 없음 (소모성)
  • 자료에 대한 스트림을 생성하면 스트림이 사용하는 메모리 공간은 별도로 생성되므로 연산이 수행되도 기존 자료에 대한 변경은 발생하지 않음




2. 스트림 생성 및 사용

  • 정수 배열에 스트림 생성하여 연산을 수행 하는 예 (Arrays.stream(arr))
public class IntArrayTest {

	public static void main(String[] args) {

		int[] arr = {1,2,3,4,5};			# 정수 배열 선언
		
		int sumVal = Arrays.stream(arr).sum();		# 정수 배열 스트림생성
		long count = Arrays.stream(arr).count();	# 정수 배열 스트림 생성
		
		System.out.println(sumVal);
		System.out.println(count);
	}

}




3. 중간 연산

  • 조건에 맞는 요소를 추출하거나 요소를 변환 함 (filter, map, sorted 메서드 등)
  • 최종 연산이 호출될 때 중간 연산이 수행되고 결과가 생성 됨 (메서드 체이닝)




4. 최종 연산

  • 스트림이 관리하는 자료를 하나씩 소모해가며 연산하는 것 (forEach, count, sum 메서드 등)
  • 최종 연산 후에 스트림은 더 이상 다른 연산을 적용할 수 없음




5. 중간 연산과 최종 연산

  • 문자열 리스트에서 문자열의 길이가 5 이상인 요소만 출력하는 연산
    (filter는 중간 연산이고, forEach는 최종 연산임)
sList.stream().filter(s->s.length() >= 5).forEach(s->System.out.println(s));
  • 고객 클래스 배열에서 고객 이름만 가져오는 연산
    (map()은 중간 연산이고, forEach()는 최종 연산임)
customerList.stream().map(c->c.getName()).forEach(s->System.out.println(s));




6. 스트림 활용

  • 정수 자료에 대한 여러 가지 연산 예
public class IntArrayStreamTest {

	public static void main(String[] args) {
		int[] arr = {1,2,3,4,5};
		Arrays.stream(arr).forEach(n->System.out.print(n + "\t"));	# 스트림 생성 및 람다식 지정
		System.out.println();
					
		int sum  = Arrays.stream(arr).sum();
		System.out.println("sum: " + sum);
		
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		list.add(5);
		int sum2 = list.stream().mapToInt(n->n.intValue()).sum();	# Integer 객체 int형으로 변환
		System.out.println(sum2);
	}

}



Section 2. reduce() 메서드

1. reduce() 메서드

  • 정의된 연산이 아닌 프로그래머가 직접 구현한 (누적)연산을 적용시킬 수 있는 메서드
  • Stream 의 모든 요소를 소모하며 누적 연산을 수행하는 메서드
T reduce(T identify, BinaryOperator<T> accumulator)	# 첫번 째 매개변수 = 초기값
							# 두번 째 매개변수 = 람다식




2. 직접 람다식을 지정하는 방식

public class ReduceTest {

	public static void main(String[] args) {

		String[] greetings = {"안녕하세요~~~", "hello", "Good morning", "반갑습니다^^"};
		
		System.out.println(Arrays.stream(greetings).reduce("", (s1, s2)-> 
                       {if (s1.getBytes().length >= s2.getBytes().length) return s1;           
           	       else return s2;})); 
	
	}
}




3. BinaryOperator를 구현하여 넘기는 방식

  • BinaryOperator - 2개의 매개변수를 받아 같은 타입의 반환값을 반환하는 표준 함수형 인터페이스
  • apply 메서드를 재정의 해야됨
  • .get()으로 결과를 받아야 함
class CompareString implements BinaryOperator<String>{		# 함수형 인터페이스를 구현

	@Override
	public String apply(String s1, String s2) {
		if (s1.getBytes().length >= s2.getBytes().length) return s1;
		else return s2;
	}
}

public class ReduceTest {

	public static void main(String[] args) {

		String[] greetings = {"안녕하세요~~~", "hello", "Good morning", "반갑습니다^^"};
		
		String str = Arrays.stream(greetings).reduce(new CompareString()).get();	# 함수형 인터페이스를 구현한 클래스를 생성해서 지정해 줌
		System.out.println(str);
		                          
	}
}




4. reduce 메서드 원리

  • 처음에 초기값이 a 매개변수로 지정되고 Stream 의 첫 요소가 b 로 지정됨
  • 그 다음 반환된 결과값이 다시 a로 지정되고 Stream 의 그 다음 요소가 b 로 지정됨
public class ReduceTest {

	public static void main(String[] args) {
		
		int[] arr = new int[5];
	
		arr[0] = 1;
		arr[1] = 2;
		arr[2] = 3;
		arr[3] = 4;
		arr[4] = 5;
		
		System.out.println(Arrays.stream(arr).reduce(0, (a,b)->{
			
			System.out.println(a);
			System.out.println(b);
			return a+b;}));
			                 
	}
}
  • 출력 결과
1
1
2
3
3
6
4
10
5
15

0개의 댓글