[LG CNS 6기] 본 과정 18일차 TIL / [백엔드] - IO Stream과 객체 직렬화

김승진·2026년 8월 21일

LG CNS AM 6기 TIL

목록 보기
27/59

1. 오늘의 한 줄 요약

  • CRUD(update, delete)를 마무리하고, IO Stream과 객체 직렬화까지 배웠다.
    그리고 불금!

2. 배운 내용

2.1 update/delete의 구현

어제 TIL에 상세보기/검색/입력까지 연결했다고 적었는데, 그때 Service의 update(), delete()는 사실 아래처럼 예외만 던지는 껍데기였다.

@Override
public int update(BlogRequestDTO request) {
    throw new UnsupportedOperationException("Unimplemented method 'update'");
}

오늘 이 두 메서드를 Dao까지 내려가서 실제로 구현했다.
update는 findAny로 찾은 blog의 필드를 직접 바꿔치기하는 방식이다.

public int update(BlogRequestDTO request) {
    return blogs.stream()
        .filter(blog -> blog.getBlogId() == request.getBlogId())
        .findAny()
        .map(blog -> {
            blog.setTitle(request.getTitle());
            blog.setContent(request.getContent());
            return 1;
        })
        .orElse(0);
}

map이 원래 값을 변환하는 용도인데 여기서는 blog 필드를 직접 바꾸면서 동시에 1을 리턴하는 데 쓰였다. blog가 참조타입이라 이 안에서 값을 바꾸면 원본 리스트 안의 객체도 그대로 바뀐다는 걸 알고 나니, 왜 이 방식이 되는지 이해가 됐다. 다만 Stream의 중간 연산은 원래 부수 효과 없이 순수하게 변환만 하는 게 원칙이라, 이렇게 원본을 직접 바꾸는 건 엄밀히는 권장되는 패턴은 아니라고 한다.

2.2 Stream API랑 IO Stream

어제 배운 Stream API는 컬렉션 데이터를 조회, 가공하는 파이프라인이고
IO Stream은 프로그램과 파일·콘솔 같은 외부 사이에 데이터가 오가는 통로를 뜻한다.

구분바이트(1byte)문자(2byte)
읽기InputStream / FileInputStreamReader / FileReader
쓰기OutputStream / FileOutputStreamWriter / FileWriter
한글 처리깨짐안 깨짐

~Stream으로 끝나면 바이트 계열, ~Reader/~Writer로 끝나면 문자 계열이다.

2.3 System.in.read()부터 시작해서 감싸는 이유

int input = System.in.read();
System.out.println(input); // 'A' 입력하면 65가 찍힘

System.in이 InputStream이라 반환값이 char가 아니라 int로 나온다.
이걸 InputStreamReader로 감싸면 문자로 바뀌고, 다시 BufferedReader로 감싸면 readLine()으로 한 줄씩 읽을 수 있다. Scanner가 사실 내부에서 이러한 체이닝을 하고 있었다는 걸 알고 나니 좀 신기했다.

2.4 try-with-resources로 정리하다

자원을 닫는 코드를 finally 안에서 또 try-catch로 감싸야 하는 게 번거로웠는데, try 괄호 안에 자원을 선언하면 블록이 끝날 때 자동으로 닫아준다.

try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
    System.out.println(br.readLine());
} catch (Exception e) {
    e.printStackTrace();
}

AutoCloseable을 구현한 클래스만 이렇게 쓸 수 있다는 것도 배웠다.

2.5 객체를 통째로 저장하는 직렬화

문자열이 아니라 List<DTO> 같은 객체를 저장하려면 직렬화가 필요하다.

public class BlogResponseDTO implements Serializable {
    // 필드는 그대로, implements만 추가
}

Serializable은 메서드가 하나도 없는 마킹 인터페이스라서 implements만 붙이면 된다. 컬렉션(ArrayList)은 이미 Serializable인데 그 안에 담긴 DTO까지 마킹돼 있어야 한다는 걸 놓치면 NotSerializableException이 난다고 배웠다.

2.6 DB 대신 파일에 저장하는 saveToFile / loadToFile

public boolean saveToFile() {
    String path = "./blogs.txt";
    try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(path)))) {
        oos.writeObject(dao.findByAll());
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

writeObject의 매개변수 타입이 Object(다형성)라서 List 통째로 넘길 수 있다.
반대로 읽어올 때는 readObject()의 반환도 Object라 캐스팅이 필요한데, 이게 어제 배운 BlogBeanFactory.getBean()이 Object를 반환하던 것과 같은 패턴이다.

public boolean loadToFile() {
    String path = "./blogs.txt";
    try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(path)))) {
        dao.setBlogs((List<BlogResponseDTO>) ois.readObject());
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

읽어온 걸 Service가 들고 있지 않고 dao.setBlogs()로 다시 넘기는 이유는, 실제 데이터를 관리하는 영역이 Dao이기 때문이다. 프로그램을 처음 실행하면 blogs.txt가 없어서 FileNotFoundException이 나는 게 정상이라는 것도 짚어주셨다.

2.7 반환 타입 통일 - ResponseEntity

list는 List, read는 DTO, insert/update/delete는 int, file은 boolean처럼 컨트롤러마다 반환 타입이 다 달라서 View 쪽이 지저분했는데, code/message/data를 담는 제네릭 클래스로 감쌌다.

public class ResponseEntity<T> {
    private int    code;
    private String message;
    private T      data;
}
public ResponseEntity<List<BlogResponseDTO>> list() {
    return new ResponseEntity<List<BlogResponseDTO>>(200, "ok", service.list());
}

3. 실습 / 적용

직접 해본 것:

  • Dao의 update, delete를 구현하고 Factory·FrontController까지 연결해서 CRUD를 완성했다.

결과:

  • CRUD가 정상 동작하는 것까지 확인했다.

4. 오늘의 회고

  • 느낀 점: 백엔드 1 과정인 자바 과정이 끝났다. 다음 주부터 SQL과 프레임워크를 배운다고 하니, 그 전까지 복습 열심히 해야겠다는 생각이 들었다.
  • 다음에 할 것: 백엔드 1 과정에 대한 전체적인 복습

#LGCNS #LGCNS6기 #개발자 #LGCNSINSPIRECAMP

profile
이것저것

2개의 댓글

comment-user-thumbnail
2026년 8월 21일

잘 읽고 갑니다. 파이팅 하세요!

1개의 답글