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 + " "));
System.out.println();
IntStream stream2 = IntStream.rangeClosed(1, 4);
stream2.forEach(e -> System.out.print(e + " "));
IntStream stream = new Random().ints(4);
stream.forEach(System.out::println);
IntStream stream = Stream.iterate(2, n -> n + 2);
String<String> stream = Files.lines(Path path);
Stream<Object> stream = Stream.empty();
System.out.println(stream.count());
스트림의 중개 연산
- 스트림 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);
stream1.distinct().forEach(e -> System.out.print(e + " "));
System.out.println();
stream2.filter(n -> n % 2 != 0).forEach(e -> System.out.print(e + " "));
Stream<String> stream = Stream.of("HTML", "CSS", "JAVA", "JAVASCRIPT");
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 + " "));
System.out.println();
stream2.limit(5).forEach(n -> System.out.print(n + " "));
System.out.println();
Stream<String> stream1 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
Stream<String> stream2 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
stream1.sorted().forEach(s -> System.out.print(s + " "));
System.out.println();
stream2.sorted(Comparator.reverseOrder()).forEach(s -> System.out.print(s + " "));
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가 있음
- 최종 연산을 수행한 스트림은 더 사용할 수 없음
Stream<String> stream = Stream.of(4, 2, 3, 1);
stream.forEach(System.out::print);
System.out.println();
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);
String result2 = stream2.reduce(15, (s1, s2) -> s1 + s2);
System.out.println(result2);
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());
OptionalInt result2 = stream2.sorted().findAny();
System.out.println(result2.getAsInt());
IntStream stream1 = IntStream.of(30, 90, 70, 10);
IntStream stream2 = IntStream.of(30, 90, 70, 10);
System.out.println(stream1.anyMatch(n -> n > 80));
System.out.println(stream2.allMatch(n -> n > 80));
IntStream stream1 = IntStream.of(30, 90, 70, 10);
IntStream stream2 = IntStream.of(30, 90, 70, 10);
System.out.println(stream1.count());
System.out.println(stream2.max().getAsInt());
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());
System.out.println(stream2.average().getAsDouble());
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());