Java 중급4

j0yy00n0·2025년 3월 11일

2025.03.07

입출력, Enum, 람다

입출력(IO)

입출력

Input과 Output의 약자, 컴퓨터 내부 또는 외부 장치와 프로그램 간의 데이터를 연동을 위한 자바 라이브러리

스트림(Stream)

입출력 장치에서 데이터를 읽고 쓰기 위한 단방향 통로로 자바에서 제공하는 클래스

  • 각각의 장치마다 연결할 수 있는 스트림이 존재하며 바이트 단위 처리와 문자 단위 처리를 위한 스트림 등이 존재
  • 스트림은 기본적으로 1바이트 단위의 데이터만 지나가게 되고 주고 받는 데이터의 기본 단위가 1바이트 이므로 한 방향만 처리가 가능하여 입력 스트림과 출력 스트림을 따로 구성

파일 관련 입출력

파일 클래스(File Class)

파일 시스템의 파일을 다루기 위한 클래스

  • 파일의 크기나 속성, 이름 등의 정보를 확인할 수 있고 파일 생성 및 삭제 기능 등을 제공

    File 변수명 = new File("파일명");

  • createNewFile() : 새로운 파일 생성

  • mkdir() : 새로운 디렉토리 생성

  • mkdirs() : 경로 상에 없는 모든 디렉토리 생성

  • delete() : 파일 또는 디렉토리 삭제

  • 모두 리턴 타임 boolean

파일 입출력 기반 스트림 종류

  • 바이트 단위(영어, 숫자, 특수기호 사용 시)
  • 문자 단위(한글까지 사용 시)

    자바 프로그램과 연결되는 외부 데이터의 타입이 무엇인지는 클래스의 이름을 보고 유추가 가능
  • InputStream/OuputStream/Reader/Writer를 빼고 남은 단어가 바로 외부 데이터의 타입
  • FileInputStream은 InputStream을 제거하고 남은 단어가 File이므로 외부 데이터는 File임
  • read() : 파일에 기록된 값을 순차적으로 읽어오고 더 이상 읽어올 데이터가 없는 경우 -1 반환
    - read() 메소드의 인자로 생성한 byte 배열을 넣어주면 파일의 내용을 읽어서 byte 배열에 기록
  • .length()로 파일의 길이를 알 수 있다
  • writer() 메소드는 IOException을 핸들링

자원 반납을 해야 하는 이유

  • 장기간 실행중인 프로그램에서 스트림을 닫지 않는 경우 다양한 리소스에서 누수(leak)가 발생한다.
  • 뒤에서 배우는 버퍼를 이용하는 경우 마지막에 flush()로 버퍼에 있는 데이터를 강제로 전송해야 한다.
    만약 잔류 데이터가 남은 상황에서 추가로 스트림을 사용한다면 데드락(deadlock)상태가 된다.
    판단하기 어렵고 의도하지 않는 상황에서도 이런 현상이 발생할 수 있기 때문에 마지막에 flush()를무조건 실행해주는 것이 좋다.
    close()메소드는 자원을 반납하며 flush()를 해 주기 때문에 close()만 제대로 해 줘도 된다.
    따라서 close() 메소드는 외부 자원을 사용하는 경우 반드시 마지막에 호출해줘야 한다.

파일 입출력 관련 보조 스트림의 종류

스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위해 사용
보조 스트림만으로는 데이터를 주고 받는 대상에 대한 처리를 하는 것이 아니므로 입출력 처리가 불가능하고 기반 스트림에 추가로 적용해야 함
보조 스트림 종류

  • 입출력 성능 향상 : BufferedInputStream/BufferedOutputStream
  • 형변환 보조스트림 : InputStreamReader/OutputStreamWriter
  • 기본 자료형 데이터 입출력 : DataInputStream/DataOutputStream
  • 객체 자료형 데이터 입출력 : ObjectInputStream/ObjectOutputStream

버퍼를 이용해 입출력 성능을 향상시키는 보조 스트림

java.io 패키지의 입출력 스트림은 기본 스트림과 필터 스트림으로 분류

  • 기본 스트림 : 외부 데이터에 직접 연결되는 스트림
  • 필터스트림 : 외부 데이터에 직접 연결하는 것이 아니라 기본 스트림에 추가로 사용할 수 있는 스트림

주로 성능을 향상시키는 목적으로 사용되며 생성자를 보면 구분이 가능

  • 생성자쪽에 매개변수로 다른 스트림을 이용하는 클래스는 필터스트림
  • 버퍼를 사용하는건 print보다 훨씬 많은 파일이나 문장을 내보내고 읽기 좋기 때문에 사용

버퍼를 이용해서 성능 향상을 시키는 보조스트림

  • BufferedWriter
  • BufferedReader
  • 버퍼에 미리 읽어온 후 한 줄 단위로 읽어들이는 기능을 제공하며 기본 스트림보다 성능을 개선
  • readLine() : 버퍼의 한 줄을 읽어와서 문자열로 반환

형변환 보조스트림

기본 스트림이 byte 기반 스트림이고, 보조 스트림이 char 기반 스트림인 경우에 사용

  • 표준 스트림 : 자바에서는 콘솔이나 키보드 같은 표준 입출력 장치로부터 데이터를 입출력 하기 위한 스트림을 표준 스트림 형태로 제공하고 있다.
    - System 클래스의 필드 in, out, err가 대상 데이터에 스트림을 의미
    • System.in (InputStream) : 콘솔로부터 데이터를 입력 받는다.
    • System.out (PrintStream) : 콘솔로 데이터를 출력한다.
    • System.err (PrintStream) : 콘솔로 오류 메세지 출력한다.
    • 자주 사용되는 자원에 대해 미리 스트림을 생성해 두었기 때문에 개발자가 별도로 스트림을 생성하지 않아도 된다.

enum

열거타입(enum)

관련이 있는 상수의 집합의 클래스

  • 각각의 열거 상수는 열거 객체로 생성
  • 기존의 상수를 정의하는 방법을 효과적으로 대체

접근제어자 enum 열거체이름{
상수명1, 상수명2,...상수명N;
}

열거체이름.상수이름

enum의 등장배경

전에는 정수 열거 패턴을 이용해 상수를 선언

  • 정수 열거 패턴은 타입 안전을 보장할 방법이 없고 에러 디버깅이 어렵다.
  • 정수형 상수는 문자열로 출력하기 어렵다.
  • 정수 열거 그룹에 속한 모든 상수를 순회(반복문 사용)하는 방법도 쉽지 않다.
  • 정수 열거 패턴으로 상수가 선언된 경우 상우에 변경이 발생하면 컴파일을 새로 해야한다.
    -> enum은 열거 패턴의 단점을 모두 보완하고 추가적인 장점도 존재

열거타입 장점

  • 싱글톤 방식으로 구현되기 때문에 인스턴스가 한 개 임을 보장
  • 동일한 이름의 상수가 필요한 경우 네임스페이스를 다르게 한다.
  • toString()을 이용하여 문자열로 변경하기 쉽다.
  • values()를 이용하여 상수값 배열을 반환하고 이를 이용해 연속처리할 수 있다.
  • 타입 안정성을 보장한다.

enum에서 자주 쓰이는 메소드

  • values() : 열거 타입의 모든 값을 배열로 리턴
  • valusOf() : 해당 이름을 가진 열거 타입 상수 리턴
  • ordinal() : 열거 타입 상수의 순서 리턴
  • name() : 열거 타입의 문자열 리턴(name 메소드 외에 toString도 가능)
  • .getNameToLowerCase() : 소문자로 출력
  • .getDescription() : 열거 요소의 특정한 값 출력

람다

람다식

메소드를 하나의 식(expression)으로 표현한 것

  • 메소드를 람다식으로 표현하면 메소드 이름과 리턴값이 없어서 익명 함수라고도 함

람다식 사용하기

  • 인터페이스 만들기
    - @FunctionalInterface 어노테이션 : 인터페이스 내부에 하나의 추상메소드가 선언된 인터페이스만 람다식의 타깃이 될 수 있는데 해당 조건을 만족하는지 컴파일 시점에서 체크해주는 기능
  • 인터페이스에 정의된 추상 메소드 활용하기 위해 3가지 방법 사용
    - 인터페이스를 상속받은 클래스를 정의하여 기능을 완성 후 사용하는 방법
    • 익명클래스를 활용하여 메소드 재정의 후 사용하는 방법
      • 익명클래스 : 일회성으로 이름이 없는 클래스, 일반적으로 인터페이스/추상 클래스를 즉석에서 구현할 때 사용(@Override 사용)
    • 람다식을 활용하는 방법

람다 표현식

  • 매개 변수 없는 경우

    ()->{식}

  • 매개 변수 있는 경우

    (타입 매개변수,...)->{식}

  • 하나의 매개변수만 존재하는 경우 ()는 생략 가능, 실행문이 하나인 경우에 {}는 생략 가능

함수적 인터페이스

인터페이스 내부에 하나의 추상메소드가 선언된 인터페이스만 람다식의 타깃이 될 수 있다

  • 해당 조건을 만족하는지를 컴파일 시점에 체크를 해주는 기능이 @FunctionalInterface 어노테이션
  • java.util.function 표준 API 패키지로 제공
  • Consumer, Supplier, Function, Operator, Predicate로 구분

Consumer

리턴 값이 없는 accept() 메소드를 가지고 있다

  • accept() 메소드는 단지 매개 변수로 넘어온 값을 소비하는 역할만 함(리턴값 없다)
  • Consumer#accept(T t) : void : 객체 T를 받아 소비한다.

Supplier

매개변수가 없고 리턴 값이 있는 getXXX() 메소드 보유

  • 실행되면 호출한 곳으로 값을 리턴
  • Supplier#get() : T : 객체 T를 리턴한다.

Function

매개변수와 리턴값이 있는 applyXXX() 메소드 보유

  • 매개변수를 리턴값으로 매핑
  • Function<T, R>#apply(T t) : R : 객체 T를 R로 매핑한다.
  • .parseInt() : 기본형 int로 변환
  • .getClass() : class 객체 반환
  • .getName() : 클래스의 전체 이름(패키지 포함) 반환

Operator

Function 과 똑같이 작동, 매개변수와 리턴값이 있는 applyXXX() 메소드 보유

  • Function 과 다른 점은 매개변수를 리턴타입으로 매핑하는 역할이 아닌 매개변수를 이용해 연산을 한 후 동일한 타입으로 리턴해주는 역할
  • BinaryOperator#apply(T t1, T t2) : T : T와 T를 연산하여 T를 리턴한다.

Predicate

매개 변수와 boolean 리턴 값이 있는 testXXX() 메소드 보유

  • 매개변수 값을 이용해 true 또는 false 를 리턴하는 역할
  • Predicate#test(T t) : boolean : T를 조사하여 boolean을 리턴한다.
profile
잔디 속 새싹 하나

0개의 댓글