[데브코스] Collection 이야기

Updated: Categories:

W1D4 - 우리가 자주 쓰는 Collection에 대해 깊게 파보자!

Collection

  • 여러 데이터구조의 묶음.
  • 기본적으로 추상체이며, 구상체로 구현되어 있음

getter? 지양하자

  • getter를 사용하게 되면 클래스 멤버 변수에게 바로 접근이 가능하게 된다.
  • 따라서 host code 레벨에서 get으로 변수를 받아 처리하는 것이 아닌, 처리하고픈 기능을 클래스 내부에서 구현해놓는 것이 좋다.


Iterator

  • 여러 데이터 묶음을 풀어서 하나씩 처리할 수 있는 수단을 제공하는 컬렉션
  • 컬렉션 내부에서 index 상태를 관리한다
  • forEach 까지는 제공 X
List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4));
Iterator iterator = list.iterator();
// hasNext : 다음 인덱스 존재여부 판단
// next : 현재 인덱스에 해당하는 값 리턴 
while(iterator.hasNext()){
    System.out.println(iterator.next());
}


Stream

  • Java 8이상부터 컬렉션 스트림 사용가능, 데이터의 연속이라고 생각하면 된다.
  • 고차함수들을 가진다. (람다함수?를 파라미터로 받는 메소드)
  • 컬렉션들은 모두 스트림 변환 메소드를 가지고 있어, 객체 Type을 스트림으로 변환 가능 => .stream()
  • Method Chaining을 통한 연속적인 데이터 처리가 가능하다
List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4));
// 스트림으로 변환
Stream<Integer> s = list.stream();

Stream 메소드 정리

  • 예전에 학교에서 수강한 데이터분석에서 스트림 메소드를 정리했었는데, 이게 또 나올줄이야…. 😫
  • 다시보니 나름 잘 정리한것 같아서 앞으로 참고하자 -> 🚀 Repo 링크

Stream 만들기

  • 컬렉션을 스트림으로 변환하지 않고 바로 만드는 것도 가능하다.
  • 두 가지 방법으로 생성 가능.
// generate(넣을 값) -> 무한루프임 (limit이 없기에)
Stream.generate(1)
// iterate(시작값, 'Function' F-I)
Stream.iterate(0, i -> i+1)


Type의 이해

  • Type 종류는 크게 세가지가 있다.
    • Primitive Type : int, char 등등..
    • Reference Type : 컬렉션 객체
      • Wrapper Class : Primitive 타입을 담기위한 그릇이다. 기본적으로 얘도 Reference Type.
  • 스트림도 객체이므로 Primitive Type은 type 지정이 불가하다.
  • Primitive Type을 스트림으로 만드는 경우엔 별도의 스트림 객체가 만들어진다

Stream에서의 타입 변환

  • stream에서의 Primitive Type은 ___Stream이라는 Wrapper class로 표현한다.


  • ___Stream -> Stream 타입 변환은 map 메소드를 사용해도 되지만 boxed 메소드로도 가능
IntStream s = Arrays.stream(new int[]{1,2,3});
// IntStream -> Stream<Integer> :  primitive 타입을 wrapper 타입으로 박싱하여 반환한다.
s.boxed()
  • Stream -> ___Stream 타입 변환은 mapToXXX 메소드로 가능
// int -> IntStream
IntStream a = Stream.generate(() -> 1)
                .limit(5)
                .mapToInt(i -> i);
  • ??? -> 컬렉션 변경은 collect 메소드로 가능
IntStream s2 = Arrays.stream(new int[]{1,2,3});
// int 배열 -> List
s2.boxed().collect(Collectors.toList()).forEach(System.out::println);


Optional

  • NPE(Null Pointer Exception) : 자바에서는 모든게 레퍼런스 -> 모든것이 null이 될 수 있다.
  • 따라서 항상 null을 확인할 필요가 있어 매우 귀찮음..
  • 이제 null을 쓰지 않기로 계약하자!! (하지만 초기화할땐 어떡하지?)

EMPTY 객체 사용하기

  • 클래스를 생성할때 그 클래스에 초기값 객체를 미리 전역으로 생성해 해놓는다.
  • Null인지를 확인하지 않고 초기값 객체인지를 본다
public class User {
    // 초기화를 위한 객체를 미리 만들어 놓는다.
    public static User EMPTY = new User(0, "");
    ...
// 객체 생성할때 초기값 객체를 가져옴
User user = User.EMPTY;
// Null 확인이 아닌, 객체를 확인
if(user == User.EMPTY){
    ...
}
  • 하지만 정해진 규칙없이 임의로 만드는것이기 때문에 모두가 규칙을 알기 힘들다.

Optional 사용하기

  • 모두가 알 수 있는 명확한 사용법
  • Null 사용을 방지하면서 값이 실제로 들어있는지 확인하기 위한 Wrapper 클래스
Optional<User> optionalUser = Optional.empty();
optionalUser = Optional.of(new User(1, ""));
// 값이 없다면 true
optionalUser.isEmpty();
// 값이 있다면 true
optionalUser.isPresent();
// 값 유무에따라 조건 실행
optionalUser.ifPresentOrElse(
                // 있다면 (Consumer)
                user -> { },
                // 없다면 (Runnable)
                () -> { }
        );