JAVA 80%

Decorator Stream

lshjju 2025. 11. 6. 16:06

자바 I/O의 **데코레이터 스트림(Decorator Stream)**은 기본 스트림에 특별한 기능을 '장식'처럼 덧입혀주는 아주 똑똑한 도구들입니다.



📘 데코레이터 스트림: "기본 수도관의 변신"

데코레이터 스트림은 스스로 데이터를 읽거나 쓸 수는 없지만, 다른 스트림을 감싸서 새로운 능력을 부여합니다.

1. Character Conversion (문자 변환: InputStreamReader / OutputStreamWriter)

  • 기능: 바이트(0, 1)만 흐르는 수도관에 '통역사'를 앉히는 것과 같습니다.
  • 설명: InputStream 같은 바이트 기반 스트림을 Reader 같은 문자 기반 스트림으로 변환해 줍니다.
  • 예시: 네트워크에서 들어오는 바이트 데이터를 우리가 읽을 수 있는 한글 텍스트로 바꿀 때 필수적입니다.

2. Performance Enhancement (성능 향상: BufferedInputStream / BufferedReader)

  • 기능: 수도관 중간에 '임시 저장 탱크(버퍼)'를 설치하는 것입니다.
  • 설명: 데이터를 하나씩 옮기지 않고 바구니에 가득 모았다가 한꺼번에 옮겨서 속도를 획기적으로 높여줍니다.
  • 예시: 수만 줄의 텍스트 파일을 읽을 때 버퍼를 쓰지 않으면 컴퓨터가 매우 힘들어하지만, 이 장식을 쓰면 순식간에 끝납니다.

3. Primitive Type I/O (기본 타입 입출력: DataInputStream / DataOutputStream)

  • 기능: 단순한 바이트를 자바의 '자료형' 단위로 해석해 주는 장치입니다.
  • 설명: int, double, boolean 같은 자바의 기본 자료형 데이터를 깨지지 않게 그대로 읽고 쓸 수 있게 해줍니다.
  • 예시: 숫자 100을 저장할 때 문자 '1', '0', '0'이 아니라 정수 int 값 그대로 파일에 기록하고 싶을 때 사용합니다.

4. Printing a Newline (줄바꿈 출력: PrintWriter / PrintStream)

  • 기능: 데이터를 예쁘게 출력해 주는 '고급 프린터' 기능을 추가합니다.
  • 설명: 우리가 흔히 쓰는 System.out.println()이 바로 이 계열입니다.
  • 예시: 특히 println() 메서드는 자동으로 **줄바꿈(Newline)**을 처리해 주어, 일일이 \n을 넣지 않아도 데이터를 보기 좋게 정렬해 줍니다.

📦 데코레이터 사용 예제 (한 번에 감싸기)

여러 개의 장식을 겹겹이 포장하는 실제 코드를 확인해 보세요.

Java
 
import java.io.*;

public class DecoratorExample {
    public static void main(String[] args) {
        // 1. 파일 쓰기 예시 (기본 + 성능향상 + 줄바꿈기능)
        try (PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("magic.txt")))) {
            pw.println("첫 번째 줄입니다."); // Printing a newline (자동 줄바꿈)
            pw.println("데코레이터 패턴은 정말 편리해요!");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 2. 기본 타입 쓰기 예시 (기본 + 자료형 입출력)
        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"))) {
            dos.writeInt(2026);        // Primitive type (int)
            dos.writeDouble(3.14159);   // Primitive type (double)
            dos.writeBoolean(true);     // Primitive type (boolean)
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

👨‍🏫 쉽게 이해하는 핵심 포인트

자바 I/O 클래스 이름만 봐도 용도를 알 수 있습니다.

  • 이름에 **Buffered**가 들어가면? → Performance Enhancement (빠름!)
  • 이름에 **Data**가 들어가면? → Primitive Type I/O (자바 자료형 그대로!)
  • 이름에 **InputStreamReader**처럼 두 단어가 섞여 있으면? → Character Conversion (변환!)

오늘의 요약

  • 데코레이터는 기본 스트림을 '감싸서' 기능을 확장한다.
  • 성능을 생각한다면 Buffered를, 자료형이 중요하다면 Data를 감싼다.
  • **PrintWriter**는 줄바꿈(println) 기능을 제공하여 출력을 아주 편하게 해준다.

이제 데코레이터 스트림을 활용해 더 강력하고 효율적인 프로그램을 만드실 수 있게 되었습니다!

이번에는 앞서 언급한 4가지 핵심 키워드를 각각의 독립된 예제 코드로 만들어, 어떤 상황에서 어떤 클래스를 써야 하는지 확실히 보여드릴게요.


📘 데코레이터 스트림 실무 예제 정복

1. Character Conversion (문자 변환)

상황: 바이트 단위로 읽는 System.in(키보드 입력)을 우리가 읽기 쉬운 '문자'로 바꾸고 싶을 때 사용합니다.

Java
 
import java.io.*;

public class ConversionExample {
    public static void main(String[] args) throws IOException {
        // InputStream(바이트)을 Reader(문자)로 변환해주는 다리 역할을 합니다.
        InputStreamReader isr = new InputStreamReader(System.in);
        
        System.out.print("아무 글자나 입력하고 엔터를 치세요: ");
        int data = isr.read(); // 바이트가 아닌 '문자' 단위로 읽습니다.
        
        System.out.println("읽은 문자: " + (char)data);
    }
}

2. Performance Enhancement (성능 향상)

상황: 아주 큰 텍스트 파일을 읽을 때, 한 글자씩 읽는 것(FileReader)과 양동이에 담아 읽는 것(BufferedReader)의 차이를 보여줍니다.

Java
 
import java.io.*;

public class PerformanceExample {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("large_text.txt"))) {
            String line;
            // 한 줄씩 통째로 읽기 때문에 속도가 어마어마하게 빠릅니다.
            while ((line = br.readLine()) != null) {
                // 데이터 처리 (예: 출력)
            }
            System.out.println("성능 향상 스트림으로 읽기 완료!");
        } catch (IOException e) {
            System.out.println("파일이 없으면 실행되지 않아요!");
        }
    }
}

3. Primitive Type I/O (기본 자료형 입출력)

상황: 메모장에 적힌 "100"이라는 글자가 아니라, 컴퓨터가 인식하는 숫자 100(int) 그대로를 파일에 저장하고 싶을 때 씁니다.

Java
 
import java.io.*;

public class PrimitiveExample {
    public static void main(String[] args) {
        // 1. 데이터 쓰기 (int, double, boolean 저장)
        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.dat"))) {
            dos.writeInt(2026);
            dos.writeDouble(99.9);
            dos.writeBoolean(true);
        } catch (IOException e) { e.printStackTrace(); }

        // 2. 데이터 읽기 (저장한 순서대로 읽어야 합니다!)
        try (DataInputStream dis = new DataInputStream(new FileInputStream("data.dat"))) {
            System.out.println("정수: " + dis.readInt());
            System.out.println("실수: " + dis.readDouble());
            System.out.println("불린: " + dis.readBoolean());
        } catch (IOException e) { e.printStackTrace(); }
    }
}

4. Printing a Newline (줄바꿈 출력)

상황: 가장 편하게 데이터를 출력하고 싶을 때 사용합니다. \n을 직접 치지 않아도 자동으로 줄을 바꿔줍니다.

Java
 
import java.io.*;

public class PrintExample {
    public static void main(String[] args) {
        // PrintWriter는 모든 타입을 문자열로 예쁘게 출력해줍니다.
        try (PrintWriter pw = new PrintWriter(new FileWriter("print.txt"))) {
            pw.println("첫 줄입니다.");    // Printing a newline (자동 줄바꿈)
            pw.println(100);              // 숫자도 자동으로 문자열로 변환
            pw.printf("이름: %s, 나이: %d", "제미나이", 1); // 포맷 출력도 가능
        } catch (IOException e) { e.printStackTrace(); }
    }
}

👨‍🏫 한눈에 정리하는 데코레이터 조합 공식

실무에서는 보통 이렇게 3단 합체를 즐겨 사용합니다.

  1. new PrintWriter(new BufferedWriter(new FileWriter("file.txt")))
    • FileWriter: 파일을 만든다. (기본)
    • BufferedWriter: 속도를 올린다. (성능)
    • PrintWriter: println() 기능을 쓴다. (편의성)

오늘의 요약

  • InputStreamReader: 바이트를 문자로 변환할 때 쓴다.
  • BufferedReader: 대용량 데이터를 빠르게 처리할 때 필수다.
  • DataStream: 자바의 자료형(int, boolean 등)을 그대로 보존한다.
  • PrintWriter: 줄바꿈(println) 기능을 활용해 보고서를 쓰듯 데이터를 출력한다.

예제 코드가 추가되니 데코레이터의 역할이 더 명확해지셨나요?


'JAVA 80%' 카테고리의 다른 글

Thread  (0) 2026.01.31
I/0 API  (0) 2025.11.06
I/O Stream  (0) 2025.11.06
LIFO/FIFO collection - Stack - Queue  (0) 2025.11.06
Collection framework  (0) 2025.11.05