Stream[Java]

SnowCat·2023년 6월 9일
0

Java - Language

목록 보기
17/17
post-thumbnail

Stream API

  • 스트림은 내부 반복을 통해 작업을 수행함
  • 스트림은 컬렉션과 달리 단 한번만 사용가능하며, 원본 데이터에 영향을 주지 않음
  • 스트림은 병렬 처리가 간편하며, 내부적으로 지연 연산을 통해 성능을 최적화함

스트림의 생성

  • 스트림 API는 컬렉션, 배열, 가변 매개변수, 지정된 범위의 정수, 특정 타입의 난수, 람다식, 파일, 빈 스트림에서 생성할 수 있음
// 컬렉션
ArrayList<Integer> list = new ArrayList<Integer>();

list.add(4);
list.add(2);
list.add(3);
list.add(1);

Stream<Integer> stream = list.stream();
stream.forEach(System.out::println);

// 배열
String[] arr = new String[]{4, 2, 3, 1};

Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(e -> System.out.print(e + " "));
System.out.println();

Stream<String> stream2 = Arrays.stream(arr, 1, 3); //인덱스 범위 지정
stream2.forEach(e -> System.out.print(e + " "));

// 가변 매개변수
Stream<Double> stream = Stream.of(4.2, 2.5, 3.1, 1.9);
stream.forEach(System.out::println);

// 정수 범위
IntStream stream1 = IntStream.range(1, 4);
stream1.forEach(e -> System.out.print(e + " ")); // 1 2 3
System.out.println();

IntStream stream2 = IntStream.rangeClosed(1, 4);
stream2.forEach(e -> System.out.print(e + " ")); // 1 2 3 4 

// 난수
// 특정 타입의 난수로 이루어진 스트림 생성
IntStream stream = new Random().ints(4); // 4개의 long 범위의 난수 생성
stream.forEach(System.out::println);

// 람다식
IntStream stream = Stream.iterate(2, n -> n + 2); // 2, 4, 6, 8, 10, ...

// 파일
String<String> stream = Files.lines(Path path); // 줄단위로 stream의 데이터가 됨

// 빈 스트림
Stream<Object> stream = Stream.empty();
System.out.println(stream.count()); // 0

스트림의 중개 연산

  • 스트림 API에 생성된 스트림은 중개 연산을 통해 또 다른 스트림으로 변환될 수 있음
  • 중개 연산은 중복해서 사용 가능
  • 대표적인 중개 연산 메서드로는 filter, distinct, map, flatMap, limit, skip, sorted, peek가 있음
IntStream stream1 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
IntStream stream2 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);

// distinct 중복제거
stream1.distinct().forEach(e -> System.out.print(e + " ")); // 7 5 2 1 3 4 6
System.out.println();

// 조건에 따른 필터링
stream2.filter(n -> n % 2 != 0).forEach(e -> System.out.print(e + " ")); // 7 5 5 1 3 5


Stream<String> stream = Stream.of("HTML", "CSS", "JAVA", "JAVASCRIPT");

// 스트림의 변환
/*
4
3
4 
10
*/
stream.map(s -> s.length()).forEach(System.out::println); 

// 배열의 평면화
String[] arr = {"I study hard", "You study JAVA", "I am hungry"};

Stream<String> stream = Arrays.stream(arr);
stream.flatMap(s -> Stream.of(s.split(" +"))).forEach(System.out::println);


// 배열의 스킵과 개수제한
IntStream stream1 = IntStream.range(0, 10);
IntStream stream2 = IntStream.range(0, 10);

stream1.skip(4).forEach(n -> System.out.print(n + " ")); // 4 5 7 8 9
System.out.println();


stream2.limit(5).forEach(n -> System.out.print(n + " ")); // 0 1 2 3 4
System.out.println();

// 정렬
Stream<String> stream1 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
Stream<String> stream2 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");

// CSS HTML JAVA JAVASCRIPT 
stream1.sorted().forEach(s -> System.out.print(s + " "));
System.out.println();

// JAVASCRIPT JAVA HTML CSS
stream2.sorted(Comparator.reverseOrder()).forEach(s -> System.out.print(s + " "));

// peek -> 연산 중간의 결과값 확인
IntStream stream = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);

stream.peek(s -> System.out.println("원본 스트림 : " + s))
    .skip(2)
    .peek(s -> System.out.println("skip(2) 실행 후 : " + s))
    .limit(5)
    .peek(s -> System.out.println("limit(5) 실행 후 : " + s))
    .sorted()
    .peek(s -> System.out.println("sorted() 실행 후 : " + s))
    .forEach(n -> System.out.println(n));

스트림의 최종 연산

  • 스트림에선는 맨 마지막에 최종 연산을 통해 결과를 표시함
  • 스트림의 최종 연산으로는 forEach, reduce, findFirst, findAny, anyMatch, allMatch, noneMatch, count, min, max, sum, average, collect가 있음
  • 최종 연산을 수행한 스트림은 더 사용할 수 없음
//forEach
Stream<String> stream = Stream.of(4, 2, 3, 1);
stream.forEach(System.out::print); // 4231
System.out.println();

// reduce
Stream<String> stream1 = Stream.of(4, 2, 3, 1);
Stream<String> stream1 = Stream.of(4, 2, 3, 1);
Optional<String> result1 = stream1.reduce((s1, s2) -> s1 + s2);
result1.ifPresent(System.out::println); // 10

String result2 = stream2.reduce(15, (s1, s2) -> s1 + s2);
System.out.println(result2); // 25

// findFirst, findAny
IntStream stream1 = IntStream.of(4, 2, 7, 3, 5, 1, 6);
IntStream stream2 = IntStream.of(4, 2, 7, 3, 5, 1, 6);

OptionalInt result1 = stream1.sorted().findFirst();
System.out.println(result1.getAsInt()); // 1

OptionalInt result2 = stream2.sorted().findAny();
System.out.println(result2.getAsInt()); // 1

// anyMatch, allMatch
IntStream stream1 = IntStream.of(30, 90, 70, 10);
IntStream stream2 = IntStream.of(30, 90, 70, 10);

System.out.println(stream1.anyMatch(n -> n > 80)); // true
System.out.println(stream2.allMatch(n -> n > 80)); // false

// count, max
IntStream stream1 = IntStream.of(30, 90, 70, 10);
IntStream stream2 = IntStream.of(30, 90, 70, 10);

System.out.println(stream1.count()); // 4
System.out.println(stream2.max().getAsInt()); // 90

// sum average
IntStream stream1 = IntStream.of(30, 90, 70, 10);
DoubleStream stream2 = DoubleStream.of(30.3, 90.9, 70.7, 10.1);

System.out.println(stream1.sum()); // 200
System.out.println(stream2.average().getAsDouble()); // 50.5

Optional

  • Optional 클래스는 임의의 객체를 포장해주는 레퍼 클래스로, null 문제를 해결할 수 있음
  • of() 메서드나 ofNullable 메서드를 사용해 Optional 객체를 생성가능
    of 메서드로 생성한 Optional 메서드는 null이 저장되면 예외가 발생하기 떄문에 null이 될 가능성이 있으면 ofNullable 메서드 사용
Optional<String> opt = Optional.ofNullable("Optional");
if(opt.isPresent()) {
    System.out.println(opt.get());
}
  • 만약 기본 타입에서 Optional 클래스를 사용하고 싶으면 OptionalInt, OptionalLong, OptionalDouble을 사용 가능
IntStream stream = IntStream.of(4, 2, 1, 3);
OptionalInt result = stream.findFirst();

System.out.println(result.getAsInt());
profile
냐아아아아아아아아앙

0개의 댓글