[JAVA] chapter 14 람다와 스트림 - 2

WOOK JONG KIM·2022년 10월 4일

자바의 정석

목록 보기
21/25
post-thumbnail

ch14-15~16 Stream의 특징

기존엔 컬렉션이나 배열에 데이터를 담고 원하는 데이터를 얻기 위해 for문 이나 Iterator 이용

또한 데이터 소스마다 다른 방식(List -> Collections.sort() , Array -> Arrays.sort())

이런 문제를 해결하기 위해 Stream 사용 (컬렉션(List,Map,Set) 이나 배열에 만들수 있다)
-> Stream 만들면 똑같은 방법으로 작업을 처리한다!

데이터 소스를 추상화(데이터 소스가 무엇이든 간에 같은 방법으로 다룸)

데이터를 다루는데 자주 사용되는 메서드들을 정의

List<Integer> list = Arrays.asList(1,2,3,4,5);

// 스트림 생성
// Collection에 stream() 메서드 호출
Stream<Integer> intStream = list.stream();

Stream<String> strStream = Stream.of(new String[] { "a", "b", "c"}); // 배열
Stream<Integer> evenStream = Stream.iterate(0, n -> n + 2); // 0,2,4,6...
Stream<Double> randomStream = Stream.generate(Math::random); // 람다식
IntStream intStream = new Random.ints(5); // 난수스트림 (크키가 5)

스트림 연산 활용

  1. 스트림 만들기
  2. 중간연산(0~n번) : 연산결과가 스트림인 연산
  3. 최종연산(0~1번) : 스트림의 요소 소모, 단 한번만 적용 가능
// 중간 연산 3번, 최종 연산 1번
stream.distinct().limit(5),sorted().forEach(System.in::println)

String[] strArr = {"dd", "aaa", "CC", "cc", "b" };
Stream<String> stream = Stream.of(strArr) // 문자열 배열이 소스인 스트림
Stream<String> filteredStream = stream.filter(); // 걸러내기(중간 연산)
Stream<String> distinctedStream = stream.distinct(); // 중복제거( 중간 연산)
Stream<String> sortedStream = stream.sort(); // 정렬(중간 연산)
Stream<String> limitedStream = stream.limit(5) // 스트림 자르기(중간 연산)
int total = stream.count(); // 최종 연산

스트림의 특징

  1. 스트림은 데이터 소스(원본)로부터 데이터를 읽기만할 뿐 변경하지 않는다(Read Only)
List<Integer> list = Arrays.asList(3,1,5,4,2);
// 리스트를 정렬 해서 새로운 리스트에 저장
List<Integer> sortedList = list.stream().sorted()
							.collect(Collectors.toList());
System.out.println(list); // [3,1,5,4,2]
System.out.println(sortedList); // [1,2,3,4,5]
  1. 스트림은 Iterator처럼 일회용이다(필요하면 다시 스트림을 생성해야 함)
strStream.forEach(System.out::println); // 모든 요소를 화면에 출력(최종 연산) : 요소를 소모
int numOfstr = strStream.count(); // 에러, 스트림이 이미 닫혔음.
  1. 최종 연산 전까지 중간연산이 수행되지 않는다 - 지연된 연산
// 코드 자체만 보면 무한 스트림에서 밑과 같은 중간 연산을 한다는 것은 말이 안되지만 
// 지연된 연산으로 인해 가능
IntStream intStream = new Random().ints(1,46) //1~45 범위의 무한 스트림
intStream.distinct().limit(6).sorted() // 중간 연산
		.foreach(i -> System.out.print(i + ",")); // 최종 연산
  1. 스트림은 작업을 내부 반복으로 처리

  1. 스트림의 작업을 병렬로 처리하기 쉬움 - 병렬스트림

즉 멀티쓰레드로 처리

// 병렬로 안할려면 sequential() : 기본 -> parallel()호출 취소 시에만 사용
// 큰 작업 빠르게 처리하게 할시 사용!

Stream<String> strSTream = Stream.of("dd", "aaa", "CC", "cc", "b") ;
int sum = strStream.parallel() // 병렬 스트림으로 전환(속성만 변경) -> 새로운 스트림 생성 X
			.mapToInt(s -> s.length()).sum(); // 모든 문자열의 길이의 합
  1. 기본형 스트림 - IntStream, LongStream, DoubleStream
  • 오토박싱 & 언박싱의 비효율이 제거됨(String< Integer> 대신 IntStream 사용)
  • 숫자와 관련된 유용한 메서드를 Stream< T > 보다 더 많이 제공

ch14-17~22 Stream 만들기

컬랙션으로 부터 만들기(stream)

Collection인터페이스의 stream() 메서드로 컬렉션을 스트림으로 변환
-> List,set등에서 사용 가능하다

Stream<E> stream() 
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> intStream = list.stream(); // List를 스트림으로 변환

// 모든 요소 출력
intStream.forEach(System.out::print); // 12345
intStream.forEach(System.out::print); // 에러, 스트림이 이미 닫힘

배열로 부터 만들기(Stream.of)

  • 객체 배열로 부터 스트림 생성하기
Stream<T> Stream.of(T...values) // 가변 인자
Stream<T> Stream.of(T[])
Stream<T> Arrays.stream(T[])

// 일부분으로 스트림 만들기
Stream<T> Arrays.stream(T[] array, int startInclusive, int endExclusive)
  • 기본형 배열로부터 스트림 생성하기
// LongStream, DoubleStream 들도 존재
IntStream IntSTream.of(int.. values)
IntStream IntSTream.of(int[])
IntStream Arrays.stream(int[])
IntStream Arrays.stream(int[] array, int startInclusive, int endExclusive)

IntStream은 숫자인지 알기에 count()외에도 sum,average 같은 기능 제공

Stream< Integer > 즉 Stream< T >는 숫자외에도 여러 타입의 스트림이 가능해야하므로 숫자 스트림에만 사용할 수 있는 sum(), average()를 넣지 않은 것!

난수(임의의 수) 스트림 만들기

Integer.MIN_VALUE <= ints() <= Integer.MAX_VALUE
Long.MIN_VALUE <= longs() <= Long.MAX_VALUE
0.0 <= doubles() < 1.0

//무한 스트림 생성
IntStream ints(int begin, int end)
LongStream longs(long begin, long end)
DoubleStream doubles(double begin, double end)

// 유한 스트림 생성
IntStream ints(long StreamSize, int begin, int end)
LongStream longs(long StreamSize, long begin, long end)
DoubleStream doubles(long StreamSize, double begin, double end)
IntStream intStream = new Random().ints(); // 무한 스트림
intStream.limit(5).forEach(System.out::println); // 5개 요소 출력

IntStream intStream = new Random().ints(5) // 크기가 5인 난수 스트림 반환

특정 범위의 정수로 스트림 만들기

IntStream IntStream.range(int begin, int end)
// 끝 범위 포함
IntStream IntStream.rangeClosed(int begin, int end)

람다식으로 스트림 만들기(iterate, generate)

// 이전 요소의 종속적 , seed -> 초기 값
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
// 이전 요소에 독립적
static <T> Stream<T> generate(Supplier<T> s)
Stream<Integer> evenStream = Stream.iterate(0, n-> n+2); // 0,2,4,6 ...

// generate 는 seed 사용 X
Stream<Double> randomStream = Stream.generate(Math::random);

// 기본형 스트림 타입의 참조변수로 다룰 수 없다
// 굳이 바꾸겠다면 mapToInt 메서드로 변환하자
IntStream evenStream = Stream.iterate(0,n->n+2); //에러

파일을 소스로 스트림 생성

Stream<Path> Files.list(Path dir) // Path 파일 또는 디렉토리

// 파일 단위 라인 단위로 읽기
Stream<String> Files.lines(Path path)
Stream<String> Files.lines(Path path, Charset cs)
Stream<String> lines()

ch14-24~34 스트림의 중간연산

중간 연산 종류

최종 연산 종류

skip(), limit()

스트림의 일부를 잘라낼 때 사용

Stream<T> skip(long n) // 앞에서 부터 n개 건너뛰기
Stream<T> limit(long maxSize) //Maxsize 이후의 요소는 잘라냄
IntStream intSteram = IntStream.rangeClosed(1,10); // 1~10 요소를 가진 스트림
intStream.skip(3).limit(5).forEach(System.out::print); // 45678

filter(), distinct()

스트림의 요소 제거 할 때 사용

Stream<T> filter(Predicate<? super T> predicate) // 조건의 맞지 않는 요소 제거
Stream<T> distinct() // 중복 요소 제거
IntStream intStream = IntStream.of(1,2,2,3,3,3,4,5,5,6);
intStream.distinct().forEach(System.out::print); //123456

IntStream intStream = IntStream.rangeClosed(1,10); // 1~10
intStream.filter(i->i%2==0).forEach(System.out::print); // 246810

sorted()

스트림 정렬 시 사용

Stream<T> sorted()
Stream<T> sorted(Comparator<? super T> comparator)

Comparator()

Comparator의 comparing()으로 정렬 기준을 제공

// 반환 타입이 comparator여서 반환된 Comparator.comparing을 sorted의 인자로 사용

comparing(Function<T, U> keyExtractor)
comparing(Function<T, U> keyExtractor, Comparator<U> keyComparator)
// 반을 기준으로 정렬할 시
// () -> s.getBan();
studentStream.sorted(Comparator.comparing(Student::getBan)
					.forEach(System.out::println);

추가 정렬 기준을 제공할때는 thenComparing 사용

map()

스트림의 요소에 저장된 값 중에서 원하는 필드만 뽑아내거나 특정 형태로 변환해야 할 때

// 매개변수로 T타입을 R타입으로 변환하는 함수를 지정
Stream<R> map<Function<? super T, ? extends R> mapper)
Stream<File> fileStream = Stream.of(new File("Ex1.java"), new File("Ex1")
new File("Ex1.bak"), new File("Ex2.java"), new File("Ex1.txt"));

// 스트림의 모든 파일의 이름을 출력
// getName을 통해 문자열 얻음. file -> String
Stream<String> filenameStream = fileStream.map(File::getName);
filenameStream.forEach(System.out :: println);
// 파일 확장자를 중복 없이 대문자로 뽑아내기
fileStream.map (File::getName)
	.filter(s->s.indexOf('.') != -1)
    // 확장자 이름 뽑아내기
    .map(s->s.substring(s.indexOf('.'+1))
    .map(String::toUpperCase)
    .distinct() 
    .forEach(System.out::print); // JAVABAKTXT

peek()

스트림의 요소를 소비하지 않고 엿보기 -> 디버깅시 자주 사용

Stream<T> peek(Consumer <? super T> action) // 중간연산
void forEach(Consumer<? super T> action) // 최종연산
fileStream.map(File::getName)
	.filter(s-> s.indexOf(".")!= -1)
    .peek(s->System.out.printf("filename=%s%n", s))
    .map(s-> s.substring(s.indexOf('.')+1))
    .peek(s->System.out.printf("extension=%s%n", s))
    .forEach(System.out::println);

flatMap()

스트림의 스트림을 스트림으로 변환

// String 배열 담는 스트림
Stream<String []> strArrStrm = Stream.of(new String[] { "abc", "def", "ghi"},
new String[]{"ABC", "GHI", "JKLMN"});
//Stream의 Stream, map을 사용시
//(arr) -> Arrays.stream() // stream은 스태틱 메서드
Stream<Stream<String>> strStrStrm = strArrStrm.map(Arrays::stream)

// 문자열의 배열의 스트림을 문자열 스트림으로 변환
Stream<String> strStrStrm = strArrStrm.flatMap(Arrays::stream);

package ch14;

import java.util.*;
import java.util.stream.*;

public class Ex14_7 {

	public static void main(String[] args) {
		Stream<String []> strArrStrm = Stream.of(
				new String[] { "abc", "def", "jkl"},
				new String[] {"ABC", "GHI", "JKL"}
				);
	
		Stream<String> strStrm = strArrStrm.flatMap(Arrays::stream);
		
		strStrm.map(String::toLowerCase)
			.distinct()
			.sorted()
			.forEach(System.out::println);
		System.out.println();
		
		String[] lineArr = {
				"Believe or not It is true",
				"Do or do not There is no try",
		};
		
		Stream<String> lineStream = Arrays.stream(lineArr);
		// + 정규식 -> 하나 이상의공백.
		lineStream.flatMap(line -> Stream.of(line.split(" +")))
			.map(String::toLowerCase)
			.distinct()
			.sorted()
			.forEach(System.out::println);
		System.out.println();

	}
}
profile
Journey for Backend Developer

0개의 댓글