Stream이란


Java8부터 지원하는 Stream은 다양한 데이터 소스(컬렉션, 배열 등)의 요소들을 하나씩 참조하며 반복적인 처리를 가능케 하여 표준화된 방법으로 다룰 수 있게 해준다. 이러한 Stream을 이용한다면 불필요한 for문과 그 안에서 이루어지는 if문등의 분기 처리를 쓰지 않고도 깔끔하고 직관적인 코드로 변형할 수 있다.

 

Stream의 특징


  • Stream은 원본데이터로부터 데이터를 읽기만 할 뿐, 원본 데이터 자체를 변경하지 않는다.
  • Stream은 일회용이며 한 번 사용하면 닫혀서 재사용이 불가능하다. 필요하다면 정렬된 결과를 컬렉션이나 배열에 담아 반환할 수 있다.
  • Stream은 최종 연산 전까지 중간연산이 수행되지 않는 지연된 연산을 수행한다.
  • Stream은 작업을 내부 반복으로 처리한다.

 

Stream의 구조


 

1. Stream 생성

2. 중개연산  : 연산 결과가 스트림인 연산 (0 ~ n번 사용 가능)

3. 최종연산 : 연산결과가 스트림이 아닌 연산 (0~ 1번 사용 가능)

 

 Stream 생성


  • Collection인터페이스의 stream()으로 Stream생성
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> intStream = list.stream();
intStream.forEach(System.out::print) //1 2 3 4 5
  • 배열로 Stream 생성
Stream<String> strStream = Stream.of("a", "b", "c"); //가변인자
Stream<String> strStream = Stream.of(new String[]{"a", "b", "c"});
Stream<String> strStream = Arrays.stream(new String[]{"a", "b", "c"});
Stream<String> strStream = Arrays.stream(new String[]{"a", "b", "c"}, 0, 3);

IntStream intStream = Arrays.stream(new int[]{1,2,3,4,5});
Stream<Integer> integerStream = Arrays.stream(new Integer[]{1,2,3,4,5});

//기본형 Stream이며 더 많은 기능을 사용할 수 있음
System.out.println(intStream.sum());
System.out.println(intStream.count());
System.out.println(intStream.average());
  • 난수 Stream 생성
IntStream intStream = new Random().ints(); //출력할 시 중간연산자limit으로 잘라줘야됨
IntStream intStream = new Random().ints(5); //5개의 난수 생성
IntStream intStream = new Random().ints(5, 1, 10); //1~10 사이의 5개의 난수 생성
  • 람다식으로 Stream 생성
//iterate()는 초기값과 이전 요소를 사용해서 다음 요소를 계산한다.
//iterate(초깃값(이전요소), 람다식(UnaryOperator))
Stream<Integer> intStream = Stream.iterate(0, n -> n + 2);
intStream.limit(5).forEach(System.out::println); //0, 2, 4, 6, 8

//generate()는 초기값과 이전요소를 사용하지 않는다.
//generate(람다식(Supplier))
Stream<Integer> oneStream = Stream.generate(() -> 1);
oneStream.limit(5).forEach(System.out::print);  // 1, 1, 1, 1, 1
  • 파일로 Stream 생성
//path로 지정된 경로의 폴더의 파일을 Stream으로 변환해줌
Stream<Path> Files.list(Path dir)

//path로 지정된 경로의 파일의 내용을 줄단위로 읽어서 Stream으로 변환해줌
Stream<String> Files.lines(Path path)

 

중간연산


  • skip(long n) : 앞에서부터 n개 건너뛰기
IntStream intStream = IntStream.rangeClosed(1, 10); //1,2,3,4,5,6,7,8,9,10
intStream.skip(3).forEach(System.out::print); //4,5,6,7,8,9,10
  • limit(long maxSize) : maxSize 이후의 요소는 잘라냄
IntStream intStream = IntStream.rangeClosed(1, 10); //1,2,3,4,5,6,7,8,9,10
intStream.limit(5).forEach(System.out::print); //1,2,3,4,5
  • filter(조건식) : 조건식에 맞지 않는 요소 제거
IntStream intStream = IntStream.rangeClosed(1, 10); //1,2,3,4,5,6,7,8,9,10
intStream.filter(i->i%2==0).forEach(System.out::print); //2,4,6,8,10
  • distinct() : 중복제거
IntStream intStream = IntStream.of(1, 2, 3, 3, 4, 5, 5, 6, 7);
intStream.distinct().forEach(System.out::print); //1, 2, 3, 4, 5 ,6, 7
  • sorted() : 스트림 요소를 기본 정렬
//기본정렬
Stream<String> strStream = Arrays.stream(new String[]{"a","a","a","b","c","c","C","C","d","d"});
strStream.sorted().forEach(System.out::print);; //CCaaabccdd

//기본정렬의 역순
Stream<String> strStream = Arrays.stream(new String[]{"a","a","a","b","c","c","C","C","d","d"});
strStream.sorted(Comparator.reverseOrder()).forEach(System.out::print);; //ddccbaaaCC

//기본정렬(대소문자 구분 없음)
Stream<String> strStream = Arrays.stream(new String[]{"a","a","a","b","c","c","C","C","d","d"});
strStream.sorted(String.CASE_INSENSITIVE_ORDER).forEach(System.out::print); //aaabccCCdd
  • map() : 스트림의 요소 변화하기
Stream<File> fileStream = Arrays.stream(new File[]{new File("Ex1.java"),new File("Ex2.java"),new File("Ex3.txt"),new File("Ex4.bak")});

fileStream.map(File::getName) //Stream<File>을 Stream<String>으로 변환
        .map(s -> s.substring(s.indexOf('.')+1)) //확장자만 추출
        .map(String::toUpperCase) //확장자를 대문자로 변환
        .distinct() //중복제거
        .forEach(System.out::print);
  • flatMap() : 스트림의 스트림을 스트림으로 변환
Stream<String[]> strArrStream = Stream.of(new String[]{"abc","def","ghi"}, new String[]{"jkl","mno","pqr"});

strArrStream
	.flatMap(Arrays::stream)
	.forEach(System.out::print); //abcdefghijklmnopqr
    

//일반적으로 String[] 배열을 Stream으로 변환 하게 되면 Stream<Stream<String>>형태로 변환된다.
/*

strArrStream
    .map(Arrays::stream)
    .forEach(System.out::print);  

출력:java.util.stream.ReferencePipeline$Head@b684286java.util.stream.ReferencePipeline$Head@880ec60

*/

 

최종연산


  • forEach(), forEachOrdered() : 스트림의 모든 요소에 지정된 수업을 수행
//직렬스트림
IntStream.range(1, 10).forEach(System.out::print); //123456789

//병렬스트림(병렬스레드로 처리하기 때문에 순서보장이 안됨)
IntStream.range(1, 10).parallel().forEach(System.out::print); //657891423

//병렬스트림인 경우 forEachOrdered를 사용하면 순서 보장이 됨
IntStream.range(1, 10).parallel().forEachOrdered(System.out::print);

 

  • allMatch(), anyMatch(), noneMatch() : 조건 검사
//배열의 모든 숫자가 10이하 이면 true
boolean b = Arrays.stream(new int[]{1,6,9,10,8}).allMatch(i -> i <= 10);
System.out.println(b);

//배열의 모든 숫자 중에 10보다 큰 숫자가 있으면 true
boolean b2 = Arrays.stream(new int[]{1,6,9,10,8}).anyMatch(i -> i > 10);
System.out.println(b2);

//배열의 모든 숫자 중에 10보다 큰 숫자가 없으면 true
boolean b3 = Arrays.stream(new int[]{1,6,9,10,8}).noneMatch(i -> i > 10);
System.out.println(b3);

 

//배열의 모든 숫자 중에 5보다 큰 첫번째 숫자
Optional<Integer> result = Arrays.stream(new Integer[]{1,6,9,10,8}).filter(i -> i > 5).findFirst();
System.out.println(result.get()); //6

//배열의 모든 숫자 중에 5보다 큰 첫번째 숫자(병렬 처리이기 때문에 순서 보장이 안됨)
Optional<Integer> result2 = Arrays.stream(new Integer[]{1,6,9,10,8}).filter(i -> i > 5).findAny();
System.out.println(result2.get()); //6

 

  • reduce() : 스트림의 요소를 하나씩 줄여가며 누적 연산 수행
//reduce(int identity, IntBinaryOperator op)
//reduce(초깃값, 작업할 수행)
//reduce(작업할 수행)과 같이 초깃값을 주지 않으면 null이 반환 될 수 도있기 때문에 Optional<Integer>로 반환이 된다
        
//배열의 요소가 몇개있는지
int cnt = Arrays.stream(new Integer[]{1,6,9,10,8}).reduce(0, (a,b) -> a + 1);
System.out.println(cnt); //5

/*
int cnt = 0;
for(int a : new int[]{1,6,9,10,8}) {
	cnt += 1;
}
System.out.println(cnt);
*/

//배열의 모든 요소의 합
int sum = Arrays.stream(new Integer[]{1,6,9,10,8}).reduce(0, (a,b) -> a + b);
System.out.println(sum);

/*
int sum = 0;
for(int a : new int[]{1,6,9,10,8}) {
     sum += a;
}
System.out.println(sum);
*/

//배열의 모든 요소 중 제일 큰 값
int max = Arrays.stream(new Integer[]{1,6,9,10,8}).reduce(Integer.MIN_VALUE, (a,b) -> a > b ? a : b);
System.out.println(max);

//배열의 모든 요소 중 제일 작은 값
int min = Arrays.stream(new Integer[]{1,6,9,10,8}).reduce(Integer.MAX_VALUE, (a,b) -> a < b ? a : b);
System.out.println(min);

 

'JAVA' 카테고리의 다른 글

String.valueOf() 와 Integer.toString() 의 차이  (0) 2024.05.01
String, StringBuffer, StringBuilder의 차이점  (0) 2024.04.24
람다식(Lambda Expression)  (0) 2022.07.17
enum  (0) 2022.01.16
JAVA 실행과정 & JVM  (0) 2022.01.09

+ Recent posts