자바 컬렉션 프레임워크 (Java Collections Framework; JCF)

컬렉션 프레임워크란

  • java.utils에 속한 일련의 클래스로, 자료구조를 담당
  • 잘 짜여진 인터페이스를 기반으로 다양한 자료구조를 구현
  • 제네릭 클래스로 되어 있어, 다양한 객체를 요소로 담을 수 있다.

JCF 인터페이스

  • List 인터페이스
    • Collection 인터페이스를 상속
    • 순서가 있는 데이터의 집합으로, 데이터의 중복을 허용
    • 구현체: ArrayList, LinkedList(, Vector, Stack)
  • Set 인터페이스
    • Collection 인터페이스를 상속
    • 순서가 없는 데이터의 집합으로, 데이터의 중복을 허용하지 않음
    • 구현체: HashSet, TreeSet
  • Map 인터페이스
    • Key-Value 쌍으로 이루어진 데이터의 집합
    • 구현체: HashMap, TreeMap, Hashtable, Properties

Collection 인터페이스

  • Collection 인터페이스의 주요 메소드

    메소드 설명
    boolean add(E e) 요소 e를 컬렉션에 추가한다.
    boolean addAll(Collection<? exteionds E> c) 다른 컬렉션 c의 모든 요소를 컬렉션에 추가한다.
    void clear() 컬렉션의 모든 요소를 제거한다.
    boolean contains(Object o) 컬렉션에 요소 o가 존재하는지 확인한다.
    boolean containsAll(Collection<?> c) 컬렉션 c의 모든 요소가 컬렉션에 포함되는지 확인한다.
    boolean equals(Object o) 컬렉션 o와 같은 내용을 포함하는지 비교한다.
    boolean isEmpty() 컬렉션이 비어있는지 확인한다.
    Iterator<E> iterator() 컬렉션의 Iterator를 반환한다.
    boolean remove(Object o) 컬렉션에서 요소 o를 제거한다.
    boolean removeAll(Collection<?> c) 컬렉션 c에 속한 모든 요소를 컬렉션에서 제거한다.
    boolean retainAll(Collection<?> c) 컬렉션 c에 포함된 객체만 남기고 나머지 요소를 제거한다.
    int size() 컬렉션에 속한 요소의 개수를 반환한다.
    T[] toArray(T[] a) 컬렉션의 요소들을 T[] 배열로 반환한다.
  • Iterator

    • iterator()로 반환되는 객체로, Collection에 저장된 요소에 접근하기 위해 사용

      메소드 설명
      boolean hasNext() 다음 요소가 있는지 확인
      E next() 다음 요소가 있을 경우 반환
      void remove() 현재 위치의 요소를 삭제
    • Iterator의 활용

      1
      2
      3
      4
      5
      Iterator<String> iter = collection.iterator();
      while (iter.hasNext()) {
      String string = iter.next();
      System.out.println(string);
      }
      1
      2
      3
      for (String string: collection) {
      System.out.println(string);
      }

List 인터페이스

  • 순서가 있는 데이터의 집합을 다루는 인터페이스

  • List는 인덱스를 이용해 요소를 구분할 수 있어, 데이터의 중복을 허용

  • Collection 인터페이스를 상속받았으며, 추가 메소드가 구현되어 있다.

    메소드 설명
    void add(int index, E element) index 위치에 요소 element를 삽입한다.
    boolean addAll(int index, Collection<? extends E> c) index위치부터 컬렉션 c의 모든 요소를 추가한다.
    E get(int index) index 위치에 저장된 요소를 반환한다.
    int indexOf(Object o) 객체 o가 저장된 첫번째 인덱스를 반환한다. 없을 경우 -1을 반환한다.
    int lastIndexOf(Object o) 객체 o가 저장된 마지막 인덱스를 반환한다. 없을 경우 -1을 반환한다.
    ListIterator<E> listIterator() ListIterator 객체를 반환한다.
    E remove(int index) index에 위치한 객체를 제거하고 반환한다.
    E set(int index, E element) index에 위치한 요소를 element로 대체한다.
    List<E> subList(int fromIndex, int toIndex) fromIndex에 위치한 요소부터 toIndex의 직전에 위치한 요소까지 포함한 List를 반환한다.
  • List 인터페이스의 구현체

    1
    2
    List<String> list = new ArrayList<>();
    list = new LinkedList<>(); // 동일 인터페이스로 다른 구현체를 사용 가능
    • ArrayList<E>

      • 제네릭 클래스로 구현된 자료구조

      • 배열을 기반으로 구현된 클래스로, 가장 자주 활용되며 활용도가 높다.

      • ArrayList의 생성자는 세 종류가 주어진다.

        1
        2
        3
        public ArrayList()
        public Arraylist(int initialCapacity)
        public ArrayList(Collection<? extends E>)
    • LinkedList<E>

      • 제네릭 클래스로 구현된 자료구조

      • 연결리스트를 기반으로 구현된 클래스로, 배열의 단점을 극복하기 위한 구현체

      • ArrayList vs. LinkedList

        구현체 순차 추가/수정/삭제 비순차 추가/수정/삭제 조회
        ArrayList 빠름 느림 빠름
        LinkedList 느림 빠름 느림
    • ArrayList, LinkedList

      • Object를 요소로 가지는 List 구현체 (Java5 이전)
  • List의 정렬

    • Collections 클래스의 sort() 메소드 사용
      • public static <T extends Comparable<? super T> void sort(List<T> list)
        • 객체에 선언된 public int compareTo(T t) 메소드로 비교하여 정렬
      • public static <T> void sort(List<T> list, Comparator<? super T> c)
        • Comparator 객체 c에 정의된 public int compare(T o1, T o2) 메소드로 비교하여 정렬
  • ListIterator

    • listIterator()로 반환되는 객체로, 양방향 사용이 가능
    • Iterator를 상속받은 클래스
    메소드 설명
    boolean hasPrevious() 이전 요소가 있는지 확인
    E previous() 이전 요소가 있을 경우 반환

Set 인터페이스

  • 순서가 없는 데이터의 집합을 다루는 인터페이스

  • 중복되는 데이터를 효율적으로 제거하는 데에 쓸 수 있음

  • Collection 인터페이스를 상속받아 메소드를 구현하고 있음

  • Set의 구현체

    • HashSet<E>

      • Set의 대표적인 구현체로, 기본적인 기능이 구현되어 있다.
    • TreeSet<E>

      • NavigableSet<E> 인터페이스를 구현하며, 이진 탐색 트리 자료구조이다.

      • 객체를 삽입하는 동시에 정렬되는 특성상 비교가 가능해야 한다.

        1
        2
        public TreeSet() // Comparable 구현체의 경우
        public TreeSet(Comparator<? super E> comparator) // 별도로 비교 객체 삽입
      • TreeSet의 메소드

      메소드 설명
      public E first() 정렬된 첫 요소를 반환
      public E last() 정렬된 마지막 요소를 반환
      public E lower(E e) e 객체의 바로 이전 객체를 반환
      public E higher(E e) e 객체의 바로 다음 객체를 반환
      public E floor(E e) e 또는 e 보다 이전 객체를 반환
      public E ceiling(E e) e 또는 e 보다 이후 객체를 반환
      public E pollFirst() 정렬된 첫 요소를 제거하고 반환
      public E pollLast() 정렬된 마지막 요소를 제거하고 반환
      public NavigableSet<E> descendingSet() 내림차순으로 정렬하는 객체를 반환
      public NavigableSet<E> headSet(E toElement, boolean inclusive) toElement 이전 요소로 구성된 객체 반환
      public NavigableSet<E> tailSet(E fromElement, boolean inclusive) fromElement 이후 요소로 구성된 객체 반환
      public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) fromElement 이후, toElement 이전 요소로 구성된 객체 반환

Map 인터페이스

  • Key와 Value의 쌍으로 구성된 자료의 집합을 다루는 인터페이스\

    • Key, Value 쌍은 Map.Entry<K, V> 객체로 관리
  • Key는 중복될 수 없으며, Value는 중복이 가능

  • Map<K, V>의 구현체

    • HashMap<K, V> : 가장 많이 사용되는 Map의 구현체
    • TreeMap<K, V> : 정렬 기준이 더해진 NavigableMap을 구현한 구현체
    • Hashtable<K, V> : HashMap과 유사하지만 성능이 떨어지는 대신 멀티스레드에 안전한 구현체
    • Properties : 속성 파일을 손쉽게 관리하는, Hashtable<K, V>의 하위 클래스 구현체
  • Map<K, V>의 주요 메소드

    메소드 설명
    void clear() Map의 모든 요소를 삭제
    boolean containsKey(Object key) key가 존재하는지 여부를 반환
    boolean containsValue(Object value) value가 존재하는지 여부를 반환
    Set<Map.Entry<K,V>> entrySet() Map의 Entry 요소를 Set에 담아 반환
    V get(Object key) key에 해당하는 value 객체 반환
    Set<K> keySet() key 요소를 Set 형태로 반환
    V put(K key, V value) key와 value 쌍으로 구성된 Entry 추가. 기존에 등록된 key라면 해당 value를, 없으면 null을 반환
    void putAll(Map<? extends K, ? extends V> m) m에 속한 모든 Entry를 추가
    V remove(Object key) key에 해당하는 Entry를 제거하고 반환. 등록되지 않은 key라면 null 반환
    Collection<V> values value 객체들을 Collection에 담아 반환
    int size() Map에 포함된 Entry 객체의 수 반환
    boolean isEmpty() Map에 데이터가 없는지 여부 반환
  • TreeMap<K, V>의 주요 메소드

    메소드 설명
    public Map.Entry<K, V> firstEntry() 정렬된 첫 Entry 반환
    public Map.Entry<K, V> lastEntry() 정렬된 마지막 Entry 반환
    public Map.Entry<K, V> lowerEntry(K key) key 바로 이전 Entry 반환
    public Map.Entry<K, V> higherEntry(K key) key 바로 다음 Entry 반환
    public Map.Entry<K, V> floorEntry(K key) key 또는 key 보다 이전 Entry 반환
    public Map.Entry<K, V> ceilingEntry(K key) key 또는 key 보다 이후 Entry 반환
    public Map.Entry<K, V> pollFirstEntry() 정렬된 첫 Entry를 제거하고 반환
    public Map.Entry<K, V> pollLastEntry() 정렬된 마지막 Entry를 제거하고 반환
    public NavigableSet<E> descendingKeySet() 내림차순으로 정렬하는 Set 반환
    public NavigableSet<E> descendingKeyMap() 내림차순으로 정렬하는 Map 반환
    public NavigableMap<K, V> headMap(K toKey, boolean inclusive) toKey 이전 Entry로 구성된 객체 반환
    public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) fromKey 이후 Entry로 구성된 객체 반환
    public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) fromKey 이후, toKey 이전 Entry로 구성된 객체 반환
  • Properties의 주요 메소드

    메소드 설명
    getProperty() key에 해당하는 속성 값을 반환
    stringPropertyNames() key의 목록을 Set<String>으로 반환
    setProperty() key로 value를 등록하고 기존 value 값을 반환
    load() reader를 이용해 속성을 읽어온다. (.properties)
    loadFromXML() XML 형식으로 저장된 속성을 읽어온다.
    store() writer를 이용해 속성을 저장한다.
    storeToXML() XML 형식으로 속성 파일을 저장한다.

Comment and share

I/O

I/O와 스트림

  • I/O란 입출력(Input/Output)을 함께 부르는 것
  • 자바의 I/O는 스트림을 이용해 데이터를 주고 받는 형식으로 이루어짐
    • 데이터의 소스와 목적지를 노드(node)라 부름
    • 노드는 키보드, 모니터, 파일, 메모리, 데이터베이스, 다른 프로그램 등이 될 수 있음

노드 스트림

InputStream과 Reader

  • InputStream의 주요 메소드 (byte 단위)

    메소드 설명
    int read() byte 하나를 읽어서 int로 반환. 읽을 값이 없으면 -1
    int read(byte b[]) 데이터를 읽어 b를 채우고, 읽은 바이트 수를 반환
    int read(byte b[], int offset, int len) 최대 len개의 바이트를 읽어 b의 offset 위치부터 채운다.
    void close() 스트림을 종료하고 자원을 반납
    int available() 읽을 수 있는 데이터의 크기를 반납
    long skip(long n) 스트림에서 n만큼 건너 뛴다.
    void mark(int readLimit) reset()으로 돌아갈 위치를 표시한다. readLimit은 돌릴 수 있는 최대 바이트 수
    void reset() mark()가 호출된 지점으로 돌아간다.
    boolean markSupported() mark, reset 메소드의 지원 여부를 반환
    1
    2
    3
    4
    5
    6
    7
    8
    try (InputStream input = System.in) {
    int read = -1;
    while ((read = input.read()) != -1) {
    System.out.printf("Integer: %d\nCharacter: %c\n", read, read);
    } catch(IOException e) {
    e.printStackTrace();
    }
    }
  • Reader의 주요 메소드 (char 단위)

    메소드 설명
    int read() char 하나를 읽어서 int로 반환. 읽을 값이 없으면 -1
    int read(char cbuf[]) 데이터를 읽어 cbuf를 채우고, 읽은 char 수를 반환
    int read(char cbuf[], int off, int len) 최대 len개의 char를 읽어 cbuf의 offset 위치부터 채운다.
    int read(java.nio.CharBuffer target) NIO target에 데이터를 저장한다.
    void close() 스트림을 종료하고 자원을 반납
    int available() 읽을 수 있는 데이터의 크기를 반납
    long skip(long n) 스트림에서 n만큼 건너 뛴다.
    void mark(int readAheadLimit) reset()으로 돌아갈 위치를 표시한다. readLimit은 돌릴 수 있는 최대 바이트 수
    void reset() mark()가 호출된 지점으로 돌아간다.
    boolean markSupported() mark, reset 메소드의 지원 여부를 반환

OutputStream과 Writer

  • OutputStream의 주요 메소드 (byte 단위)

    메소드 설명
    void write(int b) b 내용을 byte로 출력
    void write(byte b[]) b를 문자열로 변환하여 출력
    void write(byte b[], int off, int len) b의 off부터 (off + len - 1)만큼을 문자열로 변환하여 출력
    void close() 스트림을 종료하고 자원을 반납. close() 내부적으로 flush() 호출
    void flush() 버퍼 스트림에서 버퍼의 내용을 출력하고 비운다.
  • Writer의 주요 메소드 (char 단위)

    메소드 설명
    void write(int c) c 내용을 char로 출력
    void write(char cbuf[]) cbuf를 문자열로 변환하여 출력
    void write(char cbuf[], int off, int len) cbuf의 off부터 (off + len - 1)만큼을 문자열로 변환하여 출력
    void write(String str) str을 출력한다.
    void write(String str, int off, int len) str의 off부터 (off + len - 1)만큼을 출력
    Writer append(CharSequence csq) csq를 출력하고 Writer 반환
    Writer append(CharSequence csq, int start, int end) csq의 start부터 end까지를 출력하고 Writer 반환
    Writer append(char c) c를 출력하고 Writer 반환
    void close() 스트림을 종료하고 자원을 반납. close() 내부적으로 flush() 호출
    void flush() 버퍼 스트림에서 버퍼의 내용을 출력하고 비운다.

다양한 입출력 처리

  • 메모리 기반의 입/출력

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    char[] memory = "메모리 입출력 테스트".toCharArray();
    char[] buffer = new char[5];
    int read = 0;
    try (CharArrayReader reader = new CharArrayReader(memory);
    CharArrayWriter writer = newCharArrayWriter();) {
    while ((read = reader.read(buffer) > 0)) {
    wrtier.write(buffer, 0, read);
    }
    System.out.println(Arrays.toString(writer.toCharArray()));
    } catch (IOException e) {
    e.printStackTrace();
    }
  • 파일 기반의 입출력

    • 생성자 및 생성/삭제 메소드

      생성자 및 메소드 설명
      File(String pathname) pathname에 해당하는 파일 생성. 기본 경로는 애플리케이션의 시작 경로
      File(String parent, String child) parent 경로 아래 child 파일 생성
      File(File parent, String child) parent 경로 아래 child 파일 생성
      File(URI uri) file로 시작하는 URI 객체를 이용해 파일 생성
      boolean createNewFile() 새로운 파일을 생성
      boolean mkdir() 새로운 디렉토리를 생성
      boolean mkdirs() 경로상의 모든 디렉토리를 생성
      boolean delete() 파일/디렉토리 삭제
      void deleteOnExit() 애플리케이션 종료시 자동으로 삭제
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      String filePath = "D:" + File.separator + "Temp" + File.separator + "MyTemp";

      File fileOne = new File(filePath);
      fileOne.mkdir();

      File fileTwo = new File(filePath, "file2.txt");
      fileTwo.createNewFile();

      File fileThree = new File(fileOne, "file3.txt");
      fileThree.createNewFile();

      File fileFour = new File(new URI("file:///d:/Temp/MyTemp/file4.txt"));
      fileFour.createNewFile();
      fileFour.deleteOnExit();
    • File 클래스의 주요 메소드

      • getName(), getParent(), getParentFile(), getPath()
      • isAbsolute(), getAbsolutePath(), getCanonicalPath(), toURI()
      • canRead(), canWrite()
      • isDirectory(), isFile()
      • length(), list(), listFiles(), lastModified(), renameTo()
    • FileInputStream, FileOutputStream

      • 파일명이나 File 객체를 이용하여 입출력 스트림 생성 가능
      • FileOutputStream에서 boolean append를 true로 하면 기존 파일에 이어서 쓴다.
    • FileReader, FileWriter

      • 파일명이나 File 객체를 이용하여 입출력 Reader 생성 가능
      • FileWriter에서 boolean append를 true로 하면 기존 파일에 이어서 쓴다.

보조 스트림

보조 스트림의 특징

  • 스트림에 부가적인 기능 제공
  • 노드(데이터 소스/목적지)와 직접 연결되지 않고, 다른 스트림과 연결
  • Stream Chaining: 스트림을 여러개 연결하여 사용

보조 스트림의 종류

보조 스트림 기능
InputStreamReader byte 스트림을 char 스트림으로 변환
OutputStreamWriter byte 스트림을 char 스트림으로 변환
BufferedReader 버퍼링을 통해 스트림 속도 향상
BufferedWriter 버퍼링을 통해 스트림 속도 향상
BufferedInputStream 버퍼링을 통해 스트림 속도 향상
BufferedOutputStream 버퍼링을 통해 스트림 속도 향상
DataInputStream 기본 데이터형 전송
DataOutputStream 기본 데이터형 전송
ObjectInputStream 객체 전송
ObjectOuputStream 객체 전송
PrintWriter 문자열 표현으로 출력
PrintStream 문자열 표현으로 출력

스트림 자료형 변경

  • 캐릭터셋: utf-8, ms949, euc-kr

    1
    2
    3
    4
    5
    InputStreamReader readerOne = new InputStreamReader(System.in);
    InputStreamReader readerTwo = new InputStreamReader(System.in, "utf-8");

    OutputStreamWriter writerOne = new OutputStreamWriter(System.out);
    OutputStreamWriter writerTwo = new OutputStreamWriter(System.out, "ms949");

버퍼를 이용한 스트림

  • 기본 버퍼 크기: 8192 bytes

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    static void copyStream(InputStream input, OutputStream output) throws IOException {
    byte [] buff = new byte[1024];
    int read = -1;
    while ((read = input.read(buff) > 0)) {
    output.write(buff, 0, read);
    }
    }

    public static void main(String[] args) {
    File src = new File("C:/Windows/explorer.exe");
    File dst = new File("C:/temp/explorer.exe");
    try (FileInputStream in = new FileInputStream(src);
    FileOutputStream out = new FileOutputStream(target);
    BufferedInputStream buffIn = new BufferedInputStream(in);
    BufferedOutputStream buffOut = new BufferedOutputStream(out);) {
    long start = System.nanoTime();
    copyStream(in, out);
    System.out.println(System.nanoTime() - start);

    long start = System.nanoTime();
    copyStream(bin, bout);
    System.out.println(System.nanoTime() - start);
    } catch (IOException e) {
    e.printStackTrace();
    }

    }
  • BufferedReader는 readLine() 메소드를 사용할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    File src = new File("./src.txt");
    try (BufferedReader buffReader = new BufferedReader(new FileReader(src));) {
    String line = null;
    while ((line = br.readLine()) != null) {
    System.out.println(line);
    }
    } catch (IOException e) {
    e.printStackTrace();
    }

기본 데이터형 전송 스트림

  • byte, char 외에 다른 기본 데이터형도 전송 가능한 스트림

    • 읽은 후에는 자료형을 알 수 없으므로 쓴 순서대로 읽어야 함
    클래스 메소드
    DataInputStream boolean readBoolean()
    byte readByte()
    short readShort()
    int readInt()
    long readLong()
    float readFloat()
    double readDouble()
    char readChar()
    String readUTF()
    DataOutputStream void writeBoolean(bool v)
    void writeByte(byte v)
    void writeShort(short v)
    void writeInt(int v)
    void writeLong(long v)
    void writeFloat(float v)
    void writeDouble(double v)
    void writeChar(char v)
    void writeUTF(String v)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    File src = new File("c:/Temp/data.dat");
    try (DataOutputStream out = new DataOutputStream(new FileOutputStream(src))) {
    out.writeUTF("김패캠");
    out.writeInt(15);
    out.writeFloat(14.23);
    }

    try (DataInputStream in = new DataInputStream(new FileInputStream(src))) {
    String string = in.readUTF();
    int integer = in.readInt();
    float floatNum = in.readFloat();
    System.out.println(string + " " + integer + " " + floatNum);
    }

객체 저장을 위한 스트림

  • 일반적인 참조형 객체를 저장하기 위한 스트림

  • 직렬화(Serialization)와 역직렬화(Deserialization) 사용

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    class Foo implements Serializable { // has-a 관계의 모든 클래스가 Serializable이어야 함
    static final long serialVersionUID = 1L; // 객체의 버전 관리

    String userName;
    int id;

    transient String passWord;

    @Override
    public String toString() {
    return userName + " " + id + " " + passWord;
    }
    }

    class FooTest {
    public static void main (String [] args) {
    File dst = new File("C:/Temp/obj.data");
    Foo foo = new Foo();
    foo.userName = "김사탕";
    foo.id = 142;
    foo.passWord = "qwer1234";

    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(dst));
    ObjectInputStream in = new ObjectInputStream(new FileInputStream(dst));) {
    out.writeObject(foo);
    Object read = in.readobject();
    if (read != null && read instanceof Foo) {
    Foo readFoo = (Foo)read;
    System.out.println(readFoo);
    }
    } catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
    }
    }
    }

  • 부모 클래스가 Serializable이 아닌 경우 자식 클래스에서 직접 처리

    • writeObject(), readObject()를 자식 클래스에서 직접 구현
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class ParentFoo {
    int memVarOne;
    double memVarTwo;
    }

    class ChildFoo extends ParentFoo implements Serializable {
    @Override
    private void writeObject(ObjectOutputStream out) throws IOException {
    out.writeInt(memVarOne);
    out.writeDouble(memVarTwo);
    out.defaultWriteObject();
    }
    @Override
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    memVarOne = in.readInt();
    memVarTwo = in.readDouble();
    in.defaultReadObject();
    }
    }

Comment and share

java.lang 패키지

java.lang

  • Java에서 가장 기본적이며 자주 사용되는 클래스를 모은 패키지
  • 별도로 import하지 않아도 사용이 가능한, Java의 기본 중의 기본

Object Class

  • 모든 클래스의 조상 클래스로, 클래스가 갖춰야할 기본 기능을 제공

  • 필요한 경우 Object 클래스에 정의된 메소드를 Override하여 사용

    메소드 설명
    public final native Class<?> getClass() 현재 객체의 클래스를 반환한다.
    public native int hashCode() 현재 객체의 해시코드 값을 반환한다.
    public boolean equals() 현재 객체와 대상이 같은 객체를 참조하는지 여부를 반환한다.
    public String toString() 객체를 문자열로 변환하여 반환한다.
    proteted native clone() throws CloneNotSupportedException 객체를 복사하여 새로운 객체로 반환한다.

equals()

  • Object 클래스의 equals() 메소드 구현

    • 객체의 참조만을 비교
    1
    2
    3
    public boolean equals(Object obj) {
    return (this == obj);
    }
  • String 클래스의 equals() 메소드 구현 (Overriding)

    • 효율적으로 객체의 내용이 동일한지 비교
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public boolean equals(Object anObject) {
    if (this == anObject) {
    return true;
    }
    if (anObject instanceof String) {
    String aString = (String)anObject;
    if (!COMPACT_STRINGS || this.coder == aString.coder) {
    return StringLatin1.equals(value, aString.value);
    }
    }
    return false;
    }

hashCode()

  • 객체를 구분하기 위해 사용하는 정수값(해시코드)을 반환
    • 프로그램 내에서 객체마다 유일하므로 주소값처럼 사용 가능
  • native 메소드이므로 구현 내용을 볼 수 없음
  • hashCode()의 제한 사항
    • 한 객체의 hashCode()를 여러번 호출할 경우, equals()에 사용하는 값이 변하지 않으면 동일한 값을 반환해야 한다.
    • equals() 메소드가 같다고 판단한 두 객체의 hashCode() 반환값은 같아야 한다.
    • equals() 메소드가 다르다고 판단한 두 객체의 hashCode()가 반드시 다를 필요는 없으나, 다른 값이 나오면 HashTable 성능이 향상된다.

clone()

  • 자신을 복제하여 새로운 객체를 생성하는 메소드

  • 배열을 복제할 경우 새로운 객체를 생성하므로 원본을 훼손하지 않을 수 있음

  • clone() override 시 Cloneable 인터페이스를 구현해야 함

    1
    2
    int [] ints = {1, 2, 3, 4, 5};
    int [] ints2 = ints.clone();

getClass()

  • Class 에 대한 정보를 담고 있는 Class 객체를 반환

  • 객체의 getClass() 메소드 또는 해당 클래스의 정적 변수 class를 이용 가능

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Foo {
    public void methodA() {
    System.out.println("method A called.");
    }
    }

    class FooTest {
    public static void main(String[] args) throws Exception {
    Foo foo = new Foo();
    Class fooClass = foo.getClass();

    System.out.println(fooClass.getName());
    System.out.println(fooClass.getDeclaredMethods().length);
    System.out.println(Foo.class.getDeclaredMethod("methodA").invoke(foo));
    }
    }

System

  • 실행 중인 OS와 interact하기 위한 클래스

  • System 클래스의 주요 정적 변수

    속성 설명
    public static final PrintStream err 오류를 출력하기 위한 표준 출력 스트림
    public static final InputStream in 표준 입력을 처리하기 위한 입력 스트림
    public static final PrintStream out 표준 출력을 처리하기 위한 출력 스트림
  • System 클래스의 주요 정적 메소드

    메소드 설명
    arraycopy() src 배열의 내용을 dst 배열로 복사한다.
    currentTimeMillis() 현재 시스템 시간을 ms로 반환한다.
    exit() 프로그램을 종료한다
    gc() GC를 요청한다.
    getenv() 환경 변수의 값을 반환한다.
    getProperties() 시스템 속성을 Property로 반환한다.
    getProperty() 시스템 속성 값을 문자열로 반환한다. 없을 경우 null 또는 def를 반환
    identityHashCode() 객체의 해시코드 값을 반환한다.
    lineSeparator() 시스템의 줄넘김 문자열을 반환한다. UNIX: \n, WINDOWS: \r\n
    nanoTime() 시스템 시간을 ns로 반환한다.
    setProperties() 시스템 속성을 한번에 설정한다.
    setProperty() 시스템 속성을 하나씩 설정한다.
    • 주요 Property

      속성 설명
      user.country OS 로케일 정보
      java.io.tmpdir 임시 경로
      line.separator 줄넘김 문자열
      user.home 유저 홈 경로
      file.separator 파일 경로 구분

Math

  • 수학 계산에 필요한 메소드를 가진 final 클래스

    메소드 설명
    abs() 절대값을 반환한다.
    ceil() 올림 값을 double로 반환한다.
    floor() 내림 값을 double로 반환한다.
    max() 두 값 중 더 큰 값을 반환한다.
    min() 두 값 중 더 작은 값을 반환한다.
    random() 0 이상 1.0 미만의 임의의 값을 반환한다.
    round() 소수점 첫째자리에서 반올림한 정수 값을 반환한다.
    addExact() 덧셈 연산으로, Overflow 발생 시 ArithmaticException 발생.
    subtractExact() 뺄셈 연산으로, Overflow 발생 시 ArithmaticException 발생.
    multiplyExact() 곱셈 연산으로, Overflow 발생 시 ArithmaticException 발생.

Comment and share

스트림 API (Stream API)

스트림 API란

  • Java 8에서 추가된 java.util.stream 패키지
  • 컬렉션의 요소를 람다식으로 처리할 수 있도록 하는 함수형 프로그래밍 도구

스트림 API의 특징

  • 간결한 코드 작성
1
2
3
4
5
6
7
8
9
10
11
// JAVA 7
List<String> list = Arrays.asList("fast", "campus", "rocks");
List<String> newList = new ArrayList<>();

for (String s: list) {
newList.add(s.toUpperCase());
}

for (String s: newList) {
System.out.println(s);
}
1
2
3
4
// JAVA 8
List<String> list = Arrays.asList("fast", "campus", "rocks");
Stream<String> stream = list.stream();
stream.map(String::toUpperCase).forEach(System.out::println);
  • 데이터 소스에 대한 공통의 접근 방식 제공

    • List, Set, Array 등 다양한 경우에 대해 표준화된 방식으로 데이터 접근 가능
    • 특히 Stream::sorted() 메소드는 공통된 정렬 방식을 제공
  • 중간 처리와 최종 처리를 지원

    • Mapping, Filtering, Sorting 등 중간 처리 지원 (여러개 사용 가능)
    • Iteration, Count, Average, Summation, Reduce 등 최종 처리 지원 (마지막에 하나 사용 가능)
  • 데이터 소스와 처리 결과를 분리

    • 원본 데이터를 유지하여 처리에 의한 부작용 방지
    • 처리 결과를 새로운 컬렉션으로 저장 가능

스트림 API를 이용한 자료 처리

스트림 API의 종류

종류 처리 대상
Stream<T> 일반적인 객체를 처리
IntStream 기본 자료형 int를 처리
LongStream 기본 자료형 long을 처리
DoubleStream 기본 자료형 double을 처리

스트림 객체 생성 메소드

  • 데이터 소스로부터 스트림 생성

    데이터 소스 메소드
    Collection default Stream<E> stream()
    Collection default Stream<E> parallelStream()
    Arrays public static <T> Stream<T> stream(T[] array)
    Arrays public static <T> Stream<T> of(T ... values)
    Arrays public static IntStream stream(int[] array)
    Arrays public static IntStream of(int ... values)
    Arrays public static LongStream stream(long[] array)
    Arrays public static LongStream of(long ... values)
    Arrays public static DoubleStream stream(double[] array)
    Arrays public static DoubleStream of(double ... values)
  • 정수 범위와 java.util.Random으로부터 생성

    구분 메소드
    int형 범위 public static IntStream range(int startInclusive, int endExclusive)
    int형 범위 public static IntStream rangeClosed(int startInclusive, int endInclusive)
    long형 범위 public static LongStream range(long startInclusive, long endExclusive)
    long형 범위 public static LongStream rangeClosed(long startInclusive, long endInclusive)
    Random p형 값 public PStream ps()
    Random p형 값 public PStream ps(long streamSize)
    Random p형 값 public PStream ps(long streamSize, p origin, p bound)
    1
    2
    3
    4
    5
    6
    IntStream integers = IntStream.range(0, 10);
    integers.forEach(System.out::println);

    Random random = new Random();
    LongStream longs = random.longs(100, 1, 10);
    System.out.println(longs.average().getAsDouble());

중간 처리 메소드

동작 메소드
필터링 dinstict(), filter()
자르기 skip(), limit()
정렬 sorted()
매핑 flatMap(), flatMapToP(), map(), mapToP(), asDoubleStream(), asLongStream()
조회 peek()

필터링

필터링은 스트림의 일부 요소를 제거하는 역할을 한다.

  • Stream<T> distict() : 스트림 요소의 중복을 제거한 스트림을 반환
  • Stream<T> filter(Predicate<? super T> predicate) : Predicate에서 true에 해당하는 요소만으로 구성된 스트림을 반환

자르기

자르기는 스트림의 일부 요소를 한번에 생략한다.

  • Stream<T> limit(long maxSize) : 최대 maxSize까지 구성된 스트림을 반환
  • Stream<T> skip(long n) : 스트림의 상위 n개 요소를 생략한 스트림을 반환

정렬

스트림 요소의 compareTo() 또는 입력받은 Comparator를 이용해 정렬

  • Stream<T> sorted() : Comparable 객체를 정렬한 스트림 반환
  • Stream<T> sorted(Comparator<? super T> comparator) : Comparator를 이용하여 정렬된 스트림 반환
    • Comparator의 정적 메소드와 기본 메소드
      • 정적 메소드: naturalOrder(), reverseOrder(), comparing(), comparingP(), nullsFirst(), nullsLast()
      • 기본 메소드: reversed(), thenComparing(), thenComparingP()

매핑

Function 인터페이스를 이용해 요소의 값을 변환한다.

  • map 계열

    • <R> Stream<R> map(Function<? super T, ? extends R> mapper) : 기존 스트림의 T 타입 요소를 R 타입으로 변환하여 새로운 스트림 반환
    • PStream mapToP(ToPFunction<? super T> mapper) : R이 기본형 타입으로 제한된 map()
  • flatMap 계열

    • <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) : 스트림의 T 타입 요소가 n개의 R 타입 요소로 매핑된 새로운 스트림을 반환
    • PStream flatMapToP(Function<? super T, ? extends PStream> mapper) : R이 기본형 타입으로 제한된 flatMap()
    1
    2
    3
    4
    List<String> list = Arrays.asList("java", "backend", "best", "course");
    System.out.println(list.stream().flatMap(data -> {
    return Arrays.stream(data.split(""));
    }).distinct().count());

조회

스트림 처리 과정에 영향을 미치지 않으며, 중간 결과를 확인할 수 있으며 입력받은 스트림과 동일한 스트림을 반환한다.

  • Stream<T> peek(Consumer<? super T> action)

    1
    2
    3
    4
    5
    6
    List<String> list = Arrays.asList("java", "backend", "best", "course");
    System.out.println(list.stream().flatMap(data -> {
    return Arrays.stream(data.split(""));
    }).peek(s -> System.out.println("flatMap:" + s))
    .distinct().peek(s -> System.out.println("distinct:" + s))
    .count());

최종 처리 메소드

동작 메소드
매칭 allMatch(), anyMatch(), noneMatch()
수집 collect()
루핑 forEach()
집계 count(), max(), min(), average(), sum(), reduce()
조사 findFirst(), findAny()

매칭

Predicate 계열을 이용해 스트림 요소들이 특정 조건에 만족하는지 조사하는 메소드

  • boolean allMatch(Predicate<? super T> predicate) : 스트림의 모든 요소가 Predicate를 만족하면 true를 반환
  • boolean anyMatch(Predicate<? super T> predicate) : 스트림의 요소 중 하나라도 Predicate를 만족하면 true를 반환
  • boolean noneMatch(Predicate<? super T> predicate) : 스트림의 요소 중 하나라도 Predicate를 만족하지 않으면 true를 반환

집계

  • 기본 집계 메소드

    • 기본형 스트림의 통계 : count(), sum(), average(), min(), max()
    • T 타입 스트림의 통계 : count(), min(), max() (min, max의 경우 Comparator 필요)
  • reduce() 메소드

    • Optional<T> reduce(BinaryOperator<T> accumulator) : accumulator를 수행하고 Optional<T> 타입 반환
    • T reduce(T identity, BinaryOperator<T> accumulator) : identity를 초기값으로 하여, accumulator를 이용해 집계 연산
    • <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) : combiner를 이용해 병렬 스트림 결합
  • java.util.Optional<T>

    • T 타입 객체의 null 여부에 따라 다르게 동작하는 Wrapper 클래스
    • Optional 클래스의 정적 메소드를 이용해 Optional 객체 생성
      • public static <T> Optional<T> of(T value) : value가 null인 경우 NullPointerException을 발생시키는 Wrapping 메소드
      • public static <T> Optional<T> ofNullable(T value) : value가 null인 경우 empty()의 결과를 리턴하는 Wrapping 메소드
      • public static <T> Optional<T> empty() : 값이 비어있는 Optional 객체를 리턴
    • Optional 객체를 처리하는 메소드
      • public T get() : Optional의 값을 리턴하며, null일 경우 NullPointerException 발생
      • public void ifPresent(Consumer<? super T> consumer) : Optional 값이 null이 아닐 경우 consumer를 이용해 소비한다.
      • public T orElse(T other) : Optional의 값이 null일 경우 other를 반환한다.
      • public T orElseGet(Supplier<? extends T> other) : Optional의 값이 null일 경우 Supplier를 통해 공급받은 값을 반환한다.
      • public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X : Optional의 값이 null일 경우 exceptionSupplier에서 공급받은 예외를 throw

반복

forEach() 메소드로 스트림 요소를 순차적으로 Consumer<T>를 이용해 소비

  • void forEach(Comsumer<? super T> action) : 스트림의 각 요소를 action으로 소비

조사

첫번째 요소 또는 아무 요소를 조사하는 최종 처리 메소드. 필터링 등으로 인해 스트림에 요소가 남아있는지 확인할 수 있다.

  • Optional<T> findFirst() : 스트림의 첫 요소 또는 empty Optional 객체를 반환
  • Optional<T> findAny() : 스트림의 아무 요소나 가지는 Optional 객체를 반환

수집

필요한 요소를 수집하여 새로운 Collection으로 구성하여 반환하는 메소드

  • collect() 메소드

    • <R, A> R collect(Collector<? super T, A, R> collector) : collector를 이용해 새로운 Collection R에 담아 반환

      • Collectors의 정적 메소드: toList(), toSet(), toCollection(), toMap(), toConcurrentMap()
    • <R, A> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) : supplier를 통해 공급된 컨테이너 R에 accumulator를 이용해 T값을 저장. 병렬처리 스트림에 사용될 경우 combiner를 이용해 스레드별 컨테이너 R을 통합

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      String[] array = {"Java", "Is", "Fun", "Isn't", "It", "?"};
      List<String> list = Arrays.stream(array)
      .filter(s -> s.length() >= 3)
      .collect(Collectors.toList()); // ArrayList
      // .collect(Collectors.toCollection(LinkedList::new))
      System.out.println(list.getClass().getName() + ":" + list);


      Set<String> set = Arrays.stream(array)
      .filter(s -> s.length() >= 3)
      .collect(Collectors.toSet()); // HashSet
      // .collect(Collectors.toCollection(HashSet::new))
      System.out.println(set.getClass().getName() + ":" + set);

      Map<String, Integer> map = Arrays.stream(array)
      .filter(s -> s.length() >= 3)
      .collect(Collectors.toMap(s -> s, String::length)); // HashMap
      // .collect(Collectors.toCollection(s -> s, String::length, (oldVal, newVal) -> newVal, TreeMap::new))
      System.out.println(map.getClass().getName() + map);
  • Collectors의 정적 메소드를 이용한 그룹화와 분리

    • public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier) : classifier를 key값으로, 해당하는 값의 목록을 List인 value로 가지는 Map으로 스트림을 수집하는 Collector를 반환
      • public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) : List 대신 downstream collector로 수집
    • public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) : predicate 결과를 key로, 해당하는 값의 목록을 List value로 가지는 Map으로 스트림을 수집하는 Collector를 반환
      • public static <T, A, D> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream)) : List 대신 downstream collector로 수집
    1
    2
    3
    4
    5
    6
    7
    8
    9
    String[] array = {"Java", "Is", "Fun", "Isn't", "It", "?"};

    Map<Character, List<String>> map1 = Arrays.stream(array)
    .collect(Collectors.groupingBy(s -> s.charAt(0)));
    System.out.println(map1);

    Map<Boolean, List<String>> map2 = Arrays.stream(array)
    .collect(Collectors.partitioningBy(s -> s.length() >= 3));
    System.out.println(map2);
  • 집계를 위한 Collector

    • Downstream collector로 집계를 위한 Collector를 사용할 경우 유용하다.
    • counting(), summingP(), averagingP(), maxBy(), minBy(), reducing()
    1
    2
    3
    4
    5
    6
    String[] array = {"Java", "Is", "Fun", "Isn't", "It", "?"};

    Map<Character, Long> map = Arrays.stream(array)
    .collect(Collectors.groupingBy(s -> s.charAt(0),
    Collectors.counting()));
    System.out.println(map);

병렬 스트림

  • 병렬 스트림의 생성

    • stream() 대신 parallelStream()으로 변경
    • stream 생성 후 parallel()으로 병렬화
  • combiner를 이용해 병렬 스트림으로 생성된 컬렉션을 결합

    • BiConsumer<T, K> combiner : T 객체에 K 객체를 결합

Comment and share

람다식 (Lambda Expression)

람다식이란

  • Java 1.8에서 추가된 함수형 프로그래밍 기법
  • 객체지향 프로그래밍과 다르게, 비즈니스 로직만을 빠르게 구현하는 특징
  • 객체지향 언어인 Java에서 메소드를 함수처럼 사용하는 형식

람다식의 예

배열의 정렬

  • 기본 정렬 방식을 이용한 정렬

    1
    2
    3
    4
    String [] strings = {"fast", "campus", "java", "backend", "school"};
    System.out.println(Arrays.toString(strings));
    Arrays.sort(strings);
    System.out.println(Arrays.toString(strings));
    1
    2
    3
    public int compare(String o1, String o2) {
    return o1.compareTo(o2);
    }
  • 익명 내부 클래스를 이용한 정렬 방식 변경

    1
    2
    3
    4
    5
    6
    Arrays.sort(strings, new Comparator<String>() { // 객체를 생성하여 전달
    @Override
    public int compare(String o1, String o2) {
    return o1.compareTo(o2) * -1; // 내림차순
    }
    });
  • 람다식을 이용한 정렬 방식의 변경

    1
    Arrays.sort(strings, (o1, o2) -> {return o1.compareTo(o2) * -1;});
    1
    2
    3
    4
    Comparator<String> comp = (o1, o2) -> {
    return o1.compareTo(o2) * -1;
    };
    Arrays.sort(strings, comp);
  • 함수형 인터페이스 (Functional Interface)

    • 추상 메소드가 단 하나 존재하는지 검사

      1
      2
      3
      4
      5
      @FunctionalInterface
      public interface Comparator<T> {
      int compare(T o1, T o2);
      ...
      }

람다식의 형식

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(String x) -> { System.out.println(x); }

(x) -> { System.out.println(x); }

x -> System.out.println(x)

() -> System.out.println("x"); // () 생략 불가능

(x) -> {
System.out.println(x);
return x;
}

(x) -> "x: " + x

// x -> "x :" + x // () 생략 불가능

람다식의 변수 참조

  • 익명 내부 클래스와 동일한 규칙으로 변수 참조

  • 문법적으로 this의 사용법만 다름

    • 익명의 내부 클래스와 달리 외부 클래스를 참조
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    @FunctionalInterface
    interface FunctionalInterface {
    String method();
    }

    class Main {
    void functionalMethod(FunctionalInterface obj) {
    System.out.println(obj.method());
    }

    public static void main(String[] args) {
    functionalMethod(()-> {
    System.out.println("this: " + this);
    System.out.println("OuterClass.this: " + Main.this);
    return "Lambda expression used."
    });

    functionalMethod(new FunctionalInterface() {
    @Override
    String method() {
    System.out.println("this: " + this);
    System.out.println("OuterClass.this: " + Main.this);
    return "Anonymous inner class used."
    });
    }

    }

표준 함수형 인터페이스

  • 자주 사용되는 함수형 인터페이스를 정의해 둔 API
  • Consumer, Supplier, Function, Operation, Predicate 계열이 있다.
계열 입력 출력 메소드 설명
Consumer O X void accept(T) 입력을 소비
Supplier X O T get() 출력을 공급
Function O O T apply(R) 입력 -> 출력 함수 매핑
Operation O O T apply(T) 입력을 연산하여 동일 타입의 출력으로 리턴
Predicate O boolean boolean test(T) 입력을 판단

표준 함수형 인터페이스의 종류

Consumer 계열

인터페이스 메소드
Consumer<T> void accept(T t)
BiConsumer<T, U> void accept(T t, U u)
IntConsumer void accept(int value)
LongConsumer void accept(long value)
DoubleConsumer void accept(double value)
ObjIntConsumer<T> void accept(T t, int value)
ObjLongConsumer<T> void accept(T t, long value)
ObjDoubleConsumer<T> void accept(T t, double value)

Supplier 계열

인터페이스 메소드
Supplier<T> T get()
BooleanSupplier boolean getAsBoolean()
IntSupplier int getAsInt()
LongSupplier long getAsLong()
DoubleSupplier double getAsDouble()

Function 계열

인터페이스 메소드
Function<T, R> R apply(T t)
BiFunction<T, U, R> R apply(T t, U u)
PFunction<R> R apply(p value)
PtoQFunction q applyAsQ(p value)
ToPFunction<T> p applyAsP(T t)
ToPBiFunction<T, U> p applyAsP(T t, U u)
1
2
P, Q : Int, Long, Double
p, q : int, long, double

Operator 계열

인터페이스 메소드
UnaryOperator<T> T apply(T t)
BinaryOperator<T> T apply(T t1, T t2)
IntUnaryOperator int applyAsInt(int value)
LongUnaryOperator long applyAsLong(long value)
DoubleUnaryOperator double applyAsDouble(double value)
IntBinaryOperator int applyAsInt(int value1, int value2)
LongBinaryOperator long applyAsLong(long value, long value2)
DoubleBinaryOperator double applyAsDouble(double value, double value2)

Predicate 계열

인터페이스 메소드
Predicate<T> boolean test(T t)
BiPredicate<T, U> boolean test(T t, U u)
IntPredicate boolean test(int value)
LongPredicate boolean test(long value)
DoublePredicate boolean test(double value)

표준 함수형 인터페이스의 메소드

andThen(), compose()

  • 두 개 이상의 함수형 인터페이스를 연결하기 위해 사용

    • A.andThen(B): A를 먼저 실행하고 B를 실행. Consumer, Function, Operator 계열 지원
    1
    2
    3
    Function<String, String> funcOne = x -> "str: " + x;
    Function<String, String> funcTwo = x -> "{" + x + "}";
    Function<String, String> andThen = funcOne.andThen(funcTwo); // {str: x}
    • A.compose(B): B를 먼저 실행하고 A를 실행. Function, Operator 계열 지원
    1
    2
    3
    IntUnaryOperator multTwo = x -> x * 2;
    IntUnaryOperator addTen = x -> x + 10;
    IntUnaryOperator multTwo.compose(addTen); // (x + 10) * 2

and(), or(), negate(), isEqual()

  • Predicate 계열의 기본 메소드

    • and(), or(), negate()
    • 각각 &&, ||, !의 동작을 한다.
    1
    2
    3
    4
    DoublePredicate predOne = x -> x > 0.5;
    DoublePredicate predTwo = x -> x < 0.0;
    DoublePredicate predThree = predOne.or(predTwo);
    DoublePredicate predFour = predThree.negate();
  • Predicate 계열의 클래스 메소드

    • isEqual()
    1
    Predicate<String> isEqualToString = Predicate.isEqual("String");

minBy(), maxBy()

  • BinaryOperator 클래스의 클래스 메소드

    • Comparator<T>를 파라미터로 받아 최소값/최대값을 구하는 BinaryOperator<T>를 리턴
    1
    2
    3
    4
    5
    6
    7
    BinaryOperator<String> minBy = BinaryOperator.minBy((o1, o2) -> {
    return len(o1) > len(o2) ? 1 : -1;
    });

    BinaryOperator<Integer> maxBy = BinaryOperator.maxBy((val1, val2) -> {
    return val1.compareTo(val2);
    });

람다식에 메소드/생성자 사용

  • 이미 구현된 메소드가 있는 경우, 다양한 방식으로 람다식을 대체 가능

ClassName::instanceMethod

  • 첫번째 파라미터를 객체로, 두번째 파라미터를 메소드 입력으로 사용

    1
    2
    String[] strings = { "A", "B", "D", "C" };
    Arrays.sort(strings, String::compareTo);

ClassName::classMethod

  • 클래스 메소드의 입력으로 모든 파라미터가 사용됨

    1
    Function<String, Integer> parser = Integer::parseInt;

instance::instanceMethod

  • 주어진 객체의 메소드를 호출

    1
    2
    3
    String string = "StringA";
    Predicate<String> pred = string::equals;
    System.out.println(pred.apply("StringA"));

ClassName::new

  • 생성자를 이용하여 객체를 생성하는 람다식

    1
    2
    IntFunction<String> func = String::new;
    String string = func.apply(10);

ClassName[]::new

  • 배열을 생성하는 람다식

    1
    2
    IntFunction<String[]> func = String[]::new;
    String [] strings = func.apply(100);

Comment and share

내부 클래스 (Inner Classes)

내부 클래스란

  • 클래스 내부에 선언하는 클래스로 중첩 클래스(Nested Class)라고도 부름
  • HAS-A 관계에 있는 클래스가 해당 클래스에서만 사용될 경우 주로 사용

내부 클래스의 종류

  • 클래스 영역에 선언
    • 인스턴스 내부 클래스: 외부 클래스의 멤버 변수처럼 사용 가능
    • 클래스 내부 클래스: static이 붙은 정적인 내부 클래스
  • 로컬 영역에 선언
    • 로컬 내부 클래스: 선언된 영역의 Scope 내에서 사용 가능
    • 익명 내부 클래스: 객체를 일회성으로 생성하기 위한 이름이 없는 클래스

다양한 내부 클래스

인스턴스 내부 클래스 (Instance Inner Class)

  • 클래스 영역에 static 키워드 없이 선언된 클래스

  • 외부 클래스의 private을 포함한 모든 멤버에 접근 가능

  • 외부 클래스 객체를 통해서만 생성 가능

  • static 멤버 변수는 사용할 수 없으나, static final은 사용 가능

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class Outer {
    class InstanceInner {
    int innerMemberVar = 1;
    //static int staticMemberVar = 1;
    static final int CONSTANT_VAR = 10;

    void innerMethod() {
    System.out.println(innerMemberVar);
    System.out.println(outerMemberVar);
    }
    }

    private int outerMemberVar = 2;

    void outerMethod() {
    IstanceInner obj = new InstanceInner();
    obj.innerMethod();
    }

    public static void main(String[] args) {
    Outer outer = new Outer();
    InstanceInner inner = outer.new InstanceInner();
    inner.innerMethod();
    }

    }
  • 외부 클래스의 멤버 변수와 이름이 겹치는 경우 this 활용

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class Outer {
    class InstanceInner {
    int var = 1;

    void innerMethod() {
    int var = 0;
    System.out.println(var);// 0
    System.out.println(this.var);// 1
    System.out.println(Outer.this.var);// 2
    System.out.println(Outer.y); // 3 static variable
    }
    }

    private int var = 2;
    private static int y = 3;

    public static void main(String[] args) {
    Outer outer = new Outer();
    InstanceInner inner = outer.new InstanceInner();
    inner.innerMethod();
    }

    }

클래스 내부 클래스 (Class Inner Class)

  • 클래스 영역에 static 키워드와 함께 선언된 내부 클래스

  • 외부 클래스 객체가 없어도 생성 가능

  • 외부 클래스의 private을 포함한 모든 멤버에 접근 가능

  • static 멤버 변수를 가질 수 있음

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class Outer {
    static class ClassInner {
    int innerVar = 1;
    static int staticInnerVar = 100;

    void innerMethod() {
    Outer outer = new Outer();
    System.out.println(outer.outerVar);
    System.out.println(innerVar);
    }
    }

    private int outerVar = 2;

    void outerMethod() {
    ClassInner inner = new ClassInner();
    inner.innerMethod();
    }

    public static void main(String[] args) {
    ClassInner inner = new ClassInner();
    inner.innerMethod();
    }
    }

로컬 내부 클래스 (Local Inner Class)

  • 클래스 영역이 아닌 로컬 영역에서 선언된 클래스

    • 메소드, 생성자, 초기화 블록의 내부
  • 정적 변수는 가질 수 없으나, static final 변수는 가질 수 있음

  • 로컬 영역의 변수 다음과 같은 사항을 따름

    • Java1.7: final로 선언된 변수에만 접근 가능
    • Java1.8: 모든 변수에 접근 가능하나, final로 간주되어 새로운 값 할당 불가
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void outerMethod() {
    int var = 1; // 메소드 호출 스택

    class LocalInner {
    void innerMethod() {
    System.out.println(var);
    }
    }

    LocalInner inner = new LocalInner(); // 힙 영역
    inner.innerMethod();
    }

익명의 내부 클래스 (Anonymous Inner Class)

  • 로컬 내부 클래스와 동일하나, 이름이 없어 선언 즉시 한 번 사용 가능

  • 추상 클래스나 인터페이스의 구현에 많이 사용

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    interface IFoo {
    void do();
    }

    class AnonymousInnerClassTest {
    static void useFoo(IFoo foo) {
    foo.do();
    }

    public static void main(String[] args) {
    useFoo(new IFoo() {
    @Override
    void do() {
    System.out.println("Do!");
    }
    });
    }
    }

Comment and share

HTML 1

HTML

hyper text markup language

html5 부터 xml을 포함 엄격한 문법

XHTML 2.0 실패를 인정하며 WHATWG의 표준안을 수용하여 HTML5를 만듬

HTML4.01, XHTML1.0 과 HTML5와 의 차이점


  • Block/Inline 구분하지 않게 됨

HTML의 콘텐츠 모델

Comment and share

예외 처리 (Handling Exceptions)

오류와 예외

  • 프로그램이 동작 중에 비정상 종료가 발생하는 상황
  • 심각도에 따라 오류와 예외로 분류할 수 있음

오류 (Errors)

  • 시스템의 메모리가 부족하거나, 무한히 메소드 호출이 발생하는 등 프로그램 복구가 불가능한 상황
  • 오류가 발생하는 원인을 찾아서 제거하는 방법으로 해결

예외 (Exceptions)

  • 오류에 비해 심각도가 낮으며, 프로그램의 정상적인 흐름을 방해
    ex) 파일명으로 파일을 읽으려 하는데, 파일을 찾을 수 없음
  • 문제 상황을 해결하는 로직을 별도로 구성하여 해결 가능

예외 처리

  • 예외가 발생했을 때, 이 상황을 감지하고 해결하기 위해 동작하는 코드
  • try ~ catch 구문과 Exception 클래스와 그 자식 클래스를 활용

Throwable 클래스

  • Throwable 클래스는 Exception과 Error 클래스에 의해 상속
    • Exception
      • Checked Exceptions: 예외 처리되지 않으면 컴파일이 되지 않는 예외 - Exception Class 상속
      • Unchecked Exception: 예외 처리되지 않아도 컴파일이 되는 예외 - RuntimeException Class 상속
    • Error: 프로그램이 복구 불가능한 상황

Exception 클래스

  • Throwable 클래스의 주요 메소드

    메소드 설명
    public String getMessage() 발생한 예외에 대한 메세지를 반환
    public String getLocalizedMessage() 오버라이드하여 추가 메세지 제공 (오버라이드하지 않으면 getMessage()와 동일)
    public Throwable getCause() 예외의 원인이 되는 Throwable 객체 반환
    public void printStackTrace() 예외가 발생된 메소드가 호출될 때의 Method call stack을 출력

예외 처리 기법

try ~ catch 구문

1
2
3
4
5
6
7
try {
// 예외가 발생할 수 있는 코드 영역
// 예외 발생 시 예외 객체를 던짐 (throw)
} catch (Exception e) { // 던져진 예외를 받음 (catch)
// Exception의 자식 클래스로 지정하여 특정 클래스를 받는다.
// 예외 상황을 처리하는 코드
}

다중 예외 처리

  • 여러 개의 catch 구문을 사용하면 다중 예외를 처리할 수 있음

  • if ~ else if 구문처럼, 순차적으로 검사하면서 적용 가능한 예외를 처리

  • 다형성이 적용되어, 자식 예외를 처리 가능

  • 한가지의 catch 문에 대해서 예외가 잡힘

  • 상위 Exception을 제일 밑의 catch문에 배치

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    try {
    // 예외 발생 가능 코드 영역
    } catch (AException e) {
    // A예외 처리
    } catch (BException e) {
    // B예외 처리
    } catch (CException e) {
    // C예외 처리
    } catch (Exception e) {
    // 나머지 모든 예외 처리
    }

try ~ catch ~ finally 구문

  • try 구문 실행 중에 어떤 일이 발생해도 반드시 실행되어야 하는 구문은 finally 블록에 작성

  • try 구문 내에 return문이 있는 경우에도 finally 블록은 실행됨

  • try 구문 내에서 접근한 System 자원을 안전하게 복구하기 위해 사용

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    FileInputStream file = null;
    try {
    file = new FileInputStream(fileName);
    file.read();
    } catch (IOException e) {
    System.out.println("파일처리실패");
    } finally {
    if (file != null) {
    try {
    file.close();
    } catch (IOException e) {
    System.out.println("파일인풋스트림 종료 실패");
    }
    }
    }

try ~ with ~ resources 구문

  • Java1.7에서 추가된 기능

  • AutoClosable 인터페이스를 구현하는 리소스를 자동으로 close 처리

    1
    2
    3
    4
    5
    try (FileInputStream file = new FileInputStream(fileName)) {
    file.read();
    } catch (IOException e) {
    System.out.println("파일처리실패");
    }

예외 처리 위임

throws

  • 호출한 메소드로 예외 처리를 전달하는 방식

  • Checked Exception의 경우 throws로 위임 가능하나, 최종적으로 try ~ catch를 만나야 함

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class CheckedException {
    void methodA() throws ClassNotFoundException {
    Class.forname("A Class");
    }

    void methodB() {
    try {
    methodA();
    } catch (ClassNotFoundException e) {
    ...
    }
    }
    }
  • Unchecked Exception의 경우 throws로 위임하지 않아도 자동으로 전달

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class UncheckedException {
    void methodA() {
    int x = 10;
    x = 10/0;
    }
    void methodB() {
    try {
    methodA();
    } catch (ArithmeticException e) {
    ...
    }
    }
    }
  • 메소드를 오버라이드한 경우, 조상 클래스의 메소드보다 조상 예외는 던질 수 없음

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Foo {
    void methodA() throws IOException {}
    }

    class BarOne extends Foo{
    void methodA() throws IOException {} // possible
    }

    class BarTwo extends Foo{
    void methodA() throws FileNotFoundException {} // possible
    }

    class BarThree extends Foo{
    void methodA() throws Exception {} // *NOT* possible
    }

throw

  • 예외를 발생시키는 키워드

  • new 키워드로 새 Exception 객체를 생성하여 예외 내용을 작성

    1
    2
    3
    4
    5
    6
    7
    void exceptMethod() throws Exception {
    ...
    if (Err) {
    throw new Exception("Some Error"); // 예외 발생 및 Message 전달
    }
    ...
    }

사용자 정의 예외 (Custom Exceptions)

  • Exception 또는 RuntimeException 클래스를 상속하여 작성

    • Exception을 상속한경우 Checked Exception이 되어 반드시 예외를 처리해야 한다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class MyException extends RuntimeException {
    enum ErrorCode {
    ERROR_A, ERROR_B;
    }

    private ErrorCode errorCode;

    public MyException(ErrorCode errorCode, String message) {
    super(message);
    this.errorCode = errorCode;
    }

    @Override
    public String getLocalizedMessage() {
    String message = getMessage();
    ...
    return localizedMessage;
    }
    }

Comment and share

클래스 다이어그램

Class Diagram

  • 클래스의 구성요소 및 클래스 간의 관계를 묘사하는 다이어그램
  • 시간에 따라 변하지 않는 정적인 시스템 구조를 표현

클래스 다이어그램의 목적

  • 문제 해결을 위한 도메인 구조를 표현

Unified Modeling Language (UML)

  • 표준화된 모델링 표기 체계
  • 클래스를 구현하기 전에 설계하는 단계에서 사용
    • 클래스 이름, 파라미터, 리턴 타입 등

IDEA에서 UML 작성하기 (Plant UML)

  • Plant UML 플러그인 설치

  • Graphviz 설치 https://graphviz.org/download/

  • Plant UML의 문법

    • 클래스, 추상클래스, 인터페이스

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      interface IFoo {
      void method();
      }

      abstract class Bar

      class Foo {
      int [] array;
      int add(int x, int y);
      setArray(int [] array);
      void method();
      }
    • 가시성 (Visibility)

      • public : +
      • protected : #
      • default : ~
      • private : -
    • 클래스 간의 관계

      • Extension <|-
      • Aggregation o--
      • Composition *--
    • 타이틀

      1
      title 클래스 다이어그램 제목
    • 노트

      1
      2
      3
      note left of Foo
      노트 <b>내용</b> 작성
      end note

IDEA에서 UML 자동 생성

https://www.jetbrains.com/help/idea/class-diagram.html

Comment and share

Wrapper 클래스 (Wrapper Class)

Wrapper 클래스란

  • 기본형 타입을 객체로 사용하기 위한 클래스

Wrapper 클래스의 종류

기본형 Wrapper 클래스
byte Byte
char Character
short Short
int Integer
long Long
float Float
double Double
boolean Boolean

Wrapper 객체 생성

  • 생성자를 이용한 객체 생성

    1
    Integer integer = new Integer(10);
  • valueOf를 이용한 객체 생성

    1
    Integer integer = Integer.valueOf(10);

Autoboxing & Unboxing

  • 오토박싱 (Autoboxing)

    • Java1.5부터 추가된 기능으로, 객체로 다루어야 할 때 자동으로 Wrapper 클래스로 변경하는 기능
  • 언박싱 (Unboxing)

    • Wrapper 객체를 기본형으로 자동으로 변경하는 기능
    1
    2
    3
    int i = 10;
    Integer wrapped = i;
    int b = 20 + wrapped;

Wrapper 타입의 값 비교

  • Wrapper 타입은 객체이므로, ==를 이용하여 값을 비교할 수 없다.

    1
    2
    3
    4
    5
    6
    Integer intOne = new Integer(100);
    Integer intTwo = new Integer(100);

    System.out.println(intOne == intTwo); // false
    System.out.println(intOne.equals(intTwo)) // true
    System.out.println(intOne == 100) // true (Unboxing)

문자열의 기본 자료형 변환

  • Parsing 정적 메소드를 이용한 변환

    1
    2
    int x = Integer.parseInt("100");
    long y = Long.parseLong("512345124");
  • Wrapper 객체로의 변환

    1
    2
    Integer intObj = Integer.valueOf("1000");
    Integer intObjTwo = new Integer("1234");

Comment and share

Yechan Kim

author.bio


author.job