Java Programming [Day 4]

 Published On

Java 예제 4일만에 뽀개기 - Day 4

예외 : 잘못된 코드, 부정확한 데이터, 예외적인 상황에 의하여 발생하는 오류

import java.util.Scanner;

public class DivideByZero {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        System.out.print("분자 : ");
        int x = sc.nextInt();
        System.out.print("분모 : ");
        int y = sc.nextInt();
        int result = x / y;
        // y에 0을 넣어주면 위의 문장이 실행이 되지 않는다
        System.out.println("Result : " + result);
        
        sc.close();
    }

}

// 분모가 0인 경우 ArithmeticException이 발생한다
// Exception이 발생할 수 있는 코드를 try 블락 안에 넣는다.
// catch 블락이 exception의 종류에 따라 처리할 코드를 넣는다.
// exception 발생하건 안하건 finally block 실행

import java.util.Scanner;

public class DivideByZero {
    public static void main(String[] args) {
        int result = 0;
        Scanner sc = new Scanner(System.in);
        
        System.out.print("분자 : ");
        int x = sc.nextInt();
        System.out.print("분모 : ");
        int y = sc.nextInt();
        
        try {
            result = x / y;
        } catch(ArithmeticException e) {
            System.out.println("Can not divide by 0");
        } finally {
            System.out.println("finally 블락은 option");
            sc.close();
        }
        System.out.println("Program reaches here");
        System.out.println("Result : " + result);
    }
}

/*
public class ArrayException {
    public static void main(String[] args) {
        int[] array = { 1, 2, 3, 4, 5 };
        
        for(int i = 0; i <= array.length; i++) 
            System.out.println(array[i] + " ");
        
        System.out.println("Program ends\n");
    }

}
*/

public class ArrayException {
    public static void main(String[] args) {
        int[] array = { 1, 2, 3, 4, 5 };
        
        try {
            for(int i = 0; i <= array.length; i++) 
                System.out.println(array[i] + " ");
        } catch(ArrayIndexOutOfBoundsException e) {
            System.out.println("Array index out of bounds exception");
            
            System.out.println(e.getMessage()); // 이 두 라인을 적으면(catch안에 꼭 적어주자)
            e.printStackTrace(); // 어느 위치에서 어떤 예외가 발생했는지 알려준다
        } finally {
            System.out.println("Finally block");
        }
        System.out.println("Program ends\n");
    }

}

// IOException을 처리하지 않아 compile error 발생
import java.io.PrintWriter;
import java.io.FileWriter;

public class FileException {
    private int[] list;
    private static final int SIZE = 10;
    
    public FileException() {
        list = new int[SIZE];
        
        for(int i =  0; i < SIZE; i++)
            list[i] = i;
        writeList();
    }
    
    public void writeList() {
        PrintWriter out = null;
        
        out = new PrintWriter(new FileWriter("outfile.txt"));
        for(int i = 0; i < SIZE; i++)
            out.println("Array element " + i + " = " + list[i]);
            
    }
    
    public static void main(String[] args) {
        new FileExeption();
    }
}

import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException; // IOException도 하나의 클래스이므로

public class FileException {
    private int[] list;
    private static final int SIZE = 10;
    
    public FileException() {
        list = new int[SIZE];
        
        for(int i =  0; i < SIZE; i++)
            list[i] = i;
        writeList();
    }
    
    public void writeList() {
        PrintWriter out = null;
        
        try {
            out = new PrintWriter(new FileWriter("outfile.txt"));
            for(int i = 0; i < SIZE; i++)
                out.println("Array element " + i + " = " + list[i]);
        } catch(IOException e) {
            System.out.println("IOException");
        } finally {
            if(out != null)
                out.close();
        }
    }
    
    public static void main(String[] args) {
        new FileException(); // outFile이라는 텍스트가 생성
    }
}

예외의 종류
1. Error
   : 너무 심각해서 할 수 있는 범이 없음 -> 통과

2. RuntimeException
   : 프로그래밍 버그이므로 스스로 고쳐야함(처리 안해도 컴파일 가능) -> 통과

3. Error나 RuntimeException이 아닌 예외 // Checked Exception -> try ~ catch 사용
   : 반드시 처리해야함(안하면 컴파일이 안됨) -> 검사

- RuntimeException의 종류
    1. ArithmeticException : 어떤 수를 0으로 나눌 때 발생한다.
    2. NullPointerException : 널 객체를 참조할 때 발생한다.
    3. ClassCastException : 적절치 못하게 클래스를 형변환하는 경우 발생한다.
    4. NegativeArraySizeException : 배열의 크기가 음수인 경우 발생한다.
    5. OutOfMemoryException : 사용 가능한 메모리가 없는 경우 발생한다.
    6. NoClassDefFoundException : 원하는 클래스를 찾지 못하였을 경우 발생한다.
    7. ArrayIndexOutOfBoundsException : 배열을 참조하는 인덱스가 잘못된 경우 발생한다.

NumberException(상위 클래스) > TooSmallException(하위 클래스)
TooSmallException이 먼저 나오고 NumberException이 나와야지 그렇지 않으면 NumberException이 에러를 다 잡아버린다                                                                                                                                                                                             

public class ExceptionHierarchy {

    public static void main(String[] args) {
        int[] array = { 1, 2, 3, 4, 5 };
        
        try {
            for(int i = 0; i <= array.length; i++)
                System.out.println(array[i] + " ");
        } catch(ArrayIndexOutOfBoundsException e) {
            System.out.println("Exception");
        } catch(Exception e) {
            System.out.println("ArrayIndexOfBoundsException");
        } /*catch(ArrayIndexOutOfBoundsException e) {
            System.out.println("Exception");
        }*/ // 밑에 있으면 위의 Exception이 모든 예외를 처리한다
    }
}

예외를 처리하는 방법
1. try~catch
2. throws

// Exception을 함수에서 직접 처리하는 방법

public class Test {

    public static void main(String[] args) {
        int[] array = { 1, 2, 3, 4, 5 };
        
        method(array);
    }
    
    public static void method(int[] array) {
        try {
            for(int i = 0; i <= array.length; i++) 
                System.out.println(array[i] + " ");
            } catch(ArrayIndexOutOfBoundsException e) {
                System.out.println("Array index out of bounds exception");
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
    }
}

// Exception을 호출 함수에 전달하여 처리하는 방법

public class Test {
    public static void main(String[] args) {
        int[] array = { 1, 2, 3, 4, 5 };
        
        try {
            method(array);
        } catch(ArrayIndexOutOfBoundsException e) {
            System.out.println("Array index out of bounds exception");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
    
    public static void method(int[] array) throws ArrayIndexOutOfBoundsException 	{
        for(int i = 0; i <= array.length; i++)
            System.out.println(array[i] + " ");
    }
}

// Exception 객체를 생성하고 호출 함수에 전달, 처리하는 방법

public class Test {
    public static void main(String[] args) {
        int[] array = { 1, 2, 3, 4, 5 };
        
        try {
            method(array);
        } catch(ArrayIndexOutOfBoundsException e) {
            System.out.println("Array index out of bounds exception");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
    // 함수 뒤에다 이 Exception이 발생할 수 있다를 표현하기 위해서는 throws를 사용한다
    public static void method(int[] array) throws ArrayIndexOutOfBoundsException {
        for(int i = 0; i <= array.length; i++) {
            if(i == array.length)
                // 실제 이 부분에 대해서 Exception이 발생할 수 있다를 표현하기 위해서는 throw를 사용한다
                throw new ArrayIndexOutOfBoundsException(); // Exception 객체 생성하여 전달
            System.out.println(array[i] + " ");
        }
    }
}

// RuntimeErrorException의 경우 throws의 구문을 사용할 수 있다

// 사용자 정의 exception class
// 함수에서 exception을 처리하는 방법

import java.util.Scanner;

class MyException extends Exception {
    public MyException() {
        super("This is my exception");
    }
}

public class MyExceptionTest {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        System.out.print("Enter numerator : ");
        int x = sc.nextInt();
        System.out.print("Enter denominator : ");
        int y = sc.nextInt();
        
        divide(x, y);
    }
    
    public static void divide(int x, int y) {
        int result = 0;
        
        try {
            if(y == 0)
                // 자신이 만든 exception이므로 throw를 하여 객체를 생성해주어야 한다
                throw new MyException();
            result = x / y;
        } catch(MyException e) {
            System.out.println("분모가 0입니다.\n");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        System.out.println("Result is " + result);
    }

}

// Exception을 호출 함수에 전달하여 처리하는 방법

import java.util.Scanner;

class MyException extends Exception {
    public MyException() {
        super("This is my exception");
    }
}

public class MyExceptionTest {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        System.out.print("Enter numerator : ");
        int x = sc.nextInt();
        System.out.print("Enter denominator : ");
        int y = sc.nextInt();
        try {
            divide(x, y);
        } catch(MyException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
    
    public static void divide(int x, int y) throws MyException {
        if(y == 0)
            throw new MyException();
        else
            System.out.println(x / y);
    }

}

제네릭 프로그래밍
- 다양한 타입의 객체를 동일한 클래스로 사용한다
- 첫 번째 방법 : 일반적인 객체를 처리하려면 Object 참조 변수를 사용
             : Object 참조 변수는 어떤 객체이던지 참조할 수 있다

public class Box<T> { // T : 타입 매개변수(객체 생성시 타입 지정)
    private T data;
    
    public void set(T d) {
        data = d;
    }
    
    public T get() {
        return data;
    }

    public static void main(String[] args) {
//		Box<String> b = new Box<String>(); // String 타입으로 변수 선언
        Box<String> b = new Box<>(); // Java 7부터는 생성자 호출이 타입인수 생략 가능, diamond
        b.set("Hello World"); // b는 String을 가질 수 있는 변수가 되었다
        System.out.println(b.get()); 
        String str = b.get(); // type T가 String으로 형변환 불필요
        
        Box<Integer> i = new Box<>();
        i.set(100); // i.set(new Integer(100)); (auto boxing)
        System.out.println(i.get());Integer num = i.get();
        int n = i.get(); // auto unboxing(Integer 객체를 int로 변환)
        System.out.println(n);
//		i.set("String"); // type이 다를 경우 error message
    }
}

public class Point<T> {
    private T x, y;
    
    public Point(T x, T y) {
        this.x = x;
        this.y = y;
    }
    
    public void set(T o1, T o2) {
        x = o1; 
        y = o2;
    }
    
    public T getX() {
        return x;
    }
    
    public T getY() {
        return y;
    }

    public static void main(String[] args) {
        Point<Integer> g1 = new Point<>(1, 2);
        g1.set(10, 20);
        System.out.println(g1.getX() + ", " + g1.getY());
        
        Point<Double> g2 = new Point<>(1.1, 2.2);
        g2.set(1.2, 3.4);
        System.out.println(g2.getX() + ", " + g2.getY());
    }

}

- 타입 매개 변수의 표기
    1. K - Key
    2. N - Number
    3. T - Type(대체로 많이 씀)
    4. V - Value
    5. E - Element

- 다중 타입 매개 변수

// 타입 매개변수는 여러개를 지정할 수 있다

class OrderedPair<K, V> { // Key, Value
    private K key;
    private V value;

    public OrderedPair(K k, V v) {
        key = k;
        value = v;
    }

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }
}

public class OrderedPairTest {
    public static void main(String[] args) {
        OrderedPair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8); // 파라미터 지정
        OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world"); // 파라미터 생략

        System.out.println(p1.getKey());
        System.out.println(p1.getValue());

        System.out.println(p2.getKey());
        System.out.println(p2.getValue());

        // generic class의 객체 생성에서 파라미터를 생략하면 모든 파라미터를
        // Object로 간주한다.
        // Java 5 이전에 작성했던 프로그램들과의 호환성을 유지하기 위함
        // 이것을 raw type이라고 한다

        OrderedPair p3 = new OrderedPair("Hello", 10);
        System.out.println(p3.getKey());
        System.out.println(p3.getValue());
    }

}

제네릭 메소드
- 메소드에서도 타입 매개 변수를 사용하여서 제네릭 메소드를 정의할 수 있다.
- 타입 매개 변수의 범위가 메소드 내부로 제한된다.
- Comparable까지는 몰라도 됨

// 일반 클래스의 메소드를 generic 메소드로 작성

class GenericMethod {
    public <E> void printArray(E[] array) { // 타입 매개변수는 반드시 수식자와 반환형 사이에 기술
        for(int i = 0; i < array.length; i++) 
            System.out.print(array[i] + " ");
        System.out.println("\n");
    }
}

public class GenericMethodTest {
    public static void main(String[] args) {
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] dArray = { 1.1, 2.2, 3.3, 4.4, 5.5 };
        Character[] cArray = { 'H', 'E', 'L', 'L', 'O' };
        String[] sArray = { "Lee", "Kim", "Choi" }; // 새로운 타입 추가 가능
        
        GenericMethod gm = new GenericMethod();
        gm.<Integer>printArray(intArray); // 타입 생략 가능
        gm.printArray(dArray);
        gm.printArray(cArray);
        gm.printArray(sArray);
    }

}

컬렉션
- 자바에서 자료 구조를 구현한 클래스
- 리스트, 스택, 큐, 집합, 해쉬 테이블

1. Vector 클래스

// Vector 객체는 자동으로 크기 조절
// 어떤 타입도 저장 가능하지만(raw type) generic class의 특성을 사용하기 위하여 타입을 정의한다.

import java.util.Vector;

public class VectorTest {

    public static void main(String[] args) {
        Vector vc = new Vector(); // 모든 종류의 객체 저장 가능(raw type)
        
        System.out.println(vc.size() + ", " + vc.capacity() + "\n");
        vc.add("Hello World"); // 0번방에 "Hello World"라는 string을 집어넣는다(배열의 형태로 이루어진다)
        vc.add(new Integer(10)); // 1번방에 정수형 10을 집어넣는다.
        vc.add(20); // auto boxing // 2번방에 정수 20을 집어넣는다.
        vc.add(3.14); // 3번방에 실수 3.14를 집어넣는다.
        vc.add(new Double(10.5)); // 4번방에 실수형 10.5를 집어넣는다.
        vc.add(1, "Java"); // 1번방에 "Java"라는 string을 집어넣는다(기존에 있던 box의 구성원들은 뒤로 하나씩 밀린다)
        vc.insertElementAt("new string", 1); // 1번방에 "new string"을 집어넣는다(기존에 있던 box의 구성원들은 뒤로 하나씩 밀린다)
        for(int i = 0; i < vc.size(); i++) 
            System.out.println(i + " : " + vc.get(i));
        
        System.out.println(vc.size() + ", " + vc.capacity());
        System.out.println(vc.contains(20)); // 원소 중에 20이 있는가? True or False
        System.out.println(vc.lastElement());
        System.out.println(vc);
    }
}

import java.util.Vector;

public class VectorTest {
    public static void main(String[] args) {
        Vector<String> str = new Vector<>(); // String 객체만 저장 가능
        str.add("My");
        str.add("Vector");
        str.add("Test");
        for(String s : str) 
            System.out.println(s);
        str.remove(0);
        str.add(0, "Your");
        str.set(1, "vector"); // 기존에 "Test" 문자열 삭제
        str.insertElementAt("string", 1);
        str.add("!!!"); // 인덱스를 사용하지 않으면 마지막에 들어가진다.
        for(String s : str)
            System.out.println(s);
        
        Vector<Integer> array = new Vector<>(); // Integer 객체만 저장 가능
        for(int i = 0; i < 11; i++) {
            array.add(i);
            System.out.println(array.get(i));
        }
        System.out.println(array.size() + ", " + array.capacity());
        System.out.println(array.contains(20)); // True or False
        System.out.println(array.lastElement());
        System.out.println(array);
    }
}

자바에서의 컬렉션
1. 인터페이스 - Collection, Set, List, Map, Queue
2. 클래스

- ArrayList
// 가변 길이의 배열 구현
// 장점 : list 원소에 점자를 이용한 빠른 접근
// 단점 : list 중간에 삽입, 삭제할 경우 list 전체 변경

import java.util.*;

public class ArrayListTest {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        
        list.add("Milk");
        list.add("Bread");
        list.add("Butter");
        list.add(1, "Apple");
        list.set(2, "Grape");
        list.remove(3);
        list.add("Apple");
        
        for(int i = 0; i < list.size(); i++) // for loop을 이용한 출력
            System.out.println(list.get(i));
        System.out.println();
        
        Iterator<String> e = list.iterator(); // Iterator(반복자)를 이용한 출력
        String s;
        while(e.hasNext()) { // Iterator의 e 다음 원소가 있다면
            s = (String)e.next(); // Object를 리턴하기 때문에 형변환 필요
            System.out.println(s);
        }
        System.out.println();
        
        for(String str : list) // Iterator interface를 개선한 for-each loop
            System.out.println(str); // 하나씩 꺼내서 뭘 하고 싶다면 for-each loop 사용
        System.out.println();
        
        System.out.println(list); // println을 사용한 출력 방법
    }

}

- LinkedList : 중간에 삽입, 삭제를 하고 싶다면

import java.util.*;

public class ArrayListTest {

    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        
        list.add("Milk");
        list.add("Bread");
        list.add("Butter");
        list.add(1, "Apple");
        list.set(2, "Grape");
        list.remove(3);
        list.add("Apple");
        
        for(int i = 0; i < list.size(); i++) // for loop을 이용한 출력
            System.out.println(list.get(i));
        System.out.println();
        
        Iterator<String> e = list.iterator(); // Iterator(반복자)를 이용한 출력
        String s;
                // hashNext() : 아직 방문하지 않은 원소가 있으면 true 반환
                // next() : 다음 원소를 반환
        while(e.hasNext()) { // Iterator의 e 다음 원소가 있다면
            s = (String)e.next(); // Object를 리턴하기 때문에 형변환 필요
            System.out.println(s);
        }
        System.out.println();
        
        for(String str : list) // Iterator interface를 개선한 for-each loop
            System.out.println(str); // 하나씩 꺼내서 뭘 하고 싶다면 for-each loop 사용
        System.out.println();
        
        System.out.println(list); // println을 사용한 출력 방법
    }

}

- Set : 원소의 중복을 허용하지 않는다

1. HashSet
   : 해쉬 테이블에 원소를 저장하기 때문에 성능에서 가장 우수하다. 하지만 원소들의 순서가 일정하지 않는다.
2. TreeSet
   : 레드 블랙 트리에 원소를 저장한다. 따라서 값에 따라서 순서가 결정되지만 느리다.(알파벳 순서)
3. LinkedHashSet
   : 해쉬 테이블과 연결 리스트를 합한 것으로 원소들의 순서는 삽입되었던 순서와 같다.


// Set은 list와 유사하지만 순서는 상관없고 동일한 원소를 가질 수 없다

import java.util.HashSet; // hashCode()에 의한 순서
import java.util.TreeSet; // alphabet 순서
import java.util.LinkedHashSet; // 입력순서

public class SetTest {
    public static void main(String[] args) {
        LinkedHashSet<String> set = new LinkedHashSet<>(); // 입력 순서에 의한 순서
        
        set.add("Milk");
        set.add("Bread");
        set.add("Butter");
        set.add("Cheese");
        set.add("Ham");
        set.add("Ham"); // 모든 set은 중복을 허용하지 않는다
        set.remove("Cheese");
        System.out.println(set);
        System.out.println(set.size());
        
        String[] sample = { "Java", "is", "fun", "Is", "Java", "easy?" };
        
        for(int i = 0; i < sample.length; i++)
            if(!set.add(sample[i])) // 중복되는 데이터는 false 리턴
                System.out.println(sample[i] + " is already in set.");
        System.out.println(set);
        
        System.out.println();
        for(String str : set)
            System.out.println(str);
    }

}

import java.util.*;

public class Lotto {

    public static void main(String[] args) {
        Random rand = new Random();
        HashSet<Integer> set = new HashSet<>();
        int count = 0;
        int num;
        
        while(count < 6) {
            num = rand.nextInt(45) + 1;
            if(!set.add(num))
                continue;
            count++;
        }
        System.out.println(set);
    }

}

import java.util.*;

public class SetTest1 {

    public static void main(String[] args) {
        HashSet<String> s1 = new HashSet<>();
        HashSet<String> s2 = new HashSet<>();
        
        s1.add("A");
        s1.add("B");
        s1.add("C");
        
        s2.add("A");
        s2.add("D");
        // 원집합이 파괴되면 안되므로 union이라는 복사본 집합을 생성
        HashSet<String> union = new HashSet<>(s1); // s1과 같은 HashSet 객체 생성
        union.addAll(s2); // s1과 s2의 합집합
        System.out.println("합집합 : " + union);
        
        HashSet<String> intersection = new HashSet<>(s1); 
        intersection.retainAll(s2); // s1과 s2의 공통집합
        System.out.println("공통집합: " + intersection);
        
        System.out.println(s1.containsAll(s2)); // s2가 s1의 부분집합이면 true, 아니면 false
        s1.removeAll(s2); // s1과 s2의 차집합                                                                       
        System.out.println("차집합: " + s1);
    }

}

큐는 먼저 들어온 데이터가 먼저 나가는 구조

// LinkedList 클래스는 Queue 인터페이스를 구현한다
// 따라서 Queue는 LinkedList를 사용하여 작성할 수 있다

import java.util.LinkedList;

public class QueueTest {

    public static void main(String[] args) {
        LinkedList<Integer> queue = new LinkedList<>();
        
        for(int i = 0; i <= 10; i++)
            queue.add(i);
        System.out.println(queue);
        
        queue.offer(11); // add와 동일
        System.out.println(queue);
        
        System.out.println(queue.element()); // 첫 번째 원소 리턴, 삭제하지 않는다
        System.out.println(queue);
        
        System.out.println(queue.peek()); // 첫 번째 원소 리턴, 삭제하지 않는다
        System.out.println(queue);
        
        System.out.println(queue.remove()); // 첫 번째 원소 리턴, 삭제한다
        System.out.println(queue);
        
        System.out.println(queue.poll()); // 첫 번째 원소 리턴, 삭제한다
        System.out.println(queue);
        
        System.out.println(queue.get(2)); // 번호에 있는 원소 리턴, 삭제하지 않늗다
        System.out.println("size : " + queue.size());
    }
}

//           Exception 발생     null, true, false 리턴
// insert  :  add(e)            off(e)
// examine :  element()         peek()
// remove  :  remove()          poll()

- 우선순위 큐

import java.util.PriorityQueue;

// PriorityQueue는 크기 순서로 저장되지는 않지만
// 가장 작은 원소를 맨 앞으로 보내 작은 순서대로 remove
public class PriorityQueueTest {

    public static void main(String[] args) {
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        
        pq.add(80);
        pq.add(30);
        pq.add(50);
        pq.add(20);
        System.out.println(pq); // 가장 작은 원소를 처음으로 보낸다
        
        System.out.println(pq.remove());
        System.out.println(pq); // 왜 순서가 바뀌는건가?? 뒤에 있는 원소들은 순서 상관 없다
        
        while(!pq.isEmpty())
            System.out.println(pq.poll());
    }
}

import java.util.*;

class Prisoner implements Comparable<Prisoner> {
    String name;
    int year;
    public Prisoner(String n, int y) {
        name = n;
        year = y;
    }
    
    public int compareTo(Prisoner p) {
        if(year > p.year)
            return 1;
        else if(year < p.year)
            return -1;
        else
            return 0;
    }
}

public class PriorityQueueTest {

    public static void main(String[] args) {
        PriorityQueue<Prisoner> q = new PriorityQueue<>();
        // 우선순위가 결정되는 것은 사용자가 만든 compareTo에 따라 정할 수 있다
        q.add(new Prisoner("james", 5));
        q.add(new Prisoner("schofield", 99));
        q.add(new Prisoner("alex", 14));
        q.add(new Prisoner("silvia", 10));
        q.add(new Prisoner("thomson", 1));
        
        System.out.println("==== 출옥 순서");
        while(!q.isEmpty()) {
            Prisoner p = q.poll();
            System.out.println(p.name);
        }
    }
}

- map
 : 키에 값이 매핑된다

// Map 인터페이스를 구현한 클래스는 HashMap, TreeMap, LinkedHashMap이 있다
// Map은 Key와 value를 갖는다

import java.util.*;

public class MapTest {

    public static void main(String[] args) {
        HashMap<Integer, String> map = new HashMap<>(); // hashcode에 의한 정렬
        
        map.put(2, "two");
        map.put(3, "three");
        map.put(1, "one");
        map.put(4, "four");
        map.put(1, "하나"); // key값이 같으면 overwrite, 이전에 있던 키 값의 value가 사라짐
        System.out.println(map.size());
        System.out.println(map.isEmpty());
        System.out.println(map.containsKey(1));
        System.out.println(map);
        
        map.remove(2);
        System.out.println(map);
        map.put(5, "five");
        System.out.println(map);
        System.out.println(map.get(3)); // value return, 없으면 null return
        
        for(Integer key : map.keySet()) { // key값에 대한 set 작성
            System.out.println(key + ", " + map.get(key));
        }
        // Map.Entry : key와 value의 값을 따로 따로 가지고 오고 싶을 때 -> getKey(), getValue()
        for(Map.Entry<Integer, String> s : map.entrySet()) { // key, value의 set
            Integer key = s.getKey();
            String value = s.getValue();
            System.out.println("Key = " + key + ", Value = " + value);
        }
    }

}

Collections 클래스

1. max(), min() : 리스트에서 최대값과 최소값
2. reverse() : 리스트의 원소들의 순서를 반대로
3. fill() : 지정된 값으로 리스트를 채운다
4. copy() : 목적 리스트와 소스 리스트를 받아서 소스를 목적지로 복사한다
5. swap() : 리스트의 지정된 위치의 원소들을 서로 바꾼다
6. addAll() : 컬렉션 안의 지정된 모든 원소들을 추가한다
7. frequency() : 지정된 컬렉션에서 지정된 원소가 얼마나 많이 등장하는 지를 반환한다
8. disjoint() : 두 개의 컬렉션이 겹치지 않는지를 검사한다

import java.util.ArrayList;
import java.util.Random;

public class RandomList<T> {
    private T data;
    private ArrayList<T> alist = new ArrayList<>();
    private Random random = new Random();
    
    public void add(T item) {
        alist.add(item);
    }
    
    public T select() {
        int num = random.nextInt(alist.size());
        return alist.get(num);
    }
    
    public ArrayList<T> getList() {
        return alist;
    }
    
    public static void main(String[] args) {
        RandomList<Integer> list = new RandomList<>();
        for(int i = 0; i < 10; i++)
            list.add(i);
        System.out.println(list.getList());
        for(int i = 0; i < 10; i++)
            System.out.println(list.select());
    }
}

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class ArrayListTest {
    public static void main(String[] args) {
        ArrayList<Double> list = new ArrayList<>();
        Random rand = new Random();
        for(int i = 0; i < 10; i++)
//			list.add(rand.nextDouble() * 10);
            list.add((double)(rand.nextInt(11)));
        
        for(Double d : list)
            System.out.println(d);
        
        Collections.sort(list);
        list.remove(0); // 제일 최하위 인덱스
        list.remove(8); // 제일 최상위 인덱스 why? 8인가.. 앞에서 0번방을 없애주었기 때문에
        System.out.println(list);
        
        double sum = 0.0;
        for(int i = 0; i < list.size(); i++)
            sum += list.get(i);
        System.out.printf("%.2f\n", sum);
        
        System.out.println(Collections.max(list));
        System.out.println(Collections.min(list));
    }
}

import java.util.HashMap;

class MyPair<K, V> {
    private HashMap<K, V> hm;
    
    public MyPair() {
        hm = new HashMap<>();
    }
    
    public void put(K k, V v) {
        hm.put(k, v);
    }
    
    public V get(K i) {
        return hm.get(i);
    }
    
    public String toString() {
        return hm.toString();
    }
}

public class MyPairTest {
    public static void main(String[] args) {
        MyPair<Integer, String> pair = new MyPair<>();
        pair.put(1, "one");
        pair.put(2, "Two");
        System.out.println(pair.get(2));
        System.out.println(pair);
    }
}

- 스트림은 순서가 있는 데이터의 연속적인 흐름이다.
- 스트림들은 연결될 수 있다.
- 입출력 스트림:  1. 바이트 스트림 - 입/출력(8비트) (InputStream/OutputStream)
                2. 문자 스트림 - 입/출력 (Reader/Writer)
- 바이트 스트림

 // File 입출력을 바이트 단위로 출력하는 경우
/*
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
// import java.io.*; // 앞으로 이런식으로 쓰자

public class FileCopy1 {
    public static void main(String[] args) throws IOException { // main에 IOException을 해주지 않으면 각 줄마다 예외처리를 해야함
        FileInputStream in = null;
        FileOutputStream out = null;
        
        System.out.println(System.getProperty("file.encoding")); // 텍스트 encoding 방식
                                                                 // 내 PC가 어떤 코딩 방식을 쓰는지 출력
        try {                                                    // MS949(한글 확장판)
            in = new FileInputStream("input.txt"); // FileNotFoundException
            out = new FileOutputStream("output.txt"); // append mode 설정은?(true)
            int c; // 하위 8비트만 사용
            while((c = in.read()) != -1) {      // read()는 int return, eof면 -1 반환
                out.write(c);                   // read(), write()은 IOException
                System.out.print((char)c);      // int(4바이트)를 char로 반환(안그러면 나머지 3바이트가 쓰레기값이 들어가짐)
            }
        } catch(FileNotFoundException e) {
            System.out.println("File open error");
        } finally {
            if(in != null)
                in.close();
            if(out != null)  // IOException
                out.close();
        }
    }
}

// 입력 파일은 없으면 IOException이 발생
// 출력 파일은 없으면 자동 생성
// 한글을 입력하면 콘솔 창에서 깨진다 -> byte 배열을 이용하여 해결하자
*/

// byte 배열을 사용한 한글 입출력
import java.io.*; 

public class FileCopy1 {
    public static void main(String[] args) throws IOException { 
        FileInputStream in = null;
        FileOutputStream out = null;
        
        System.out.println(System.getProperty("file.encoding"));
                                                         
        try {                                            
            in = new FileInputStream("input.txt"); 
            out = new FileOutputStream("output.txt"); 
            int c, i = 0; 
                        byte[] buffer = new byte[100]; // byte라는 배열을 만들어서 모든 string을 집어넣자
            
            while((c = in.read()) != -1) {      
                out.write(c);           
                buffer[i++] = (byte)c;
            }
        } catch(FileNotFoundException e) {
            System.out.println("File open error");
        } finally {
            if(in != null)
                in.close();
            if(out != null)  // IOException
                out.close();
        }
    }
}

- 문자 스트림

// File 입출력을 문자 스트림으로 처리하는 경우

import java.io.*; // File I/O 문자 스트림

public class FileCopy2 {
    public static void main(String[] args) throws IOException { 
        FileReader in = null;
        FileWriter out = null;
                                                         
        try {                                            
            in = new FileReader("input.txt"); // FileNotFoundException
            out = new FileWriter("output.txt"); 
            int c; // 하위 16 bit만 사용
            
            while((c = in.read()) != -1) {  // read()는 int return, 하위 16 bit 사용
                out.write(c);               // read(), write() 는  IOException
                System.out.print((char)c);     // 형변환 필요
            }
        } catch(FileNotFoundException e) {
            System.out.println(e.getMessage());
        } finally {
            if(in != null)
                in.close();
            if(out != null)  // IOException
                out.close();
        }
    }
}

- 스트림은 연결될 수 있다
- 바이트 스트림과 문자 스트림을 연결하는 방법

// 조합 stream
import java.io.*;

public class InputStreamReaderTest {

    public static void main(String[] args) throws IOException {
        InputStreamReader in = null;
        OutputStreamWriter out = null;
                                                         
        try {            
            // byte stream은 문자 스트림으로 변환하는 객체 생성(생성자에 byte stream 객체)
            // 문자 스트림들을 byte stream으로 변환하는 객체 생성(생성자에 byte stream 객체)
            in = new InputStreamReader(new FileInputStream("input.txt")); 
            out = new OutputStreamWriter(new FileOutputStream("output.txt")); 
            int c; 
            
            while((c = in.read()) != -1) {  
                out.write(c);              
                System.out.print((char)c);    
            }
        } catch(FileNotFoundException e) {
            System.out.println(e.getMessage());
        } finally {
            if(in != null)
                in.close();
            if(out != null)  
                out.close();
        }

    }

}

- 줄단위의 입출력

// 문자 stream을 BufferedReader, BufferedWriter와 같이 사용
// Buffering을 이용해 입출력 효울을 높인다.
// 버퍼가 없는 스트림을 버퍼가 있는 스트림으로 변경
// -> new BufferedReader(new FileReader())
// -> new BufferedWriter(new FileWriter())

import java.io.*;

public class CopyLines {

    public static void main(String[] args) throws IOException {
        BufferedReader in = null;
        BufferedWriter out = null;
        
        try {            
            in = new BufferedReader(new FileReader("input.txt"));
            out = new BufferedWriter(new FileWriter("output.txt")); 
            String str;
            
            while((str = in.readLine()) != null) {  // line 단위 입력, 줄바꿈 기호는 포함하지 않는다
                out.write(str + "\n");            
                System.out.println(str);
            }
        } catch(FileNotFoundException e) {
            System.out.println(e.getMessage());
        } finally {
            if(in != null)
                in.close();
            if(out != null)  // IOException
                out.close();
        }

    }

}

- 토큰 분리

// 파일에서 문자열을 읽고 token으로 분리
// Scanner sc = new Scanner(System.in); 표준 입력
// Scanner 클래스는 공백 문자(공백, 탭, 줄바꿈 문자 등)을 이용하여 각각의 토큰을 분리한다

import java.io.*;
import java.util.Scanner;

public class ScanTest {
    public static void main(String[] args) throws IOException {
        Scanner sc = null;
        BufferedWriter out = null;
        String token;
        
        try {
            sc = new Scanner(new BufferedReader(new FileReader("input.txt")));
            out = new BufferedWriter(new FileWriter("output.txt"));
            while(sc.hasNext()) {
                token = sc.next();
                System.out.println(token);
                out.write(token +  "\n");
            }
        } catch(FileNotFoundException e) {
            System.out.println(e.getMessage());
        } finally {
            if(sc != null)
                sc.close();
            if(out != null)
                out.close();
        }
    }

}

// Scanner 클래스보다 Tokenizer 클래스가 더 효율적임

import java.io.*;
import java.util.Scanner;
import java.util.StringTokenizer;

public class ScanTest {
    public static void main(String[] args) throws IOException {
        StringTokenizer t = new StringTokenizer(null);
        BufferedReader r = null;
        BufferedWriter w = null;
        String str, token;
        
        try {
            r = new BufferedReader(new FileReader("input.txt"));
            w = new BufferedWriter(new FileWriter("output.txt"));
            
            while((str = r.readLine()) != null) {
                    while(t.hasMoreTokens()) {
                        token = t.nextToken();
                        System.out.println(token);
                        w.write(token +  "\n");
                }
            }
        } catch(FileNotFoundException e) {
            System.out.println(e.getMessage());
        } finally {
            if(r != null)
                r.close();
            if(w != null)
                w.close();
        }
    }
}

- Arguments
- 외부에서 입력 가능

public class CommandLineArgument {

    public static void main(String[] args) {
        for(int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
        
        int n1 = Integer.parseInt(args[0]); // String -> int
        int n2 = Integer.parseInt(args[1]);
        String str = String.valueOf(n1 + n2); // int -> String
        
        // 상단 메뉴 -> Run -> Run Configuration -> Arguments 탭 -> 10 20 입력(',' 사용 안됨 / 공백으로 사용)
        System.out.println(args[0] + " + " + args[1] + " = " + str);
    }
}

- DataStream

// DataInputStream, DataOutputStream은 byte stream만 지원
// byte 단위 io가 아니고 data type 단위의 io
// 출력 순서대로 입력해야함

import java.io.*;

public class DataStreamTest {

    public static void main(String[] args) {
        DataInputStream in = null; 
        DataOutputStream out = null;
        
        try {
            out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data.bin")));
            // data.bin 파일에 바이트 단위 파일 출력 스트림 개설 ->
            // 바이트 단위 출력 스트림을 버퍼링 ->
            // 바이트 단위 출력을 데이터 형 단위 출력으로 변환
            
            // type에 따라 write하는 메소드가 다르다
            out.writeDouble(3.14);
            out.writeInt(100);
            out.writeChar('c');
            out.writeBoolean(true);
            out.writeUTF("test data");
            System.out.println(out.size()); // 현재까지 출력된 데이터의 바이트 수
            out.flush(); // buffer에 남아 있는 데이터 강제 출력 // C에서 fflush()와 같음
            
            in = new DataInputStream(new BufferedInputStream(new FileInputStream("data.bin")));
            // 읽어오는 순서는 파일에 쓴 순서대로 적어줘야 한다
            // 일일이 써준다는 단점이 있지만 타입별로 적고 싶다면 이것이 가장 효율적이다
            System.out.println(in.readDouble());
            System.out.println(in.readInt());
            System.out.println(in.readChar());
            System.out.println(in.readBoolean());
            System.out.println(in.readUTF());
            if(out != null)
                out.close();
            if(in != null)
                in.close();
        } catch(IOException e) { // IOException을 써주어야 한다 -> main에서 throw를 이용해도 가능
            System.out.println(e.getMessage());
        }
    }

}

// 객체 단위 입출력을 하기 위한
// 클래스는 Serializable interface를  구현해야 한다
// file에 출력하는 경우를 직렬화(serialization)
// (객체의 상태를 바이트 스트림으로 변환하는 것)
// file에서 읽는 경우를 역직렬화(deserialization)
// 따라서 byte stream 객체를 생성해야 한다

import java.io.*;
import java.util.*;

class Student implements Serializable {
    // serialVersionUID를 쓰지 않으면 클래스 옆에 오류가 나와서 generate serial를 눌러주면 생성된다
    // default serial은 1의 값이 생성된다
    private static final long serialVersionUID = 6012177974279663492L;
    private int id;
    private String name;
    
    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
    
    public String toString() {
        return id + ", " + name;
    }
}

public class ObjectStream {
    public static void main(String[] args) throws IOException {
        ObjectInputStream in = null;
        ObjectOutputStream out = null;
        
        try {
            // serialization(직렬화)
            out = new ObjectOutputStream(new FileOutputStream("object.dat"));
            out.writeObject(new Student(1, "Hong")); // IOException
            out.writeObject(new Student(2, "Kim"));
            out.writeObject(new Student(3, "Choi"));
            out.flush();
            
            // deserialization(역직렬화)
            in = new ObjectInputStream(new FileInputStream("object.dat"));
            System.out.println((Student)in.readObject());
            System.out.println((Student)in.readObject());
            System.out.println((Student)in.readObject());
            if(in != null)
                in.close();
            if(out != null)
                out.close();
        } catch(ClassNotFoundException e) { // 구제척인 예외는 대처할 수 있는 방법을 써주지만
                                            // IOException은 불확실하기 때문에 운영체제에 넘긴다
            System.out.println("ClassNotFoundException");
        }
    }
}

// 실전용
// 여러 개의 객체를 읽고 싶을 때

import java.io.*;
import java.util.*;

class Student implements Serializable {
    private static final long serialVersionUID = 6012177974279663492L;
    private int id;
    private String name;
    
    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
    
    public String toString() {
        return id + ", " + name;
    }
}

public class ObjectStream2 {
    public static void main(String[] args) throws IOException {
        ObjectInputStream in = null;
        ObjectOutputStream out = null;
        
        try {
            out = new ObjectOutputStream(new FileOutputStream("object.dat"));
            
            ArrayList<Student> list = new ArrayList<>();
            
            list.add(new Student(1, "일지매"));
            list.add(new Student(2, "이지매"));
            list.add(new Student(3, "삼지매"));
            
            out.writeObject(list);
            out.flush();
            
            in = new ObjectInputStream(new FileInputStream("object.dat"));
            
            ArrayList<Student> list2 = (ArrayList<Student>)in.readObject();
            // ArrayList에 있는 모든 것을 화면에 출력하는 반복문
            for(Student s : list2)
                System.out.println(s);
            
            if(in != null)
                in.close();
            if(out != null)
                out.close();
        } catch(ClassNotFoundException e) { 
            System.out.println("ClassNotFoundException");
        }
    }
}

import java.io.*;
import java.util.*;

public class FileTest {
    public static void main(String[] args) throws IOException {
        File file = new File("object.dat");
        System.out.println("Name : " + file.getName());
        System.out.println("Parent : " + file.getParent());
        System.out.println("Absoute path : " + file.getAbsolutePath());
        System.out.println("Is directory : " + file.isDirectory());
        System.out.println("Ins file : " + file.isFile());
        System.out.println("Length : " + file.length());
        file.deleteOnExit();
    }
}

- 임의 접근 파일

// 지금까지는 순차 접근 파일(Sequential access file)
// 임의 접근 파일(Random access file) : file pointer를 사용하여
// 파일 임의 위치에 접근 가능

import java.io.*;

public class RandomAccessFileTest {
    public static void main(String[] args) throws IOException {
        RandomAccessFile inout;
        
        try {
            inout = new RandomAccessFile("inout.bin", "rw"); // 읽고 쓰기 모드
             
            inout.setLength(0); // file 길이 설정
            for(int i = 0; i < 10; i++)
                inout.writeInt(i); // 타입별로 쓸 수 있음(int는 4바이트이므로 4바이트씩 증가)
                                   // 파일 포인터의 마지막 위치는 40번지
            System.out.println("File length : " + inout.length()); // 파일 길이
            System.out.println(inout.getFilePointer()); // 현재 파일 포인터 위치
            
            inout.seek(0); // 파일 포인터 처음으로 이동
            // 파일 포인터가 4바이트의 메모리를 읽고 나면
            // 4바이트 뒤에 위치하게 된다
            // 따라서 처음 위치에서 4바이트 이동하게 된다
            System.out.println("number : " + inout.readInt()); 
            System.out.println(inout.getFilePointer()); // 현재 파일 포인터 위치

            inout.skipBytes(4); // 4 byte를 이동(number = 1 skip)
            System.out.println("number : " + inout.readInt());
            System.out.println(inout.getFilePointer()); // 현재 파일 포인터 위치
            
            inout.seek(5 * 4); // 6번째로 이동
            System.out.println(inout.getFilePointer()); // 현재 파일 포인터 위치
            System.out.println("number : " + inout.readInt());
            
            inout.writeInt(555); // 7번째 변경
            inout.seek(inout.length()); // 파일 끝으로 이동
            
            inout.writeInt(999); // 마지막에 추가
            System.out.println("New length : " + inout.length()); // 길이 변경 확인
            
            inout.seek(10 * 4);
            System.out.println("number : " + inout.readInt());
            
            inout.seek(0);
            for(int i = 0; i < inout.length(); i += 4)
                System.out.println(inout.readInt());
            inout.close();
        } catch(FileNotFoundException e) {
            System.out.println(e.getMessage());
        }
    }
}

- zip 파일은 스킵!

import java.io.*;
import java.util.*;

public class FileSort {
    public static void main(String[] args) {
        int value;
        ArrayList<Integer> list = new ArrayList<>();
        BufferedReader reader; // 입력
        PrintWriter writer; // 출력
        
        try { // 원래는 클래스를 만들어서 각각의 메소드를 설정해주어야 한다(reader, writer)
            reader = new BufferedReader(new FileReader("input.txt"));
            String line = reader.readLine();
            while(line != null) {
                value = Integer.parseInt(line);
                list.add(value);
                line = reader.readLine();
            }
            Collections.sort(list);
            
            writer = new PrintWriter(new FileWriter("output.txt"));
            int num;
            for(int i = 0; i < list.size(); i++) {
                num = list.get(i);
                writer.write(num + "\n");
                System.out.println(num);
            }
            reader.close();
            writer.close();
        } catch(IOException e) {
            System.out.println(e.getMessage());
        }
    }

}

Tags: Language

Comments:

comments powered by Disqus

© 2021 - MH.Ji. All rights reserved
Built using Jekyll