220618_인터넷 강의_스트림

창고·2022년 10월 21일
0

티스토리에 저장했던 글을 옮겼습니다.
https://mrcocoball.tistory.com/91

1. 스트림(Stream)

(1) 스트림의 정의와 특성

  • 자료의 대상과 관계없이 동일한 연산을 수행
  • 배열, 컬렉션을 대상으로 연산을 수행 함
  • 일관성 있는 연산으로 자료의 처리를 쉽고 간단하게 함
  • 자료 처리에 대한 추상화가 구현되었다고 함
  • 한번 생성하고 사용한 스트림은 재사용 할 수 없음
    • 자료에 대한 스트림을 생성하여 연산을 수행하면 스트림은 소모됨
    • 다른 연산을 수행하기 위해서는 스트림을 다시 생성해야 함
public class IntArrayStreamTest {

	public static void main(String[] args) {
		
		int[] arr = {1,2,3,4,5};
		
		for (int num : arr) {
			System.out.println(num);
		}
		
		System.out.println("스트림 적용");
		Arrays.stream(arr).forEach(n -> System.out.println(n));
		// Arrays.stream을 통해 IntStream 타입 값 반환 가능,
		// forEach를 통해 arr의 요소를 하나하나 꺼내서 처리를 하는데 그 처리 내용은 n -> System.out.println(n)
		
		IntStream is = Arrays.stream(arr);
		System.out.println("1회차");
		is.forEach(n -> System.out.println(n));
		System.out.println("2회차");
		// is.forEach(n -> System.out.println(n)); 스트림이 소모가 되어 Exception 발생, 스트림 재생성 필요!!

	}
}

  • 스트림 연산은 기존 자료를 변경하지 않으며 자료에 대한 스트림을 생성하면 스트림이 사용하는 메모리 공간은 별도로 생성되므로 연산이 수행되도 기존 자료에 대한 변경은 발생하지 않음

(2) 스트림의 중간 연산, 최종 연산

  • 스트림 연산은 중간 연산과 최종 연산으로 구분 됨
  • 스트림에 대해 중간 연산은 여러 개의 연산이 적용될 수 있지만 최종 연산은 마지막에 한 번만 적용됨
  • 최종연산이 호출되어야 중간 연산에 대한 수행이 이루어 지고 그 결과가 만들어짐
  • 따라서 중간 연산에 대한 결과를 연산 중에 알수 없기에 이를 '지연 연산'이라 함
  • 중간 연산의 예시
    • filter() - 조건에 맞는 요소를 추출
    • map() - 요소를 변환
    • sorted() - 정렬함
public class ArrayListStreamTest {

	public static void main(String[] args) {
		
		List<String> sList = new ArrayList<String>();
		sList.add("리코");
		sList.add("마리");
		sList.add("요시코");
		
		Stream<String> stream = sList.stream();
		stream.forEach(s -> System.out.println(s));
		
		sList.stream().sorted().forEach(s -> System.out.print(s + "\t")); // 요소를 정렬해서 출력
		System.out.println();
		sList.stream().map(s->s.length()).forEach(n -> System.out.print(n + "\t")); // 문자 길이를 출력
		System.out.println();
		sList.stream().filter(s->s.length()>=3).forEach(s -> System.out.print(s + "\t")); // 문자 길이가 3 이상인 요소 출력
		

	}

}

2. 연산 수행에 대한 구현을 할 수 있는 reduce() 연산

(1) reduce() 연산의 정의

  • 정의된 연산이 아닌, 프로그래머가 직접 구현한 연산을 적용
T reduce (T identify, BinaryOperator<T> accumlator)

T reduce (T 초기값, BinaryOperator<T> accumlator)
  • 최종 연산으로 스트림의 요소를 소모하여 연산을 수행
  • 배열의 모든 요소의 합을 구하는 reduce() 연산 구현 예시
Arrays.stream(arr).reduce(0, (a,b) -> a+b));
  • reduce() 메소드의 두 번째 요소로 전달되는 람다식에 따라 다양한 기능 수행 가능
  • 람다식을 직접 구현하거나 람다식이 긴 경우 BinaryOperator를 구현한 클래스를 사용

(2) BinaryOperator를 구현, 배열에 여러 문자열이 있을 때 길이가 가장 긴 문자열 찾기

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", "Goood Morning", "반가워요 참새콘"};
		
		// 직접 람다식 사용
		System.out.println(Arrays.stream(greetings).reduce("", (s1, s2) ->
			{if (s1.getBytes().length >= s2.getBytes().length ) return s1;
			else return s2;}
			));
		
		// BinaryOperator<String> 사용
		String str = Arrays.stream(greetings).reduce(new CompareString()).get();
		System.out.println(str);

	}

}

3. 스트림을 활용한 예제 풀이

  • 시나리오
    • 여행사 패키지 상품 중 18세 이상 100만원, 그 미만은 50만원
    • 고객 세 명이 패키지 여행을 떠날 떄 비용 계산 및 고객 명단 검색 등에 대한 연산 스트림으로 구현
    • 고객에 대한 클래스를 만들고 ArrayList로 관리
public class TravelCustomer {
	
	private String name;   //이름
	private int age;       //나이
	private int price;     //가격
	
	public TravelCustomer(String name, int age, int price) {
		this.name = name;
		this.age = age;
		this.price = price;
	}

	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}

	public int getPrice() {
		return price;
	}
	
    	public void setName(String name) {
		this.name = name;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public void setPrice(int price) {
		this.price = price;
	}

	public String toString() {
		return "name: " + name + " age: " + age + " price: " + price; 
	}

}
public class TravelTest {

	public static void main(String[] args) {
		
		TravelCustomer mari = new TravelCustomer("마리", 19, 100);
		TravelCustomer rico = new TravelCustomer("리코", 18, 100);
		TravelCustomer yoshiko = new TravelCustomer("요시코", 17, 50);
		
		List<TravelCustomer> cList = new ArrayList<TravelCustomer>();
		cList.add(mari);
		cList.add(rico);
		cList.add(yoshiko);
		
		System.out.println("고객 명단을 추가된 순서대로 출력");
		// 이름(getName)만 가져와서(map) 출력
		cList.stream().map(c->c.getName()).forEach(s -> System.out.println(s));
		
		System.out.println("총 여행 비용");
		// mapToInt()로 비용(getPrice)를 int화 한 후 sum 한 것을 출력
		System.out.println(cList.stream().mapToInt(c->c.getPrice()).sum());
		
		System.out.println("18세 이상 고객 명단을 정렬하여 출력");
		// 나이(getAge) 가 18 이상인 요소를 필터링(filter)한 후 이름(getName)을 가져온 뒤 정렬(sorted) 하여 출력
		cList.stream().filter(c->c.getAge() >= 18).map(c->c.getName()).sorted().forEach(s-> System.out.println(s));
		

	}

}

profile
공부했던 내용들을 모아둔 창고입니다.

0개의 댓글