ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Part2] Java8 In action - Chapter5 - 3
    Java8 In Action 2022. 7. 29. 13:37
    반응형

    해당 내용은 Java8 In Action 책을 요약 및 정리한 내용입니다.

    좀 더 자세히 알고 싶으신 분들은 책을 사서 읽어보심을 추천드립니다.!

    5.5 실전 연습

    Entity

    Trader.java

    package Part2.Chapter5.Chapter5_5_5.entity;
    
    public class Trader {
        private final String name;
        private final String city;
    
        public Trader(String name, String city) {
            this.name = name;
            this.city = city;
        }
    
        public String getName() {
            return this.name;
        }
    
        public String getCity() {
            return this.city;
        }
    
        public String toString() {
            return "Trader : " + this.name + " in " + this.city;
        }
    }

    Transaction.java

    package Part2.Chapter5.Chapter5_5_5.entity;
    
    public class Transaction {
        private final Trader trader;
        private final int year;
        private final int value;
    
        public Transaction(Trader trader, int year, int value) {
            this.trader = trader;
            this.year = year;
            this.value = value;        
        }
    
        public Trader getTrader() {
            return this.trader; 
        }
    
        public int getYear() {
            return this.year;
        }
    
        public int getValue() {
            return this.value;
        }
    
        public String toString() {
            return "{" + this.trader
                + ", year : " + this.year
                + ", value : " + this.value  
                + "}";
        }
    }

    Main

    package Part2.Chapter5.Chapter5_5_5;
    
    import java.util.Arrays;
    import java.util.Comparator;
    import java.util.List;
    import java.util.stream.Collectors;
    
    import Part2.Chapter5.Chapter5_5_5.entity.Trader;
    import Part2.Chapter5.Chapter5_5_5.entity.Transaction;
    
    /*
     * 5.5 실전 연습
     */
    public class Main_5_5 {
    
        static public void main(String[] args) {
            Trader raoul = new Trader("Raoul", "Cambridge");
            Trader mario = new Trader("Mario", "Milan");
            Trader alan = new Trader("Alan", "Cambridge");
            Trader brian = new Trader("Brian", "Cambridge");
    
            List<Transaction> transactions = Arrays.asList(
                new Transaction(brian, 2011, 300)
                , new Transaction(raoul, 2012, 1000)
                , new Transaction(raoul, 2011, 400)
                , new Transaction(mario, 2012, 700)
                , new Transaction(mario, 2012, 700)        
                , new Transaction(alan, 2012, 950));
    
            // 1. 2011년에 일어난 모든 트랜잭션을 찾아 값을 오른차순으로 정리하시오.
            System.out.println("1. 2011년에 일어난 모든 트랜잭션을 찾아 값을 오른차순으로 정리하시오.");
            transactions.stream()
                .filter((tran) -> tran.getYear() == 2011)
                .sorted((tran1, tran2) -> Integer.compare(tran1.getValue(), tran2.getValue()))
                .collect(Collectors.toList())
                .stream().forEach(tran -> System.out.println(tran.toString()) );
    
            System.out.println("[풀이] 1. 2011년에 일어난 모든 트랜잭션을 찾아 값을 오른차순으로 정리하시오.");
            transactions.stream()
                .filter((tran) -> tran.getYear() == 2011)
                .sorted(Comparator.comparing(Transaction::getValue))
                .collect(Collectors.toList())
                .stream().forEach(tran -> System.out.println(tran.toString()) );
    
            // 2. 거래자가 근무하는 모든 도시를 중복 없이 나열하시오.
            System.out.println("\\n2. 거래자가 근무하는 모든 도시를 중복 없이 나열하시오.");
            transactions.stream()            
                .map((tran) -> tran.getTrader().getCity())
                .distinct()
                .collect(Collectors.toList())
                .stream().forEach(tran -> System.out.println(tran.toString()) );
    
            System.out.println("[풀이] 2. 거래자가 근무하는 모든 도시를 중복 없이 나열하시오.");
            transactions.stream()
                .map(tran -> tran.getTrader().getCity())            
                .collect(Collectors.toSet())
                .stream().forEach(tran -> System.out.println(tran.toString()) );
    
            // 3. 케임브리지(cambridge)에서 근무하는 모든 거래자를 찾아서 이름순으로 정렬하시오.
            System.out.println("\\n3. 케임브리지(cambridge)에서 근무하는 모든 거래자를 찾아서 이름순으로 정렬하시오.");
            transactions.stream()
                .filter(transaction -> "cambridge".equals(transaction.getTrader().getCity().toLowerCase()) )
                .sorted((o1, o2) -> o1.getTrader().getName().compareTo(o2.getTrader().getName()))
                .map(tranName -> tranName.getTrader().getName())
                .distinct()
                .map(traderName -> {
                    return transactions.stream()
                        .filter(tranNameFilter -> tranNameFilter.getTrader().getName().equals(traderName))
                        .sorted(Comparator.comparing(Transaction::getYear).reversed())
                        .limit(1)
                        .collect(Collectors.toList());
                })            
                .collect(Collectors.toList())
                .stream().forEach(System.out::println);
    
            System.out.println("[풀이] 3. 케임브리지(cambridge)에서 근무하는 모든 거래자를 찾아서 이름순으로 정렬하시오.");
            transactions.stream()
                .map(Transaction::getTrader)
                .filter(trader -> "Cambridge".equals(trader.getCity()))
                .distinct()
                .sorted(Comparator.comparing(Trader::getName))
                .collect(Collectors.toList())
                .stream().forEach(tran -> System.out.println(tran.toString()) );
    
            // 4. 모든 거래자의 이름을 알파벳순으로 정렬해서 반환하시오.
            System.out.println("\\n4. 모든 거래자의 이름을 알파벳순으로 정렬해서 반환하시오.");
            transactions.stream()
                .map(tran -> tran.getTrader().getName())
                .distinct()
                .sorted((o1, o2) -> o1.compareTo(o2))
                .map(traderName -> {
                    return transactions.stream()
                        .filter(tranFilter -> traderName.equals(tranFilter.getTrader().getName()))
                        .sorted(Comparator.comparing(Transaction::getYear).reversed())
                        .limit(1)
                        .collect(Collectors.toList());
                })
                .collect(Collectors.toList())
                .forEach(System.out::println);
    
            System.out.println("[풀이-1] 4. 모든 거래자의 이름을 알파벳순으로 정렬해서 반환하시오.");
            System.out.println(transactions.stream()
                .map(tran -> tran.getTrader().getName())
                .distinct()
                .sorted()
                .reduce("", (n1, n2) -> n1 + n2) );
            /*
             * 각 반복 과정에서 모든 문자열을 반복적으로 연결해서 새로운 문자열 객체를 만든다.
             * 따라서 위 코드는 효율성이 부족하다. 이를 해결하기 위해 joining()을 이용하면 된다.
             */
            System.out.println("[풀이-2] 4. 모든 거래자의 이름을 알파벳순으로 정렬해서 반환하시오.");
            System.out.println(transactions.stream()
                .map(tran -> tran.getTrader().getName())
                .distinct()
                .sorted()
                .collect(Collectors.joining()) );        
    
            // 5. 밀라노(milan)에서 거래자가 있는가?
            System.out.println("\\n5. 밀라노(milan)에서 거래자가 있는가?");
            System.out.println(transactions.stream()
                .anyMatch((tran) -> "milan".equals(tran.getTrader().getCity().toLowerCase()) ));
    
            System.out.println("[풀이] 5. 밀라노(milan)에서 거래자가 있는가?");
            System.out.println(transactions.stream()
                .anyMatch((tran) -> "Milan".equals(tran.getTrader().getCity()) ));
    
            // 6. 케임브리지에 거주하는 모든 거래자의 모든 트랜잭션값을 출력하시오.
            System.out.println("\\n6. 케임브리지에 거주하는 모든 거래자의 모든 트랜잭션값을 출력하시오.");
            System.out.println(transactions.stream()
                .filter(tran -> "cambridge".equals(tran.getTrader().getCity().toLowerCase()) )
                .map(tran -> tran.getValue())
                .reduce(0, (tran1, tran2) -> tran1 + tran2));
    
            System.out.println("[풀이] 6. 케임브리지에 거주하는 모든 거래자의 모든 트랜잭션값을 출력하시오.");
            System.out.println(transactions.stream()
                .filter(tran -> "Cambridge".equals(tran.getTrader().getCity()))
                .map(Transaction::getValue)
                .reduce(0, Integer::sum));
    
            // 7. 전체 트랜잭션 중 최대값은 얼마인가?
            System.out.println("\\n7. 전체 트랜잭션 중 최대값은 얼마인가?");
            System.out.println(transactions.stream()
                .map(tran -> tran.getValue())
                .reduce(Integer::max).get() );
    
            System.out.println("[풀이] 7. 전체 트랜잭션 중 최대값은 얼마인가?");
            System.out.println(transactions.stream()
                .map(Transaction::getValue)
                .reduce(Integer::max).get() );
    
            // 8. 전체 트랜잭션 중 최소값은 얼마인가?
            System.out.println("\\n8. 전체 트랜잭션 중 최소값은 얼마인가?");
            System.out.println(transactions.stream()
                .map(tran -> tran.getValue())
                .reduce(Integer::min).get() );
    
            System.out.println("[풀이] 8. 전체 트랜잭션 중 최소값은 얼마인가?");
            System.out.println(transactions.stream()
                .reduce((t1, t2) -> 
                    t1.getValue() < t2.getValue() ? t1 : t2
                ).get() );        
        }
    }

    5.6 숫자형 스트림

    Entity

    Dish.java

    package Part2.Chapter5.Chapter5_5_6.entity;
    
    public class Dish {
        private final String name;
        private final boolean vegetarian;
        private final int calories;
        private Type type;
    
        public Dish(String name, boolean vegetarian, int calories, Type type) {    
            this.name = name;
            this.vegetarian = vegetarian;
            this.calories = calories;
            this.type = type;
        }
    
        public String getName() {
            return this.name;
        }
    
        public int getCalories() {
            return this.calories;
        }
    
        public Type getType() {
            return this.type;
        }
    
        public boolean isVegetarian() {
            return vegetarian;
        }
    
        @Override
        public String toString() {
            return this.name;
        }
    
        public enum Type {
            MEAT, FISH, OTHER
        }
    }

    Main

    package Part2.Chapter5.Chapter5_5_6;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.OptionalInt;
    import java.util.stream.IntStream;
    import java.util.stream.Stream;
    
    import Part2.Chapter5.Chapter5_5_4.entity.Dish;
    
    /*
     * 5.6 숫자형 스트림
     * 
     * int calories = menu.stream()
     *         .map(Dish::getCalories)
     *         .reduce(0, Integer::sum);
     * 
     * 위 코드는 메뉴의 칼로리 합계를 구하는 코드이다.
     * 그러나 사실 위 코드에는 박싱 비용이 숨어있다.
     * 내부적으로 합계를 계산하기 전에 Integer를 기본형으로 언박싱해야 한다.
     * 
     * 숫자 스트림을 효율적으로 처리할 수 있게 기본형 특화 스트림(primitive stream specialzation)을 제공한다. 
     */
    public class Main_5_6 {
    
        public static void main(String[] args) {
            List<Dish> menu = Arrays.asList(
                new Dish("pork", false, 800, Dish.Type.MEAT)    
                , new Dish("beef", false, 700, Dish.Type.MEAT)                
                , new Dish("chicken", false, 400, Dish.Type.MEAT)
                , new Dish("french fries", true, 530, Dish.Type.OTHER)
                , new Dish("rice", true, 350, Dish.Type.OTHER)
                , new Dish("season fruit", true, 120, Dish.Type.OTHER)
                , new Dish("pizza", true, 550, Dish.Type.OTHER)
                , new Dish("prawns", false, 300, Dish.Type.FISH)
                , new Dish("salmon", false, 450, Dish.Type.FISH));
    
            /*
             * 5.6.1 기본형 특화 스트림
             * 
             * 자바 8에서는 3가지 기본형 특화 스트림을 제공한다.
             * 박싱 비용을 피할 수 있도록 'int에 특화된 IntStream', 'double에 특화된 DoubleStream', 'long 요소에 특화된 LongStream'
             * 을 제공한다. 
             * 각각의 인터페이스는 숫자 스트림의 합계를 계산할 수 있는 sum, 최대값 요소를 검색하는 max 같이 자주 사용하는 숫자 관련
             * 리듀싱 연산 수행 메서드를 제공한다.
             * 또한 필요할 때 다시 객체 스트림으로 복원하는 기능도 제공한다.
             * 특화 스트림은 오직 박싱과정에서 일어나는 효율성과 관련 있으며 스트림에 추가 기능을 제공하진 않는다는 사실을 기억하자.          
             */
    
            /*
             * mapToInt 메서드는 각 요리에서 모든 칼로리(Integer 형식)를 추출한 다음에 IntStream을 반환한다.
             * (Stream<Integer>가 아님)
             * 따라서 IntStream 인터페이스에서 제공하는 sum 메서드를 사용할 수 있다.
             * sum 메서드는 스트림이 비어있으면 기본값 0을 반환한다.
             * IntStream은 max, min, average 등 다양한 유틸리티 메서드를 지원한다.
             */
            System.out.println("5.6.1 기본형 특화 스트림 - mapToInt : " + menu.stream()
                .mapToInt(Dish::getCalories)
                .sum());
    
            /*
             * 객체 스트림으로 복원하기
             * 
             * boxed 메서드를 이용하면 특화 스트림을 일반 스트림으로 변환할 수 있다.
             */
            // 스트림을 숫자 스트림으로 변환.
            IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
            System.out.println("[IntStream] 객체 스트림으로 복원하기 : " + intStream);
    
            // 숫자 스트림에서 boxed 메서드를 이용해서 스트림으로 변환.
            Stream<Integer> streamInteger = menu.stream().mapToInt(Dish::getCalories).boxed();
            System.out.println("[Stream<Integer>] 객체 스트림으로 복원하기 : " + streamInteger);
    
            /*
             * 기본값 : OptionalInt
             * 
             * 합계 예제에서는 0이라는 기본값이 있어 별 문제가 없었다.
             * 하지만 IntStream에서 최대값을 찾을 때는 0이라는 기본값 때문에 잘못된 결과가 도출될 수 있다.
             * 스트림에 요소가 없는 상황과 실제 최대값이 0인 상황을 어떻게 구별할 수 있을까?
             * Optional을 Integer, String 등의 레퍼런스 형식으로 파라미터화할 수 있다.
             * 또한 OptionalInt, OptionalDouble, OptionalLong 세 가지 기본형 특화 스트림 버전도 제공한다. 
             */
            OptionalInt optionalInt = menu.stream().mapToInt(Dish::getCalories).max();
            // 최대 값이 없는 상황에 orElse 메서드를 이용해서 명시적으로 기본값을 정의 할 수 있다.
            System.out.println("기본값 : OptionalInt : " + optionalInt.orElse(1));
    
            /*
             * 5.6.2 숫자 범위
             * 
             * 특정 범위의 숫자를 이용해야 하는 상황이 자주 발생한다.
             * 예를 들어 1부터 100사이의 숫자를 생성하려한다고 가정하자.
             * 자바 8의 IntStream, LongStream에서는 range와 rangeClosed라는 두 가지 정적 메서드를 제공한다.
             * 두 메서드 모두 첫 번째 인수로 시작값을 두 번째 인수로 종료값을 갖는다.
             * 다만 range 메서드는 종료값이 결과에 포함되지 않는다.
             */
            System.out.println("5.6.2 숫자 범위 - range(0 ~ 10)");
            IntStream.range(0, 10).forEach(System.out::println);
    
            System.out.println("5.6.2 숫자 범위 - rangeClosed(0 ~ 10)");
            IntStream.rangeClosed(0, 10).forEach(System.out::println);
    
            /*
             * 5.6.3 숫자 스트림 활용 : 피타고라스 수
             */
            Stream<int[]> pythagoreanTriples = IntStream.rangeClosed(1, 100)
                .boxed()
                .flatMap(a -> {
                    return IntStream.rangeClosed(a, 100)
                        .filter(b -> Math.sqrt(a * a + b * b) % 1 == 0)
                        .mapToObj(b -> new int[] {a, b, (int)Math.sqrt(a * a + b *b) })
                        .filter(t -> t[2] % 1 == 0);
                });
    
            System.out.println("5.6.2 숫자 스트림 활용 : 피타고라스 수");
            pythagoreanTriples
                .limit(5)
                .forEach(t -> System.out.println(t[0] + ", " + t[1] + ", " + t[2]));
        }
    
    }

    5.7 스트림 만들기

    File

    Main_5_7.txt

    이거슨 첫 번째 라인 입니다.
    이거슨 두 번재 라인 입니다.

    Main

    package Part2.Chapter5.Chapter5_5_7;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URISyntaxException;
    import java.net.URLDecoder;
    import java.nio.charset.Charset;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.util.Arrays;
    import java.util.function.IntSupplier;
    import java.util.stream.IntStream;
    import java.util.stream.Stream;
    
    /*
     * 5.7 스트림 만들기
     */
    public class Main_5_7 {
    
        public static void main(String[] args) throws UnsupportedEncodingException, URISyntaxException {
            /*
             * 5.7.1 값으로 스트림 만들기
             * 
             * 임의의 수를 인수로 받는 정적 메서드 Stream.of를 이용해서 스트림을 만들 수 있다.
             */
            Stream<String> streamString = Stream.of("Java 8", "Lambdas", "In ", "Action");
            System.out.println("5.7.1 값으로 스트림 만들기");
            streamString.map(String::toUpperCase).forEach(System.out::println);
    
            /*
             * 5.7.2 배열로 스트림 만들기
             * 
             * 배열을 인수로 받는 정적 메서드 Array.stream을 이용해서 스트림을 만들 수 있다.
             */
            int[] numbers = {2, 3, 5, 7, 11, 13};
            System.out.println("5.7.2 배열로 스트림 만들기 : " + Arrays.stream(numbers).sum());
    
            /*
             * 5.7.3 파일로 스트림 만들기
             *
             * 파일을 처리하는 등의 I/O 연산에 사용하는 자바의 NIO API(비블록 I/O)도 스트림 API를
             * 활용할 수 있도록 업데이트 되었다. 
             * java.nio.file.Files의 많은 정적 메서드가 스트림을 반환한다.
             */
            long uniquoWords = 0;        
            String fileName = URLDecoder.decode(Main_5_7.class.getResource("").getPath() + "Main_5_7.txt", "UTF-8")
                    .replaceFirst("^/(.:/)", "$1");
    
            try (
                Stream<String> lines = 
                Files.lines(Paths.get(fileName), Charset.defaultCharset()) ) {
    
                uniquoWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
                    .distinct().count();                
    
                System.out.println("5.7.3 파일로 스트림 만들기 : " + uniquoWords);
            } catch(IOException e) {
                e.printStackTrace();
            }
    
            /*
             * 5.7.4 함수로 무한 스트림 만들기
             * 
             * 스트림 API는 함수에서 스트림을 만들 수 있는 두 개의 정적 메서드 Stream.iterate와 Stream.generate를
             * 제공한다.
             * 두 연산을 이용해서 무한 스트림(infinite stream), 즉 고정된 컬렉션에서 고정된 크기의 스트림이 아닌
             * 크기가 고정되지 않는 스트림을 만들 수 있다.        
             * iterate와 generate에서 만든 스트림은 요청할때마다 주어진 함수를 이용해서 값을 만든다.
             * 보통 무한한 값을 출력하지 않도록 limit(n)함수를 함께 연결해서 사용한다.
             */
    
            /*
             * iterate
             * 
             * iterate는 요청할 때마다 값을 생산할 수 있으며 끝이 없으므로 무한 스트림(infinite stream)을 만든다.
             * 이러한 스트림을 언바운드 스트림(unbounded stream)이라고 표현한다.
             * 이런 특징이 스트림과 컬렉션의 가장 큰 차이점이다. 예제에서는 limit 메서드를 이용해서 스트림의 크기를
             * 명시적으로 처음 10개의 짝수로 제한한다. 그리고 최종 연산인 forEach를 호출해서 스트림을 소비하고
             * 개별 요소를 출력한다.
             */
            System.out.println("5.7.4 함수로 무한 스트림 만들기 - iterate");
            Stream.iterate(0, n -> n + 2)
                .limit(10)
                .forEach(System.out::println);
    
            /*
             * generate
             * 
             * generate도 요구할 때 값을 계산하는 무한 스트림을 만들 수 있다.
             * 하지만 iterate와 달리 생산된 각 값을 연속적으로 계산하지 않는다.
             */
            System.out.println("5.7.4 함수로 무한 스트림 만들기 - generate");
            Stream.generate(Math::random)
                .limit(5)
                .forEach(System.out::println);
    
            /* 우리가 사용한 공급자(supplier)는 상태가 없는 메서드, 즉 나중에 계산에 사용할
             * 어떤 값도 저장해두지 않는다.
             * 하지만 공급자에 꼭 상태가 없어야 하는 것은 아니다. 공급자가 상태를 저장한 다음에
             * 스트림의 다음 값을 만들 때 상태를 고칠 수 있다.
             * 여기서 중요한 점은 병렬 코드에서는 공급자에 상태가 있으면 안전하지 않다는 것이다.
             * 
             * 아래 코드는 IntSupplier 인스턴스를 만들었다.
             * 만들어진 객체는 기존 피보나치 요소와 두 인스턴스 변수에 어떤 피보나치 요소가
             * 들어있는지 추적하므로 "가변(mutable) 상태 객체"다.
             * getAsInt를 호출하면 객체 상태가 바뀌며 새로운 값을 생산한다.
             * iterate를 사용했을 때는 각 과정에서 새로운 값을 생성하면서도 기존 상태를 바꾸지 않는
             * 순수한 "불변(immutable)" 상태를 유지했다.
             * (iterate 피보나치는 Quiz_5_7에서 확인.)
             * 
             * 스트림을 병렬로 처리하면서 올바른 결과를 얻으려면 "불변 상태 기법"을 고수해야 한다.
             */
            IntSupplier fib = new IntSupplier() {
                /*
                 * 추적 대상 변수들 - 위 설명에서 나온 "상태"를 뜻하기도 한다.
                 */
                private int prev = 0;
                private int curr = 1;
    
                @Override
                public int getAsInt() {
                    int oldPrev = this.prev;
                    int nextVal = this.prev + this.curr;
    
                    this.prev = this.curr;
                    this.curr = nextVal;
    
                    return oldPrev;
                }
            };
    
            System.out.println("5.7.4 함수로 무한 스트림 만들기 - generate");
            IntStream.generate(fib).limit(10).forEach(t -> System.out.print(t + ", "));
    
        }
    
    }

    Quiz_5_7

    Quiz_5_7.java

    package Part2.Chapter5.Chapter5_5_7.Quiz;
    
    import java.util.stream.Stream;
    
    public class Quiz_5_7 {
    
        public static void main(String[] args) {
            /*
             * 퀴즈 5-4 피보나치수열 집합
             */
            Stream.iterate(new int[] {0, 1}, t -> new int[] {t[1], t[0] + t[1]})
                .limit(20)
                .map(t -> t[0])
                .forEach(t -> System.out.print(t + ", ")); 
        }
    
    }

    스트림 활용

    • 데이터를 어떻게 처리할지는 스트림 API가 관리하므로 편리하게 데이터 관련 작업을 할 수 있다.
    • 스트림 API 내부적으로 다양한 최적화가 이루어질 수 있다.
    • 내부 반복뿐 아니라 코드를 병렬로 실행할지 여부도 결정할 수 있다. 이러한 일은 순차적인 반복을 단일 스레드로 구현했기 때문에 외부 반복으로는 불가능하다.

    요약

    • 스트림 API를 이용하면 복잡한 데이터 처리 질의를 표현할 수 있다.
    • filter, distinct, skip, limit 메서드로 스트림을 필터링하거나 자를 수 있다.
    • map, flatMap 메서드로 스트림의 요소를 추출하거나 변환할 수 있다.
    • findFirst, findAny 메서드로 스트림의 요소를 검색할 수 있다. allMatch, noneMatch, anyMatch 메서드를 이용해서 주어진 프레디케이트와 일치하는 요소를 스트림에서 검색할 수 있다.
    • 이들 메서드는 쇼트서킷(short-circuit), 즉 결과를 찾는 즉시 반환하며, 전체 스트림을 처리하지는 않는다.
    • reduce 메서드로 스트림의 모든 요소를 반복 조합하며 값을 도출할 수 있다. 예를 들어 reduce로 스트림의 최대값이나 모든 요소의 합계를 계산할 수 있다.
    • filter, map 등은 상태를 저장하지 않는 "상태 없는 연산(stateless operation)"이다 reduce 같은 연산은 값을 계산하는 데 필요한 상태를 저장한다. sorted, distinct 등의 메서드는 새로운 스트림을 반환하기 앞서 스트림의 모든 요소를 버퍼에 저장해야 한다. 이런 메서드를 "상태 있는 연산(stateful operation)"이라고 부른다.
    • IntStream, DoubleStream, LongStream은 기본형 특화 스트림이다. 이들 연산은 각각의 기본형에 맞게 특화되어 있다.
    • 컬렉션뿐 아니라, 값, 배열, 파일, iterate와 generate 같은 메서드로도 스트림을 만들 수 있다.
    • 크기가 정해지지 않는 스트림을 무한 스트림이라고 한다.
    반응형

    댓글

Designed by Tistory.