KDT 공부 일지 - 2026.01.21

김시코·2026년 1월 21일

KDT 공부 일지

목록 보기
13/27

람다식 + StreamAPI

ArrayList와 람다식을 이용한 코드

[p1]
package p1;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

public class App {
    public static void main(String[] args) {
        // 람다식, stream API

        List<StudentDto> studentDtoList = new ArrayList<>();
        studentDtoList.add(new StudentDto("민수", 30, "비밀 정보"));
        studentDtoList.add(new StudentDto("철수", 28, "비밀 정보"));
        studentDtoList.add(new StudentDto("영수", 32, "비밀 정보"));

        // 어쩌다 보니 위에 있는 목록이 생겼다.

        // List<StudentDto> 를 List<ResponseStudentDto> 로 변환
    //  List<ResponseStudentDto> responseStudentDtoList = new ArrayList<>();

    //     for(StudentDto studentDto : studentDtoList) {
    //         ResponseStudentDto responseStudentDto = new ResponseStudentDto();
    //         responseStudentDto.setName(studentDto.getName());
    //         responseStudentDto.setAge(studentDto.getAge());

    //         responseStudentDtoList.add(responseStudentDto);
    // }        옛날에 많이 쓰던 코드

        // 위의 코드를 stream API를 이용해서 작성해보자.
        List<ResponseStudentDto> responseStudentDtoList = studentDtoList.stream()
        .map(ResponseStudentDto::from)
        .toList();

        // 1부터 100까지 구해보자.
        IntStream.rangeClosed(1, 100).sum();

        // 1부터 100까지 구하는데 3의 배수랑 5의 배수는 빼고 구하자
        int sum = IntStream.rangeClosed(1, 100)
        .filter(e -> e%3!=0)
        .filter(e -> e%5!=0)
        .sum();
    }

    
}

class ResponseStudentDto {
    private String name;
    private int age;

    public ResponseStudentDto() {}

    public ResponseStudentDto(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public ResponseStudentDto(StudentDto studentDto) {
        // this.name = studentDto.getName();    // 아래코드랑 같은거긴 함
        this.setName(studentDto.getName());     // 이건 setter쓰는거
        this.setAge(studentDto.getAge());
    }

    public static ResponseStudentDto from(StudentDto studentDto) {
        ResponseStudentDto responseStudentDto = new ResponseStudentDto();
        responseStudentDto.setName(studentDto.getName());
        responseStudentDto.setAge(studentDto.getAge());
        return responseStudentDto;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

class StudentDto {
    private String name;
    private int age;
    private String secret;

    public StudentDto(String name, int age, String secret) {
        this.name = name;
        this.age = age;
        this.secret = secret;
    }

    // getter, setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSecret() {
        return secret;
    }

    public void setSectet(String secret) {
        this.secret = secret;
    }
}

[StudentManagerV3] - 배열만 ArrayList로 바꾼 것.

[StudentManagerRepository]
package com.joongang.stm.repository;

import java.util.ArrayList;
import java.util.List;

import com.joongang.stm.dto.StudentDto;
// 이 부분이 제일 중요함. 인터페이스나 그런것보단 클래스 문법, ArrayList, 기초 등이 중요
public class StudentManagerRepository {
    private List<StudentDto> studentList = new ArrayList<>();
      // 앞으로 반복할 때는 배열이 아니라 ArrayList로. 다형성

    public void save(StudentDto studentDto) {
        studentList.add(studentDto);
    }

    public List<StudentDto> findAll() {
        return studentList;
    }

    public int count() {
        return studentList.size();  // size가 count를 대체 함
    }

}
[StudentManagerService]
package com.joongang.stm.service;

import java.util.List;

import com.joongang.stm.dto.StudentDto;
import com.joongang.stm.repository.StudentManagerRepository;
import com.joongang.stm.util.IoUtil;

public class StudentManagerService {

    private StudentManagerRepository repository = new StudentManagerRepository();

    public void register() {
        
        IoUtil.print("======= 학생 정보 등록 =======");
        String name = IoUtil.input("이름 > ");
        int age = Integer.parseInt(IoUtil.input("나이 > "));
        int score = Integer.parseInt(IoUtil.input("점수 > "));

        StudentDto studentDto = new StudentDto(name, age, score);
        repository.save(studentDto);

        IoUtil.print("============================");
    }

    public void list() {
        IoUtil.print("======= 학생 정보 목록 =======");

        // 배열을 Lits로 바꾼것. 배열은 크기가 고정되어야 할 때만 씀.
        List<StudentDto> studentList = repository.findAll();
        int count = repository.count();

        for(StudentDto studentDto : studentList) {
            String text = "";
            text += "이름: " + studentDto.getName();
            text += ", 나이: " + studentDto.getAge();
            text += ", 점수: " + studentDto.getScore();
            IoUtil.print(text);
        }

        IoUtil.print("총 " + count + "명이 존재합니다.");

        IoUtil.print("============================");
    }

}

이 두개만 바뀌었다.

[예외 처리]
결과물의 품질을 높이는 것. 지금까지 한것들은 코드의 품질(가독성)을 높이는 것이지, 결과물의 품질을 높이진 않는다. 그래서 결과물의 품질을 높이기 위해서는 모든 예외상황을 예측하고 처리 해야 한다. 사용자가 어떤 일들을 할지 모르기 때문에. 예외(Exception)란? runtime 오류를 말하는 것. 예외처리이 종류로는 checked와, unchecked가 있다. checked는 Java에만 있으며, 다른 언어에는 대부분 없다.
[try-catch문]

  • try: 예외처리가 필요한 코드들이 들어간다. try를 쓰지 않았을때랑 똑같이 쓰면 됨.
  • catch: try문 안에 있는 코드들이 실행되다가 예외가 발생했을때 실행이 될 코드를 작성하면 된다. 여러개 작성할 수 있다.
  • finally: 어떠한 경우에도 실행이 되는 코드인데, 어떠한 경우라는 뜻은 try문 안에 return이 있더라도 무조건 실행이 된다는 뜻이다. 사실 try-catch문 밖에 써도 똑같은거라고 할 수 있다. 참고로 finally는 대부분의 경우 사용법이 정해져 있다. 자원 해제 용. 근데 try with resources라는 새로운 문법이 나옴.
  • throw: Exception을 직접 발생시키는 것이다. try-catch없이 이 코드를 만나면 프로그램을 그냥 터트려버리며, 그렇기 때문에 try-catch를 사용해서 프로그램이 터지는걸 막아야 한다.
[p2]
package p2;

public class App {
    
    public static void main(String[] args) {
        // 예외처리

        System.out.println("코드1");
        System.out.println("코드2");

        // 지금은 테스트를 위해 적어뒀지만 우리는 원래 이 input의 값을 모른다.
        // 만약 여기 input 값에 사용자가 0을 넣는다면 컴파일 에러는 나지 않지만
        // runtime 에러를 발생시켜서 위의 2줄만 실행되고 프로그램이 아예 뻗어버린다.
        // 이러한 예외를 잘 처리한 프로그램이 안정성이 높은 프로그램이다.
        // 1순위의 목적으로, 우리는 프로그램이 절대 뻗는 일이 생기지 않게 해야한다.
        // exception이 발생하더라도 뻗으면 안되기 때문에 try catch문을 쓴다
        
        try{
            int input = 1;
            System.out.println(10/input);
            // try문에 있는 코드들이 실행되다가 예외 발생시 catch문으로 바로 넘어 간다.
            
            System.out.println("코드3");

            String name = "민수";
            // 여가에 null값이 들어오는 경우도 있을 수 있기 때문에 try-catch를 해준다.
            // 만일 try문을 쓰지 않으면 컴파일 에러는 아니지만 조심하라는 경고가 뜨며,
            // 실행하면 역시나 문제가 생긴다. (runtime error - NullPointException)
            // String이 null이라는 뜻 참조주소가 없다는 뜻이고, 참조주소가 없기 때문에
            // 접근연산자(.)로 접근 자체를 할 수가 없다. - 에러코드로도 알려준다.
            // Exception in thread "main" java.lang.NullPointerException:
            // Cannot invoke "String.equals(Object)" because "name" is null
            // 에러코드를 볼 줄 알아야 함.

            System.out.println(name.equals("야호"));    

            System.out.println("야호!!");
            System.out.println("야호!!");
            System.out.println("야호!!");
        } catch (NullPointerException e) {
          // e는 변수명이라서 아무거나 해도 되지만 보통 e를 쓴다. 그리고 여기에 정확한
          // Exception 이름을 넣어주면 그때만 catch해서 안의 실행문 실행.
            // 예측 가능 - NullPointerException
            // ... NullPointerException이 발생했을때 대응해야 할 코드

        } catch (ArithmeticException e) {
            // 예측 가능 - ArithmeticException
            // ... ArithmeticException이 발생했을때 대응해야 할 코드

        } catch (Exception e) {
            // 예측 불가능... (혹은 대충 퉁쳐서 처리)
            // 로그를 찍어서 어떤 때에 어떤 exception이 발생했는지..

            e.printStackTrace();
            // 예외 처리 정보 콘솔 출력: 어떤 exception이 발생했는지 알려줌. (많이 씀)
        } finally {
            // 여기는 어떠한 경우에도 실행 됨.
        }

        System.out.println("코드4");
        System.out.println("코드5");
    }
}
[p3]
package p3;

public class App {
    public static void main(String[] args) {
        // try-catch 구문의 finally
        test(10);
    }

    public static void test(int value) {
        try {
            if(value < 0) {
                return;
            }

            int result = 10/value;
            System.out.println(result);
        } catch (Exception e) {
            System.out.println("예외 발생");
        } finally {
            // 여기는 어떠한 경우에도 실행 됨
            System.out.println("여기는 무조건 실행됨!");
        }
    }
}

[checked, unchecked 예외]

  • Exception: 모든 클래스의 최상위에 있는것. Exception을 상속 받은것들은 예외가 발생하면 컴파일 에러가 나서 실행이 안된다.
  • RuntimeException: Exception과 다르게 예외가 발생해도 컴파일 에러가 나지는 않는데 실행(runtime)시에 프로그램이 터진다.
  • throws: 굉장히 무책임하지만 중요하다. 발생된 예외의 책임을 다른곳에 던지는 것이다. 하지만, 책임을 전가할때만 쓰이는 것이 아니라 예외를 처리할때 예외가 발생한 곳에서 처리를 하는게 아니라 메서드를 호출한 곳에서 예외를 처리하게 시킬때도 쓸 수 있다.
    비유해 보면 throw는 폭탄을 던지는거고, try-catch는 폭탄 처리반, Exception은 폭탄 터트릴거라고 소리치는거. 메서드 옆에 throws 붙이면 폭탄 돌리기
    checked: Exception 클래스 하위에 존재. Exception클래스의 하위에 있는것들은 다 checked이다. 문법적으로 try문을 강제하는것.
    unchecked: RuntimeException 클래스 하위. RuntimeException클래스의 하위에 있는것들은 다 unchecked이다. 문법적으로 try문을 강제하지 않는것. 물론 그렇다고 터지지 않는건 아님
    가끔 빨간줄 에러가 떠서 마우스오버 해보면 Unhandled exception type Exception이 뜰 때가 있다. 무슨 뜻이나면, 지금 쓰고있는 이거는 checked야, 그러니까 핸들링(try-catch)해야해 라는 뜻
[p4]
package p4;

public class App {
    public static void main(String[] args) {
        // throw

        "ffff".charAt(0);   // 이것도 마우스오버 해보면 마지막에 throw 있음

        SumCalculator sumCalculator = new SumCalculator();

        try {
            int result = sumCalculator.sum(1, 10);
            System.out.println(result);
        } catch (StartNotBetterThenEndException exception) {
        // 귀찮으면 catch (Exception e)로 함.
        // Exception은 최상위 클래스라 모든 예외를 받을 수 있음
            // ...
            exception.printStackTrace();
            // 로그 찍는것. 무슨 예외가 발생하는지 모르기 때문에 일단 찍는것이 좋다.
        }

        System.out.println("프로그램 종료.");
    }

}

class SumCalculator {
    public int sum(int start, int end) throws StartNotBetterThenEndException {

        if(start > end) {
          // 이러면 아예 말이 안되니까 return을 해주면 안됨. - 서비스 거부
            throw new StartNotBiggEndException("start가 end보다 클 수 없다.");
            // 여기에는 exception을 상속 받은것(직접만들어도ok)만 생성 시킬 수 있음.
            // 그런건 보통 이름의 마지막에 exception이 들어감.
        }

        int sum = 0;
        for(int i = start; i <= end; i++) {
            sum += i;
        }

        return sum;
    }
}

// exception의 이름을 지정 해주고 싶으면 Exception을 직접 만들 수 있다.
// 그냥 Exception을 분리하는거라 내부에 들어가는게 거의 없음
class StartNotBiggerThenEndException extends RuntimeException {
    public StartNotBetterThenEndException(String message) {
        super(message);
    }
}
[p5]
package p5;

import java.io.File;
import java.io.FileOutputStream;

public class App {
    public static void main(String[] args) {
        // try문을 배운 이유 = 적어도 문법 오류는 막아야 되기에...
        
        try {
            Thread.sleep(1000);
        } catch (Exception e) {  // 모든 예외를 받을 수 있기 때문에 간단히 쓸때 좋다.
            e.printStackTrace(); // 어떤 예외가 발생하는지 알기 위해서 로그 기록 필요.
        }

        File file1 = new File("C:\\temp\\aaa.jpg");

        try {
            FileOutputStream fos = new FileOutputStream(file1);
            fos.write(10);
            // 할거 다 하고...

            fos.close();    // 자원 반납 (해제)
        } catch (Exception e) {
          // API중에 checked API가 꽤나 많고, 그 API마다 Exception의 종류가 다 달라서
          // catch를 사용하는 API 수 만큼 짜야하는데, 그걸 하나하나 다 쓸 수 없으니까
          // 정확한 Exception 이름을 넣는게 아니라 퉁치는거.
          // 애초에 이런 API들은 예외가 거의 나지 않는다.
            e.printStackTrace();
        } finally {

        }

        // 예전에 했던 방법. 얼마나 힘들었는지 보여주신다고... 그래서 새로운 문법이 나옴
        File file2 = new File("C:\\temp\\aaa.jpg");
        FileOutputStream fos = null;

        try {
            fos = new FileOutputStream(file2);
            fos.write(10);
            // 할거 다 하고...

            fos.close();    // 자원 반납
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(fos != null) {
                try {
                    fos.close();    // 자원 반납 (해제)
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
[p6]
package p6;

import java.io.File;
import java.io.FileOutputStream;

public class App {
    public static void main(String[] args) {
        // try with resources

        File file = new File("C:\\aaa\\aaa.jpg");

        // try 다음 괄호 안에 있는게 resources임
        try(FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(10);
            //... 할거 하고 알아서 close(); 해줌
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
[p7]
package p7;

import java.util.Scanner;

public class App {
    public static void main(String[] args) {
        
        Scanner scanner = new Scanner(System.in);

        // 나이 입력
        while (true) {
            try {
                System.out.print("나이 입력 > ");
                int age = Integer.parseInt(scanner.nextLine());
                System.out.println("입력 받은 값: " + age);
                break;
                // 예외가 발생하면 break를 만나지 않고 catch로 가고,
                // 예외가 없으면 break를 만나서 반복문 밖으로..
            } catch (Exception e) {
                System.out.println("숫자만 입력 할 수 있습니다.");
                System.out.println("다시 입력 해주세요.");
            }
        }
        System.out.println("프로그램 종료");
        scanner.close();
    }
}

[문법적 키워드 복습, 정리]
문법적 키워드: 기본타입 8가지(int, char..), null, package, true, try...
클래스 이름: App, System, Math, main... 등등
int는 문법적 키워드라 변수명으로 쓸 수 없지만, String는 문법적 키워드가 아니라 변수명으로 쓸 수 있다. 즉, 키워드인지 아닌지 알아보기 위해서는 변수 명으로 써보기.

까먹었을때 보기 위해 정리하는 vscode 다크 테마 기준 단어들 색의 의미

  • 진한 파란색: 자바에서 지원하는 문법 키워드
  • 파란색: static 필드 ex) System.out.println(); 에서 out
  • 하늘색: 사용사가 지정한 변수의 이름
  • 연보라: 흐름제어 문법 키워드
  • 노란색: 메서드 이름
  • 초록색: 클래스 명, 데이터 타입(데이터 타입이 초록색인 이유는, 결국 타입들도 어딘가에 정의되어 있는 클래스의 이름이기 때문에)
  • 주황색: 문자 리터럴
  • 연두색: 숫자 리터럴
  • 카키색: 주석

    괄호마다 색이 다른건 자바의 기능이 아니고, 에디터가 지원해주는 기능이다.
    괄호의 깊이가 깊어짐에 따라서 색이 바뀌는데 노랑 -> 보라 -> 파랑 순서로 바뀐다. 가장 바깥의 괄호가 노란색, 그 다음이 보라, 그 다음이 파랑이다. 이때, 파란색 괄호의 안에서 괄호를 또 열면 노란색으로 돌아가서 반복된다. 참고로 괄호의 구분은 없다.
profile
취업하고싶다...

0개의 댓글