백준 10952

문제

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.

입력

입력은 여러 개의 테스트 케이스로 이루어져 있다.

각 테스트 케이스는 한 줄로 이루어져 있으며, 각 줄에 A와 B가 주어진다. (0 < A, B < 10)

입력의 마지막에는 0 두 개가 들어온다.

 


 

처음 접근한 방법

BufferedReader, BufferedWriter를 사용해서 입력, 출력한다.

반복문 안에서 더하기 연산을 수행하고, 만약 입력값이 0이라면 반복을 멈추고 결과값들을 출력한다.

package baekjoon;

import java.io.*;

public class B10952 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        String[] inputString = {};
        int sum;

        while (true) {
            inputString = br.readLine().split(" ");

            if("0".equals(inputString[0])){
                break;
            }

            sum = 0;

            for (int i = 0; i < inputString.length; i++) {
                sum += Integer.parseInt(inputString[i]);
            }

            bw.write(sum + "\n");
        }

        bw.flush();
        bw.close();
        br.close();
    }
}

 

 

초기 코드의 문제점

 

반복문을 멈추는 조건문의 조건식이

입력받은 문자열을 공백 기준으로 분리해서 저장한 배열의 첫 번째 인덱스 요소가 "0"일 때 break 한다.

이렇게 되면 0, 1을 더하는 연산도 수행하지 않고 반복문이 중단되기 때문에, 반드시 "0 0"이 입력되었을 때만 중단하도록 수정해야한다.

 

 

개선한 코드

if("0".equals(inputString[0]) && "0".equals(inputString[1])){
    break;
}

 

 


결과

문제 1

기존의 for문으로 인덱스 번호와 데이터를 같이 출력하던 코드를 스트림을 적용한 코드로 리팩토링 하는 과정에서, 인덱스 번호없이 출력해야 하는 문제 발생

for문
stream

 


분석

일반적인 스트림은 for문처럼 차례대로 루프를 도는 것이 아니라, 모든 요소가 각 연산 단계를 같은 시점에 수행하기 때문에 인덱스 값을 1씩 늘리면서 출력하는 게 불가능했다.

이를 해결하기 위해 데이터에 인덱스 필드를 추가해야겠다고 생각했다.

그런데 인덱스를 추가하려면 개별적인 menuItem을 관리하는 menu 클래스에 인덱스 값을 가지는 필드를 추가해야 했고, 

menu 클래스는 데이터를 map 자료구조를 통해 관리하고 있다.

key값은 각 menuItem, value값은 해당 요소의 수량 정보를 저장하고 있어서, 인덱스 필드를 넣기에는 또다시 자료구조에 변화를 줘야 했다.

 

알아보니 단순히 연산을 하기 위해 사용하는 기본형 특화 스트림이 존재했다.

기존의 스트림이 for-each문과 비슷한 기능을 했다면, 기본형 특화 스트림은 기본형 for문과 비슷한 기능을 하는 것 같다.

기본형 특화 스트림은 IntStream, LongStream, DoubleStream이 있었고, 나는 단순히 인덱스 번호로 활용할 거기 때문에 IntStream을 적용했다.

 


해결

IntStream.range(0, categoryList.size())
        .forEach(i -> {
            System.out.print((i + 1) + ". ");
            System.out.println(categoryList.get(i).getCategoryName());
        });

 

첫 줄 코드를 보면 range 메서드로 반복 수행할 범위를 지정할 수 있다.

그리고 두 번째 줄부터 forEach 최종 단계 연산으로 인덱스 번호와, 인덱스 번호에 해당하는 요소를 가져와 출력했다.

이 기본형 특화 스트림으로 for문 대신 인덱스 번호와 데이터를 함께 출력할 수 있었다.

 

 


문제 2

장바구니 안의 특정 이름을 가지는 데이터만 제거하는 기능을 스트림으로 구현하는 과정에서 생긴 문제다.

아래 코드를 실행하면 제거를 수행해도 결과물에 해당 데이터가 제거되지 않고 그대로 출력된다.

Stream<MenuItem> forRemove = myCart.getCartItemList().keySet().stream()
                .filter(item -> "SmokeShack".equals(item.getName()));

myCart.getCartItemList().remove(forRemove);

 

 


원인 분석

브레이크포인트를 걸고 디버그 모드로 실행해도 스트림의 모든 과정을 거치지만 결과물은 제거되지 않는 상태였다.

이 문제는 스트림이 최종 연산 단계를 거쳐야만 중간 연산을 실행하기 때문에 발생한 것이었다.

 

최종 연산 단계를 거치기 위해 메서드를 살펴봤지만, 굳이 또다른 컬렉션을 만들면 새로 만들어진 컬렉션을 이후 프로그램에 사용해야 하므로 collect 메서드를 사용하는 방법은 불가능하다.

 

그러다 발견한 메서드는 ifPresent()이다.

이전 단계에서 필터링된 요소가 존재하는 경우에 괄호 안의 코드를 수행하는 메서드이다.

 

 

이번에는 이미지처럼 오류가 발생했다.

찾아보니 ifPresent는 스트림의 최종 연산이 아니라, Optional<T>의 최종 연산 메서드였다.

즉, 이전 단계해서 반환되는 데이터의 형식이 Optional<T> 여야 한다.

이를 해결하려면 Optional<T>를 반환해주는 스트림의 최종 연산 메서드인 fineFirst() 메서드를 사용하면 해결 가능하다.

 


해결

 

filter는 해당하는 요소가 없을 경우 null을 반환하는 게 아니라, 빈 스트림을 반환한다.

이 빈 스트림이 findFirst() 메서드에 입력되면 Optional.empty()가 실행되어 Optional로 감싸진 null을 반환한다.

만약 빈 스트림이 아니라면 findFirst() 메서드는 Optional<MenuItem>을 반환하게 된다.

이후 ifPresent()는 값이 존재하는 경우에 내부 코드를 실행하여 해당 데이터를 삭제하는 remove 메서드를 실행하게 된다.

 

findFirst() 메서드는 필터링된 스트림에서 첫 번째 요소를 찾고, 그 요소를 Optional<T>로 반환하는 기능을 한다.

만약 내가 각 item을 리스트에 저장했다면, 필터링된 요소가 2개 이상인 경우도 있을 것이기 때문에 (삭제해야 할 데이터를 2개 이상 장바구니에 담은 상황) 이 코드로 완전히 해당 요소를 제거할 수 없었을 것이다.

하지만 나는 map을 사용해서 데이터를 장바구니에 저장했고, 동일한 menuItem은 덮어쓰여지면서 저장되기 때문에, 필터링된 요소는 단 하나의 요소만 반환하게 되어 있다.

이전에 다른 문제를 해결하느라 자료구조를 map으로 변경했는데, 그 결과로 인해 findFirst() 메서드를 사용해서 편리하게 값을 제거할 수 있었다.

2025.03.12 - [트러블 슈팅] - [Java] 리스트에 담긴 데이터 중복 출력 이슈

 

[Java] 리스트에 담긴 데이터 중복 출력 이슈

문제Cart 클래스 내의 `CartItemList`에 동일한 `menuItem`을 여러 번 담은 상황에서,기존의 코드는 출력하면 `menuItem`이 개수만큼 출력됐다.`menuItem`을 한 번만 출력하되 수량을 함께 출력할 수 있게 코드

go-getter1kim.tistory.com

 

 


결과

 

문제

Cart 클래스 내의 `CartItemList`에 동일한 `menuItem`을 여러 번 담은 상황에서,

기존의 코드는 출력하면 `menuItem`이 개수만큼 출력됐다.

`menuItem`을 한 번만 출력하되 수량을 함께 출력할 수 있게 코드를 아래와 같이 수정했다.

// Cart.java

private List<MenuItem> cartItemList = new ArrayList<>();

public boolean checkDuplication(MenuItem item){
        if(cartItemList.get(0)==item){
            return false;
        }else{
            for (int i = 0; i < cartItemList.indexOf(item); i++) {
                if(cartItemList.get(i)==item){
                    return true;
                }
            }
            return false;
        }
    }
// MenuView.java

for(MenuItem item : cart.getCartItemList()){
            if(!cart.checkDuplication(item)){
                System.out.print(item.getName() + " | ");
                System.out.print(item.getPrice() + " | ");
                System.out.print(cart.getQuantity(item) + " | ");
                System.out.println(item.getExplanation());
            }
        }

 

나의 의도는 `getCartItemList()` 메서드로 Cart 클래스 안에 있는 `CartItemList`에 접근해서 for-each문으로 각각의 `menuItem`을 출력하는 것이다.

이때 `checkDuplication()` 메서드에 각 요소를 전달한다.

`checkDuplication()` 메서드 안에서는 전달받은 요소가 첫 번째 요소면 무조건 출력할 수 있도록 바로 중복 여부를 false로 반환하고,

그 이후의 요소들은 이전에 존재하는 요소인지 확인하는 과정을 거치고, 처음 나온 요소인 경우만 출력할 수 있도록 한다.

 

그러나 위 코드의 문제는 중복을 점검하는 메서드를 거쳐도 여전히 중복되어 나온다는 것이다.

 


 

원인 분석

A버거 2개, B버거 2개를 장바구니에 담아놓고 출력하는 과정을 디버깅으로 확인했다.

 

같은 요소는 동일한 주소값을 가지고 있기 때문에, (A버거는 1059, B버거는 1066)

A버거의 경우는 `equals()`나 `==`을 사용해서 비교하면 같은 값으로 인식해서 중복 여부가 false가 되어 버린다.

if(cartItemList.get(0)==item){
	return false;
}

 

 

그렇다면 A버거 이후에 장바구니에 담았던 B버거는 위의 조건문에 해당하지 않으므로 제대로 중복없이 출력이 되어야 하지만 B버거도 마찬가지로 중복으로 출력된다.

그 원인은 indexOf 메서드에 있다.

for (int i = 0; i < cartItemList.indexOf(item); i++) {
    if(cartItemList.get(i)==item){
        return true;
    }
}
return false;

 

`indexOf()`는 해당 요소의 정확한 인덱스 번호를 반환하는 게 아니라, 리스트 내부를 순회하다가 가장 처음 만난 동일한 요소의 인덱스를 반환한다.

그렇기 때문에 세 번째로 입력한 B버거와 네 번째로 입력한 B버거 모두, for문의 조건식 `i < cartItemList.indexOf(item)`이 `i < 2`로 적용된다.

세 번째로 입력한 B버거는 앞서 입력된 A버거와 다른 인스턴스이기 때문에 조건문에 해당하지 않아, 정상적으로 반복문 밖에 있는 return false가 실행된다.

네 번째로 입력한 B버거 역시 indexOf로 인해 A버거와만 비교되기 때문에, 반복문 밖의 return false를 실행하게 된다.

 


 

해결

이 문제를 해결하기 위해서는 Cart 클래스에 전역 변수를 선언해서, checkDuplication 메서드를 호출한 횟수를 세어야 한다.

횟수를 조건문에 적용해서 첫 번째 A버거와 두 번째 A버거, 첫번째 B버거와 두 번째 B버거를 비교해가면서 중복 여부를 판단하기에는 너무 복잡한 메서드가 되고, 

장바구니 내역을 출력할 때마다 전역 변수를 초기화 해주어야 한다.

위 알고리즘을 적용하기에는 너무 가독성이 떨어지고 이해하기 어려운 코드가 되기 때문에,

List가 아닌 Map 자료구조를 적용하기로 했다.

 

Map은 List와 다르게 중복을 허용하지 않으면서, key-value로 값을 입력한다.

중복을 허용하지 않으면 같은 메뉴 아이템을 어떻게 여러 번 담을 수 있을까?

바로 기존의 데이터를 덮어쓰는 방식으로 진행해야 한다.

조건문으로 이전에 동일한 요소가 저장된 적이 있는지 확인할 필요없이 코드 한 줄로 해결이 가능하다.

cartItemList.put(item, cartItemList.getOrDefault(item, 0) + 1)

 

`getOrDefault(key, defaultValue)`는 동일한 key값이 저장된 적 있으면 기존의 값을 가져오고, 

저장된 적이 없으면 defaultValue에 지정한 값을 가져온다.

따라서 위의 코드를 해석하면 요소를 value값과 함께 Map에 저장할 건데,

이전에 동일한 요소가 저장된 게 없으면 value값을 1로 지정해서 요소를 넣고,

이전에 동일한 요소가 있으면 저장되어 있던 value값에 1을 더해서 덮어쓰겠다! 하는 코드이다.

즉, 여기서 value는 요소의 개수(quantity)가 되므로 따로 `getQuantity()`의 로직을 만들 필요 없이 아래처럼 Map이 제공하는 메서드 `get()`을 이용하면 된다.

public int getQuantity(MenuItem item) {
    return cartItemList.get(item);
}

 

결과를 출력하는 클래스에서도 중복을 확인하는 과정없이 아래 코드로 작성하면 된다.

여기서 `keySet()`은 Map에서 key값만 가지는 Set<T>을 반환하는 메서드로, 장바구니에 저장되어 있던 `menuItem` Set이 된다.

for (MenuItem item : cart.getCartItemList().keySet()) {
    System.out.print(item.getName() + " | ");
    System.out.print(item.getPrice() + " | ");
    System.out.print(cart.getQuantity(item) + "개 | ");
    System.out.println(item.getExplanation());
}

 


 

결과

 

이미지를 보면 각 요소가 중복되지 않고 출력되는 것을 볼 수 있고, 수량도 제대로 2개씩 출력된다.

 

 

 

 

 

+2025/03/14 추가

과제 해설 세션을 통해 `map.put(key, map.getOrDefault(key, 0) + 1)`와 같은 기능을 하면서 조금 더 간단한 메서드를 알게 됐다.

map.merge(key, value, remappingFunction)
Map<String, Integer> map = new HashMap<>();
map.put("apple", 2);
map.merge("apple", 1, Integer::sum); // apple의 값은 3이 됨

 

key가 없으면 value를 새로 삽입하고, key가 이미 존재하면 remappingFunction을 통해 두 값을 병합하는 메서드이다.

Integer.sum() 메서드를 통해 기존에 입력된 2와 새로 머지할 1을 더하기 연산하여 저장할 수 있다.

자바에서 null 값을 참조할 때 발생하는 런타임 예외

 

NPE가 발생하는 대표적인 상황

1. null 객체의 메서드를 호출할 때

String str = null;
System.out.println(str.length()); // ❌ NPE 발생

 

 

2. null 객체의 필드에 접근할 때

class Person {
    String name;
}

public static void main(String[] args) {
    Person p = null;
    System.out.println(p.name); // ❌ NPE 발생
}

 

 

3. null을 배열처럼 사용하려 할 때

int[] arr = null;
System.out.println(arr.length); // ❌ NPE 발생

 

 

4. null을 포함한 equals() 호출

String input = null;
if (input.equals("exit")) {  // ❌ NPE 발생
    System.out.println("프로그램 종료");
}
if ("exit".equals(input)) {  // ✅ NPE 방지 - 상수값을 앞에 두고 비교
    System.out.println("프로그램 종료");
}

 

 

5. null 값을 unboxing할 때 (Wrapper 클래스)

Integer num = null;
int value = num; // ❌ NPE 발생 (null을 int로 변환 불가)

'TIL' 카테고리의 다른 글

프로세스와 스레드의 동작 원리  (0) 2025.03.23
웹서버 애플리케이션 관점에서의 Thread Pool  (0) 2025.03.21
JVM 메모리 구조  (0) 2025.02.25
이스케이프 시퀀스  (0) 2025.02.22
NumberFormat 런타임 에러  (0) 2025.02.21

입출력 성능을 향상시키기 위해 버터를 사용하는 자바의 입출력 클래스다.

Scanner는 사용자가 입력하는 값을 바로 읽고 출력하지만, Buffer는 입력값 또는 출력값을 모아놨다가 한 번에 처리하는 방식이다.

 

BufferedReader를 사용할 때 예외 처리가 필요하고, 버퍼를 사용해서 입출력할 때 문자열 변환 과정이 필요하다는 단점이 있지만, 한 번에 모아서 데이터를 처리하는 과정에서 입출력 속도를 향상시킬 수 있다.

 


BufferedReader

  • 문자 기반 입력 스트림
    • 입력값이 정수라면 아스키 코드 출력
    • 입력값이 실수라면 NumberFormatException 발생
    • => 문자열로 변환하는 과정 필요
  • read() : 한 문자 단위 읽기 -> 아스키코드로 변환하여 int형으로 반환
  • readLine() : 한 줄 단위 읽기
  • 예외 처리 필요
    • 파일을 read 할 때, 파일이 존재하지 않는 경우 IOException (FileNotFoundException) 발생
    • 네트워크 스트림을 읽을 때, 서버 연결이 끊어지거나 권한 문제가 발생하여 파일을 읽지 못할 때 IOException 발생
    • try-catch 블록으로 적절한 예외 처리 필요함
import java.io.*;

public class BufferedReaderExample {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 콘솔 입력

        System.out.print("입력하세요: ");
        String input = br.readLine();  // 한 줄 입력받기
        System.out.println("입력값: " + input);

        br.close();  // 리소스 해제
    }
}

 


 

BufferedWriter

  • 문자 기반 출력 스트림
    • 문자열 외의 데이터 타입을 출력하려면, 문자열로 변환 후 출력
    • 개행 문자를 포함해서 출력
  • write() : 문자열이 버퍼에 쌓임
    • Buffer가 가득 찼을 때는 write() 실행 시 바로 출력됨
  • newLine() : 줄바꿈(\n)이 버퍼에 쌓임
  • flush() : 버퍼에 쌓여있던 출력
    • close()를 사용하면 자동으로 flush()를 호출
import java.io.*;

public class BufferedWriterExample {
    public static void main(String[] args) throws IOException {
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); // 콘솔 출력

        bw.write("Hello, BufferedWriter!");
        bw.newLine();  // 개행 (== \n)
        bw.write("Java I/O 성능 향상!");
        bw.flush();  // 버퍼 비우기 (출력)

        bw.close();  // 리소스 해제
    }
}

 


 

Buffer 사용 후 close() 하지 않으면 발생하는 문제점

문제

package baekjoon;

import java.io.*;

public class Buffer {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        String inputCnt = br.readLine();
        int cnt = Integer.parseInt(inputCnt);
        
        while(cnt!=0){
            String inputNums = br.readLine();
            String[] stringNums = inputNums.split(" ");

            int sum = 0;
            for(String i : stringNums){
                sum += Integer.parseInt(i);
            }
            bw.write(sum);
            bw.newLine();
            cnt--;
        }
        bw.flush();
        bw.close();
    }
}

 

코드를 위와 같이 작성했을 때, 입력만 받고 출력없이 프로그램이 종료되는 문제가 발생했다.

 


원인

 

디버깅 했을 때, 출력할 변수인 sum에도 값이 잘 들어가 있는 걸 볼 수 있는데 출력이 되지 않은 걸 보니, `bw.write(sum)`, `bw.flush()` 부분 때문인 것 같다.

어딘가에 실수가 있다기 보다는 내가 BufferedWriter를 이해하고 있지 않은 상태에서 작성한 코드라 조금 더 BufferedWriter에 대해 찾아보면 해결 가능할 것 같았다.

 


분석

찾아보니 BufferedWriter는 정수를 매개변수로 전달받지만 내부적으로는 값을 아스키코드로 변환해서 문자열로 다루는 함수였다.

따라서 전달한 값을 의도대로 출력하기 위해서는 valueOf로 문자열로 변환한 후에 출력하거나, 개행문자를 추가해주면 됐다.


아스키코드로 변환해서 출력하는 시스템인데, 왜 나는 아무것도 출력이 되지 않았을까해서 아스키코드를 살펴봤다.

피연산자를 1, 2, 3 같이 작은 숫자로만 지정하고 테스트를 했다보니 해당하는 아스키코드 값이 SOH, STX 등의 제어 문자였다.

아래와 같이 피연산자의 값을 크게 지정하고 실행하니 아스키코드 'A'가 출력되는 걸 볼 수 있었다.

 


 

해결

 

첨부된 이미지처럼 write 메서드 안에 문자열을 추가해주니 결과값이 제대로 출력되는 것을 볼 수 있었다.

 

1. 예외 복구 (Exception Recovery)

예외가 발생한 후, 예외 상황을 처리하고 프로그램이 정상적으로 계속 실행될 수 있도록 하는 방법

try {
    // 파일 읽기 작업
    FileReader file = new FileReader("file.txt");
} catch (FileNotFoundException e) {
    // 예외 복구 - 다른 파일 경로 시도
    System.out.println("파일이 존재하지 않습니다. 다른 파일을 시도합니다.");
    FileReader file = new FileReader("backup_file.txt");
}

 


 

2. 예외 회피 (Exception Avoidance)

예외가 발생하지 않도록 사전 예방적인 조치를 취하는 방식

File file = new File("file.txt");
if (file.exists()) {
    FileReader file = new FileReader("file.txt");
} else {
    System.out.println("파일이 존재하지 않습니다.");
}

 


 

3. 예외 전환 (Exception Propagation)

발생한 예외를 상위 메소드나 호출자에게 전달하는 방법

public void readFile() throws FileNotFoundException {
    FileReader file = new FileReader("file.txt");
}

public void processFile() {
    try {
        readFile();
    } catch (FileNotFoundException e) {
        System.out.println("파일을 찾을 수 없습니다.");
    }
}

 


 

예외 전환의 필요성

책임 분리

  • 예외를 상위 메소드로 전달해서 상위에서 전체적인 흐름을 관리
  • 어디서 예외가 발생했는지, 그 예외에 어떻게 반응해야 하는지를 더 높은 수준에서 결정
  • 아래 코드와 같이 더 구체적이고 명확하게 표현 가능
public void processFile() throws FileNotFoundException {
    // 파일을 읽는 로직
    FileReader file = new FileReader("file.txt"); // 예외 발생 가능
}

public void handleFileProcessing() {
    try {
        processFile(); // 예외 전환
    } catch (FileNotFoundException e) {
        System.out.println("파일을 찾을 수 없습니다.");
    }
}

 

유연성

  • 하위 메소드에서 예외를 처리하면 고정된 방식으로 처리
    • ex. 파일을 찾지 못하면 그 즉시 오류 메시지를 출력하거나 기본 파일을 대신 사용
  • 상위 메소드에서 예외를 받아 상황에 맞게 대응
    • ex. 예외가 발생했을 때 로그를 남기고 다른 작업을 이어서 실행, 또는 사용자에게 메시지를 출력하거나 애플리케이션을 종료

 

재사용성

  • 예외를 상위 메소드로 전환하면 하위 메소드는 더 일반적이고 재사용 가능한 형태로 남아, 다양한 상황에서 유연하게 사용 가능

 

 

'언어, 프레임워크 > Java' 카테고리의 다른 글

람다 실습하기 (Comparator, Compose, andThen)  (0) 2025.03.14
BufferedReader / BufferedWriter  (0) 2025.03.11
Assert 알아보기  (0) 2025.03.08
Collectors 클래스  (0) 2025.03.07
개선된 switch문  (0) 2025.03.06

 

1. 로컬에서 commit & push 할 때

타입: 변경 사항 요약 (이슈 번호)

필요하면 상세 설명 (선택)

git commit -m "feat: 회원가입 기능 추가 (#43)"
git commit -m "fix: 로그인 버그 수정 (비밀번호 검증 오류)"
git commit -m "refactor: UserService 리팩토링 (메서드 분리)"

 

  • 변경 사항은 최대한 간단하게 작성하되, 자주 커밋하기
  • 이슈 연결하는 경우 첫 번째 예시처럼 작성

 

2. PR할 때

제목
[타입] 작업 내용 요약

본문
## 작업 내용
- 회원가입 기능 추가
- 로그인 기능 구현 (JWT 토큰 발급)
- 유효성 검사 추가

하단
## 관련 이슈
Closes #42
  • 관련된 이슈가 있는 경우 하단(footer)에 이슈번호 추가
  • `Closes #이슈번호`를 포함하면 PR이 머지될 때 자동으로 이슈 닫힘

 

3. Merge할 때

제목
Merge pull request #PR번호 from 브랜치명

본문
PR 제목
Merge pull request #42 from feature/signup

회원가입 및 로그인 기능 구현

 

'도구 & 환경 설정 > Git' 카테고리의 다른 글

Git 명령어 / 협업 시 세팅 단계  (0) 2025.02.17

for 문

for 변수 in 반복가능객체:
	실행할 코드
  • 반복 가능한 객체 : range(), 리스트, 튜플, 문자열

예제

for i in range(5):  # 0~4 반복
	print(i)
fruits = ["사과", "바나나", "포도"]
for fruit in fruits:
	print(fruit)
for char in "Python"
	print(char)

한 줄짜리 for 문 (리스트 컴프리헨션)

numbers = [i for i in range(5)]
print(numbers) # [0, 1, 2, 3, 4]

 


while 문

while 조건:
	실행할 코드

 

예제

count = 0
while count < 3:
	print(count)
    count += 1
while True:
	text = input("끝내려면 'exit' 입력: ")
    if text == "exit":
    	print("반복문 종료")
        break

 

 


else가 있는 반복문

  • for / while이 정상 종료되면 else 블록 실행
  • break로 종료되면 else 블록 실행 안 됨
for i in range(3):
	print(i)
else:
	print("정상 종료")

 

  • 디버깅 용도
  • assert문 실패 시 AssertionError 예외 발생
  • 예외 처리를 위한 것이 아니라, 버그를 초기에 발견하는 목적으로 사용
  • 런타임에서 기본적으로 비활성화 되어 있고, JVM 실행 옵션 `-ea ` (enable assertions)를 활성화해야 동작

assert 기본 문법

기본 형태 - 조건식이 false이면 AssertionError 발생

assert 조건식

 

 

 

메시지 포함한 형태 - false이면 AssertionError가 발생하고, 메시지 출력

assert 조건식 : 메시지;

 

int age = -1;
assert age >= 0 : "나이는 음수가 될 수 없습니다!";


Exception in thread "main" java.lang.AssertionError: 나이는 음수가 될 수 없습니다!

 


assert 활성화 방법

// 활성화 방법
java -ea MyClass

// 비활성화 방법
java -da MyClass
  • JVM 실행 시 -ea 옵션이 없으면 assert 무시됨
  • 배포 환경에서는 비활성화되어 아무 동작 하지 않음 -> 디버깅 용도로만 사용

assert  vs 예외처리

'언어, 프레임워크 > Java' 카테고리의 다른 글

BufferedReader / BufferedWriter  (0) 2025.03.11
예외 복구/회피/전환 (예외 전환의 필요성)  (0) 2025.03.10
Collectors 클래스  (0) 2025.03.07
개선된 switch문  (0) 2025.03.06
enum 이해하기  (0) 2025.03.06