Java Collectionストーリー

104828 ワード

  • Collection

  • 各種データの集合を集合(抽象体、インタフェース)と呼ぶ

  • 資料構造と見なすことができる

  • Collection->List->LinkedList、Array、Vectorなど

  • 集合にデータを入れると順序は存在しません

  • List,SetはCollectionの継承関係,MapはSetの依存関係,破線矢印は実現


  • きほんコード
  • package com.programmers.java.collection;
    import java.util.ArrayList;
    import java.util.List;
    
    public class Main {
        public static void main(String[] args) { // 하하하
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
    
            for(int i=0; i<list.size(); i++){
                System.out.println(list.get(i));
            }
        }
    }

  • メソッドチェーン用のMyCollectionコード
  • package com.programmers.java.collection;
    import java.util.Arrays;
    import java.util.function.Consumer;
    
    public class MyCollection<T> {
        private List<T> list;
    
        public MyCollection(List<T> list){
            this.list = list;
        }
    
        public void foreach(Consumer<T> consumer){
            for(int i=0; i<list.size(); i++){
                T data = list.get(i);
                consumer.accept(data);
            }
        }
    }
  • package com.programmers.java.collection;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Consumer;
    import java.util.function.Function;
    
    public class MyCollection<T> {
        private List<T> list;
    
        public MyCollection(List<T> list){
            this.list = list;
        }
    
        public MyCollection<T> filter(Predicate<T> predicate){
            List<T> newList = new ArrayList<>();
    
            foreach(data -> {
                if(predicate.test(data)) newList.add(data);
            });
    
            return new MyCollection<>(newList);
        }
    
        // '이 함수에서 <U>를 제네릭으로 사용해라'라는 뜻으로 `<U> MyCollection<U>`을 붙임
        // <U>는 이 메소드에서만 유효한 상태가 됨 -> 딴 곳에서 못 써!
        public <U> MyCollection<U> map(Function<T, U> function){
            //Function<T, U> : T를 input, U를 output으로 받는 함수
            List<U> uTypeList = new ArrayList<>();
    
            // function에서 나온 U타입 반환물을 list에 넣기 (list는 아까 List<U> list라고 선언해서 U타입을 받을 수 있다)
            foreach(data -> uTypeList.add(function.apply(data)));
    
            return new MyCollection<>(uTypeList);
        }
    
        public void foreach(Consumer<T> consumer){
            for(int i=0; i<list.size(); i++){
                T data = list.get(i);
                consumer.accept(data);
            }
        }
    }

  • リンクメソッド用のMainコード
  • public class Main { // 람다 표현식으로 바뀌기 전
        public static void main(String[] args) {
    
            new MyCollection<Integer>(Arrays.asList(1,2,3,4,5,6,7))
                    .foreach(new Consumer<Integer>() {
                        @Override
                        public void accept(Integer integer) {
                            System.out.println(integer);
                        }
                    });
    
        }
    }
  • public class Main { // 람다 표현식으로 바뀐 후
        public static void main(String[] args) {
         /*
            new MyCollection<Integer>(Arrays.asList(1,2,3,4,5,6,7))
                    .foreach(integer -> System.out.println(integer));
             */
    
            new MyCollection<Integer>(Arrays.asList(1,2,3,4,5,6,7)) // Integer
                    .foreach(System.out::println);
    
            new MyCollection<String>(Arrays.asList("A","B","C","D","E","F","G")) // String
                    .foreach(System.out::println);
        }
    }
  • public class Main {
        public static void main(String[] args) {
    
            MyCollection <String> c1 = new MyCollection<>(Arrays.asList("Ar", "Brr", "Crrr", "Da"));
    
            //MyCollection <Integer> c2 = c1.map(s -> s.length());
    
            MyCollection <Integer> c2 = c1.map(String::length);
    
            c2.foreach(System.out::println);
    
            //위의 코드 3줄이랑 같은 의미임 == 미친듯한 생략이 람다 표현식의 가장 큰 장점이자 나에게 단점...
            // 이런 코드를 method chaining 라고 한다
            new MyCollection<>(Arrays.asList("Ar", "Brr", "Crrr", "Da", "Ee", "F12", "G"))
                    .map(String::length) // 문자열의 길이를 int로 변환하고
                    .filter(i -> i % 2 == 0) // 필터링을 통해 문자열 길이가 짝수인 것만
                    .foreach(System.out::println); // 출력하겠다
        }
    }

  • 19歳以上の学生名を出力(上のコードに追加)

  • 直感的またはgetterを使用すると、オブジェクトに関する情報を任意にクエリーできるため、このコードは完璧なコードではありません.
  • package com.programmers.java.collection;
    import java.util.Arrays;
    
    public class User {
        private String name;
        private int age;
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() { // 원치않는 사용자가 객체의 이름 정보에 대해 임의로 조회가능
            return name;
        }
    
        public int getAge() { // 원치않는 사용자가 객체의 나이 정보에 대해 임의로 조회가능
            return age;
        }
    }
    
    public class Main2 {
        public static void main(String[] args) {
            new MyCollection<User>(
                    Arrays.asList(
                            new User("학생A", 15),
                            new User("학생B", 16),
                            new User("학생C", 17),
                            new User("학생D", 18),
                            new User("학생E", 19),
                            new User("학생F", 20),
                            new User("학생G", 21),
                            new User("학생H", 22),
                            new User("학생I", 23)
                    )
            )
                    .filter(u -> u.getAge() >= 19)
                    .map(u -> u.getName())
                    .foreach(System.out::println);
        }
    }

  • 19歳以上の学生の名前を印刷(効果的な改善)
  • package com.programmers.java.collection;
    import java.util.Arrays;
    
    public class User {
        private String name;
        private int age;
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public boolean isAdult() { // 객체의 나이가 19세 이상인지 아닌지 boolean값으로 반환하는 함수
            return age >= 19;
        }
    
        @Override
        public String toString() { // toString()을 오버라이드하기
            return "name = " + name +
                    ", age =" + age;
        }
    }
    
    public class Main2 {
        public static void main(String[] args) {
            new MyCollection<User>(
                    Arrays.asList(
                            new User("학생A", 15),
                            new User("학생B", 16),
                            new User("학생C", 17),
                            new User("학생D", 18),
                            new User("학생E", 19),
                            new User("학생F", 20),
                            new User("학생G", 21),
                            new User("학생H", 22),
                            new User("학생I", 23)
                    )
            )
                    .filter(user -> user.isAdult())
                    .foreach(System.out::println); //toString()은 그냥 객체만 넣고 출력해도 나온다
        }
    }

  • TMI

  • インタフェース名抽象メソッドは,Consumervoid accept(T)オブジェクトがT消費BiConsumervoid accept(T,U)オブジェクトTを受け入れることを示している.U受入消費DoubleConsumervoid accept(2値)2値受入消費IntConsumervoid accept(int value)int値受入消費LongConsumervoid accept(longvalue)長値受入消費ObjectDoubleConsumervoid accept(T,2値)オブジェクトTとint値受入消費ObjectObjectLongConsumervoid acceptオブジェクトTとint値(T,long value)受信対象Tとlong値は、消費者Predicateboolean test(T.t)パラメータTを受け取りboolean値
  • を返す.
  • Iterator

  • インタフェースはIvalterrと呼ばれ、データの展開と処理方法のセットを提供します.

  • Iterator.次のデータはnext()でクエリーできます.
  • 以前のデータは照会できません

  • きほんコード
  • package com.programmers.java.iterator;
    
    import java.util.Arrays;
    import java.util.Iterator;
    import java.util.List;
    
    public class Main {
        public static void main(String[] args) {
            List<String> list = Arrays.asList("A", "B", "C", "D", "F");
            Iterator<String> iterator = list.iterator();
            // iterator.next()를 할 때마다 list에서 하나씩 띄어서 데이터를 처리하는 것임
    
            while (iterator.hasNext()){
                System.out.println(iterator.next());
            }
        }
    }

  • 改良コード(MyCollection.javaMyIterator<T> iterator()MyIterator<T> 인터페이스関連コードを挿入)
  • package com.programmers.java.iterator;
    //MyCollection.java에 이 코드들만 추가
    
    
    public interface MyIterator<T> { // T타입을 반환할 것이다는 의미
        boolean hasNext(); // 다음 원소가 있는지 체크해서 boolean으로 반환하는 추상 메소드
        T next(); // T타입을 반환하는 추상 메소드
    }
    
    public MyIterator<T> iterator(){ // Iterator<T>의 객체에 대한 생성자함수
            return new MyIterator<T>() {
                private int index = 0;
    
                @Override
                public boolean hasNext() {
                    return index < list.size();
                }
    
                @Override
                public T next() {
                    return list.get(index++); // 하고나서 index값을 증가시켜야 하므로 후위계산식 num++을 넣기
                }
            };
        }
    
    
    public class Main {
        public static void main(String[] args) {
            MyIterator<String> iterator =
                    new MyCollection<String>(Arrays.asList("A123","B2","C4","D555","E6666"))
                            .iterator();
    
            while (iterator.hasNext()){
                System.out.println(iterator.next());
            }
        }
    }
  • Stream

  • データから抽出された連続要素は데이터 처리연산をサポートする

  • Streamは데이터의 흐름(연속)です.

  • 必要な結果は、配列または集合インスタンスに複数の関数を組み合わせてフィルタリングし、加工の結果を得ることができます.

  • ランダを使用して、コードの数を減らし、簡略化することもできます.これは、配列と集合を関数と見なすことができることを意味します.
  • /*모두 Stream의 한 종류이다*/
    System.out //0utputStream
    System.in //InputStream

  • Collection.stream()Java 8から提供
  • Java 8からサポートされているのは데이터에 관련한 Streamです

  • filter、map、forEachなどの高次関数(関数をパラメータとする関数)が提供されます.
  • package com.programmers.java.stream;
    
    import java.util.Arrays;
    
    public class Main {
        public static void main(String[] args) {
    
            Arrays.asList("Ar", "Brr", "Crrr", "Da", "Ee", "F12", "G")
                    .stream()
                    .map(s -> s.length())
                    .filter(i -> i % 2 == 0)
                    .forEach(System.out::println);
        }
    }

  • その他のコード
  • package com.programmers.java.stream;
    import java.util.Arrays;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;
    import java.util.stream.Stream;
    
    public class Main2 {
        public static void main(String[] args) {
            Stream<Integer> s1 = Arrays.asList(1, 2, 3, 4).stream();
    
            // IntStream s2 = Arrays.asList(new int[]{1,2,3,4}); 가 불가능하기 때문에
            // Integer가 아닌 int배열을 stream으로 변환하고 그걸 받아 줄 수 있는 특별한 클래스인 IntStream을 생성한다
            IntStream s2 = Arrays.stream(new int[]{1,2,3,4});
            // 즉 primitive타입(int, boolean, double 등)을 위한 클래스 IntStream라고 보면 된다
    
            Arrays.stream(new int[]{1,2,3,4}).map(i -> Integer.valueOf(i));
            Arrays.stream(new int[]{1,2,3,4}).boxed(); //boxed()라는 메소드로 wrapper 클래스로 변환가능
            Arrays.stream(new int[]{1,2,3,4}).boxed().collect(Collectors.toList()); // 컬렉터의 리스트로 변환하겠다
            Arrays.stream(new int[]{1,2,3,4}).boxed().toArray(Integer[]::new); // int형 Array로 변환하겠다
            Arrays.stream(new int[]{1,2,3,4}).boxed().toArray(); // Object를 담는 Array로 변환하겠다
            // 이를 위해 Integer를 이용
    
        }
    }

  • Streamを作成する方法1:generate()
  • public class Main2 {
        public static void main(String[] args) {
           
            Stream.generate(() -> 1) // 1 값을 무한 생성
                    .forEach(System.out::println);
            
            Random random = new Random();
            Stream.generate(random::nextInt) // random 값을 10개만 생성
                    .limit(10)
                    .forEach(System.out::println);
        }
    }

  • Stream 2:iterate()の作成方法
  •     public class Main2 {
            public static void main(String[] args) {
                       
                Stream.iterate(0, i -> i + 1) // 0부터 시작해서 i+=1을 하며 10개 출력
                        .limit(10)
                        .forEach(System.out::println);
            }
        }

  • サイコロを1000回投げて3を投げる確率
  • package com.programmers.java.stream;
    import java.lang.reflect.Array;
    import java.util.Arrays;
    import java.util.Comparator;
    import java.util.Random;
    import java.util.stream.Stream;
    
    public class Main3 {
        public static void main(String[] args) {
    
            //주사위를 1000번 던져서 3이 나올 확률
            Random random = new Random();
            var cnt = Stream.generate(()->random.nextInt(6)+1)
                    .limit(1000)
                    .filter(i -> i == 3)
                    .count(); // count()는 long값을 반환한다
            System.out.println((float)cnt/1000);
    
            
            //1~10까지 중복되지 않는 것만 3개 뽑아서 배열에 넣기
            Random r = new Random(); // 1 ~ 10까지 숫자 중에서
            var arr = Stream.generate(()->r.nextInt(10)+1)
                    .distinct() // 중복되지 않는 것만
                    .limit(3) // 숫자 3개
                    .mapToInt(i -> i)
                    .toArray(); // int[]을 반환함
            System.out.println(Arrays.toString(arr));
    
            
            // 1 ~ 200까지 값중에서 랜덤값 5개를 뽑아 큰 순서대로 표시하시오
            Random ran = new Random();
            int[] array = Stream.generate(()->ran.nextInt(200)+1)
                    .limit(5)
                    .sorted(Comparator.reverseOrder())
                    .mapToInt(i -> i)
                    .toArray();
    
            System.out.println(Arrays.toString(array));
        }
    }

  • ストリームを使用すると、連続デートに豊富な高次関数を使用して強力な機能を簡潔に表現できます.

  • 熟能生巧
  • Optional

  • 背景

  • Null Pointer Exception(NPE):最も一般的な空のポインタ参照エラー

  • Javaでは(ほとんど)すべてが参照値です.この言葉はすべてnullになることを意味します.

  • 開発者は常に空かどうかを確認する必要があります

  • このような不便を減らすために、開発者はnullを使用しないと約束した.계약한다계약을 하고 프로그래밍한다と呼ばれています
  • nullは外せないので、お互いに書かないことを約束します.

  • EMPTYオブジェクトを使用します.
  • package com.programmers.java.collection;
    
    public class User {
        //null값으로 초기화하지 않기 위해서 없을 것 같은 존재를 임의의로 만든다
        public static final User EMPTY = new User("", 0);
    
        private String name;
        private int age;
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public boolean isAdult() {
            if (this == EMPTY) return false;
            return age >= 19;
        }
    
        @Override
        public String toString() {
            return "name = " + name +
                    ", age =" + age;
        }
    }
    
    
    package com.programmers.java.optional;
    
    import com.programmers.java.collection.User;
    
    public class Main {
        public static void main(String[] args) {
            User user1 = User.EMPTY;
    
            User user2 = getUser();
            if(user2 == User.EMPTY){
    
            }
            System.out.println(user1);
        }
    
        private static User getUser() {
            return User.EMPTY;
        }
    }

  • Optionの使用方法

  • nullデータ:Optional.empty();

  • データ:Optional.of({DATA});
  • package com.programmers.java.optional;
    import com.programmers.java.collection.User;
    import java.util.Optional;
    
    public class Main2 {
        public static void main(String[] args) {
    
            // User 객체가 실제로 정보가 있을 수도, 없을 수도 있으니 긴가민가한 이들을 위해 만든 것이 Optional
            Optional<User> optionalUser = Optional.empty(); // 얘는 현재 null
            
            optionalUser = Optional.of(new User("학생", 18));
            
            optionalUser.isEmpty(); // null이면 true 반환
            optionalUser.isPresent(); // null이 아닌 데이터가 존재하면 true 반환
        }
    }

  • Optionalのデータを確認します.
  • optionalUser.isEmpty(); , optionalUser.isPresent();
  • public class Main2 {
        public static void main(String[] args) {
    
            // User 객체가 실제로 정보가 있을 수도, 없을 수도 있으니 긴가민가한 이들을 위해 만든 것이 Optional
            Optional<User> optionalUser = Optional.empty(); // 얘는 현재 null
            optionalUser = Optional.of(new User("학생", 18));
    
            if(optionalUser.isPresent()){
                //do1
            }else{
                ///do2
            }
    
            if(optionalUser.isEmpty()){
                //do1
            }else {
                //do2
            }
    
            optionalUser.ifPresent(user -> {
                //do1
            });
    
            optionalUser.ifPresentOrElse(user ->{ //{}가 2개 들어감
                //do1, 데이터가 있을 경우
            }, ()-> {
                //do2, 데이터가 없을 경우
            });
    
        }
    }

  • オプションのメリット
  • EMPTYオブジェクトは、所定の開発者間でコードを記述することによりNPEが生成される可能性があるが、オプションを追加することにより、そのコードがNPE(互いに対する防御コード)
  • を生成しないことに留意することができる.
    nullの有無が分からないオブジェクトについては、
  • を簡潔に処理することができる