Java Stream으로 리스트에서 50 초과 숫자 개수 구하기

Java Stream을 연습할 때 리스트에서 50 초과 숫자 개수를 구하는 문제는 filter()와 count()의 역할을 익히기에 좋은 예제입니다. 반복문으로도 충분히 풀 수 있지만, Stream으로 작성하면 “조건에 맞는 값만 남기고, 남은 개수를 센다”는 흐름을 코드에 비교적 명확하게 담을 수 있습니다.

다룰 문제는 다음과 같습니다.

> 정수 리스트에서 50보다 큰 숫자가 몇 개인지 구하라.

처음에는 간단해 보이지만, 실제로 코드를 작성하다 보면 filter()가 무엇을 반환하는지, count() 결과를 왜 long으로 받아야 하는지, “50 초과”와 “50 이상”을 어떻게 구분해야 하는지에서 실수가 자주 나옵니다. 그래서 단순히 정답 코드만 보는 것보다, 조건을 코드로 옮기는 과정을 함께 확인하는 편이 좋습니다.

문제 조건을 먼저 사람이 읽는 방식으로 풀어 보기

예제에서 사용할 리스트는 다음과 같습니다.

[30, 60, 40, 70, 20, 55, 80, 35]

이 중에서 50 초과인 숫자를 직접 골라 보면 다음 네 개입니다.

60, 70, 55, 80

따라서 기대하는 결과는 4입니다.

Stream 코드를 작성하기 전에 이렇게 손으로 한 번 확인해 두면, 실행 결과가 맞는지 판단하기 쉽습니다. 특히 초보 단계에서는 코드가 실행된다는 사실보다 “내가 작성한 조건이 문제 문장과 같은 의미인지”를 확인하는 과정이 더 중요합니다.

이 문제를 Java Stream으로 옮기면 흐름은 다음과 같습니다.

1. 숫자 리스트를 준비한다. 2. 리스트에서 Stream을 만든다. 3. filter()로 50보다 큰 숫자만 남긴다. 4. count()로 남은 요소의 개수를 센다.

짧게 표현하면 “걸러낸 뒤 개수를 센다”입니다.

전체 예제 코드로 먼저 실행해 보기

아래 코드는 그대로 복사해서 실행할 수 있는 완성 예제입니다.

import java.util.Arrays;
import java.util.List;

public class StreamCountExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(30, 60, 40, 70, 20, 55, 80, 35);

        System.out.println("숫자 리스트: " + numbers);

        long count = numbers.stream()
                .filter(n -> n > 50)
                .count();

        System.out.println("50 초과인 숫자 개수: " + count);
    }
}

실행 결과는 다음과 같습니다.

숫자 리스트: [30, 60, 40, 70, 20, 55, 80, 35]
50 초과인 숫자 개수: 4

60, 70, 55, 80이 조건을 만족하므로 결과가 4로 출력됩니다.

여기서 눈여겨볼 부분은 변수 타입입니다.

long count = numbers.stream()
        .filter(n -> n > 50)
        .count();

count()는 int가 아니라 long을 반환합니다. 리스트 크기가 작은 예제에서는 큰 차이를 느끼기 어렵지만, Java Stream API 기준으로 count()의 반환 타입은 long입니다. 따라서 예제 단계에서도 long으로 받는 습관을 들이는 것이 좋습니다.

filter()와 count()를 한 줄씩 읽는 방법

Stream 문법이 낯설면 아래처럼 메서드가 이어지는 구조가 복잡하게 보일 수 있습니다.

numbers.stream()
        .filter(n -> n > 50)
        .count();

하지만 각 줄의 역할을 나누면 어렵지 않습니다.

numbers.stream()

numbers는 List<Integer>입니다. stream()을 호출하면 리스트의 요소들을 순서대로 처리할 수 있는 Stream 흐름이 만들어집니다.

.filter(n -> n > 50)

filter()는 조건을 만족하는 요소만 다음 단계로 넘깁니다. 여기서 n -> n > 50은 람다식이며, 의미는 “n이 50보다 크면 통과시킨다”입니다.

반복문과 비교하면 아래 조건문과 비슷하게 읽을 수 있습니다.

if (n > 50) {
    // 조건을 만족하므로 개수 세기 대상이 됨
}

마지막 단계는 count()입니다.

.count()

count()는 현재 Stream에 남아 있는 요소의 개수를 셉니다. 이 예제에서는 filter()를 통과한 숫자가 네 개이므로 4가 됩니다.

주의할 점은 filter() 자체가 개수를 세는 메서드는 아니라는 것입니다. filter()는 어디까지나 조건에 맞는 값만 남기고, 실제 개수 계산은 count()가 담당합니다.

반복문 풀이와 Stream 풀이 비교

Stream을 왜 쓰는지 잘 와닿지 않는다면 반복문 코드와 나란히 비교해 보는 것이 도움이 됩니다.

import java.util.Arrays;
import java.util.List;

public class LoopCountExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(30, 60, 40, 70, 20, 55, 80, 35);

        int count = 0;

        for (int number : numbers) {
            if (number > 50) {
                count++;
            }
        }

        System.out.println("50 초과인 숫자 개수: " + count);
    }
}

반복문 방식도 정확한 풀이입니다. 오히려 처음 자바를 배우는 단계에서는 반복문이 더 직관적일 수 있습니다. 조건문 안에서 카운터를 증가시키는 과정이 눈에 잘 보이기 때문입니다.

같은 문제를 Stream으로 쓰면 다음과 같습니다.

long count = numbers.stream()
        .filter(n -> n > 50)
        .count();

Stream 방식은 중간 변수나 카운터 증가 코드를 직접 작성하지 않고, “50 초과인 값만 필터링한 뒤 개수를 센다”는 의도를 메서드 조합으로 표현합니다.

다만 Stream이 항상 반복문보다 좋다고 말하기는 어렵습니다. 디버깅이 쉬워야 하는 상황, 복잡한 조건을 단계별로 추적해야 하는 상황, 팀에서 반복문 스타일을 선호하는 상황이라면 반복문이 더 적절할 수 있습니다. 반대로 조건 검색, 집계, 변환처럼 데이터 처리 흐름이 분명한 경우에는 Stream 코드가 읽기 좋은 선택이 될 수 있습니다.

수업에서 자주 본 실수: 초과와 이상을 섞어 쓰는 경우

수업에서 Java Stream 기초 문제를 다룰 때 자주 본 실수는 Stream 문법 자체보다 비교 연산자 선택에서 나왔습니다. 문제에는 “50 초과”라고 적혀 있는데 코드에는 n >= 50을 쓰는 경우가 많았습니다.

  • 50 초과: n > 50
  • 50 이상: n >= 50

두 조건은 비슷해 보이지만 50이라는 값이 리스트에 포함되면 결과가 달라집니다.

아래 코드를 실행해 보면 차이가 바로 보입니다.

import java.util.Arrays;
import java.util.List;

public class GreaterThanCompareExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(30, 50, 60, 70);

        long greaterThan50 = numbers.stream()
                .filter(n -> n > 50)
                .count();

        long greaterThanOrEqual50 = numbers.stream()
                .filter(n -> n >= 50)
                .count();

        System.out.println("50 초과: " + greaterThan50);
        System.out.println("50 이상: " + greaterThanOrEqual50);
    }
}

실행 결과는 다음과 같습니다.

50 초과: 2
50 이상: 3

n > 50에서는 60, 70만 통과합니다. 반면 n >= 50에서는 50, 60, 70이 통과합니다.

직접 코드를 정리해 보니, 이 문제는 Stream을 얼마나 잘 아느냐보다 문제 문장을 얼마나 정확히 코드로 바꾸느냐가 더 중요했습니다. 특히 코딩 테스트나 과제에서는 “초과”, “이상”, “미만”, “이하”를 잘못 해석하면 알고리즘이 맞아도 결과가 틀릴 수 있습니다.

조건식만 바꾸면 다른 개수 세기 문제에도 응용된다

stream() → filter() → count() 구조는 그대로 두고, filter() 안의 조건식만 바꾸면 여러 문제로 확장할 수 있습니다.

70 이상인 숫자 개수 구하기

long count70OrMore = numbers.stream()
        .filter(n -> n >= 70)
        .count();

System.out.println("70 이상인 숫자 개수: " + count70OrMore);

짝수 개수 구하기

long evenCount = numbers.stream()
        .filter(n -> n % 2 == 0)
        .count();

System.out.println("짝수 개수: " + evenCount);

30 이하인 숫자 개수 구하기

long count30OrLess = numbers.stream()
        .filter(n -> n <= 30)
        .count();

System.out.println("30 이하인 숫자 개수: " + count30OrLess);

처음 Stream을 배울 때는 map(), collect(), reduce() 같은 메서드를 한꺼번에 외우려고 하기보다, filter()와 count() 조합을 정확히 익히는 편이 좋습니다. 이 패턴만 익혀도 리스트에서 조건에 맞는 값의 개수를 구하는 문제는 대부분 해결할 수 있습니다.

수업 실습 문제와 풀이 코드

아래 리스트를 사용해서 직접 실습해 보세요.

List<Integer> scores = Arrays.asList(45, 50, 51, 67, 89, 90, 100);

풀어 볼 문제는 세 가지입니다.

1. 50 초과인 숫자의 개수를 구하기 2. 90 이상인 숫자의 개수를 구하기 3. 홀수인 숫자의 개수를 구하기

먼저 예상 결과를 손으로 적어 보는 것이 좋습니다.

  • 50 초과: 51, 67, 89, 90, 100 → 5개
  • 90 이상: 90, 100 → 2개
  • 홀수: 45, 51, 67, 89 → 4개

풀이 코드

import java.util.Arrays;
import java.util.List;

public class StreamPracticeSolution {
    public static void main(String[] args) {
        List<Integer> scores = Arrays.asList(45, 50, 51, 67, 89, 90, 100);

        long over50Count = scores.stream()
                .filter(score -> score > 50)
                .count();

        long overOrEqual90Count = scores.stream()
                .filter(score -> score >= 90)
                .count();

        long oddCount = scores.stream()
                .filter(score -> score % 2 != 0)
                .count();

        System.out.println("50 초과인 숫자 개수: " + over50Count);
        System.out.println("90 이상인 숫자 개수: " + overOrEqual90Count);
        System.out.println("홀수인 숫자 개수: " + oddCount);
    }
}

실행 결과는 다음과 같습니다.

50 초과인 숫자 개수: 5
90 이상인 숫자 개수: 2
홀수인 숫자 개수: 4

실습할 때는 결과 숫자만 맞히고 넘어가기보다, 어떤 값이 filter()를 통과했는지 함께 확인해 보는 것이 좋습니다. 예를 들어 score > 50에서는 50이 포함되지 않습니다. 이 한 가지를 놓치면 첫 번째 문제의 답을 6으로 잘못 생각할 수 있습니다.

실행 결과가 예상과 다를 때 점검할 부분

코드를 실행했는데 예상 결과와 다르다면 아래 순서로 확인해 보세요.

  • 문제에서 요구한 조건이 “초과”인지 “이상”인지 다시 확인합니다.
  • filter() 안의 비교 연산자가 문제 조건과 일치하는지 봅니다.
  • count() 결과를 int가 아니라 long으로 받고 있는지 확인합니다.
  • 리스트에 경계값인 50, 90 등이 포함되어 있는지 확인합니다.
  • 홀수 조건에서는 score % 2 != 0, 짝수 조건에서는 score % 2 == 0을 사용했는지 봅니다.

Stream 코드는 짧기 때문에 오히려 작은 조건 실수가 눈에 잘 띄지 않을 수 있습니다. 특히 람다식 안의 조건은 전체 결과를 결정하므로, 처음에는 조건식을 바꿀 때마다 테스트용 출력이나 손계산으로 검증하는 습관을 들이는 것이 안전합니다.

객체 리스트에서도 같은 방식으로 확장할 수 있다

숫자 리스트에서 50 초과 숫자 개수를 구하는 예제는 단순하지만, 실제 자바 코드에서는 객체 리스트에도 같은 패턴을 적용할 수 있습니다.

예를 들어 학생 점수 객체가 있다고 가정하면 다음처럼 사용할 수 있습니다.

class Student {
    private final String name;
    private final int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public int getScore() {
        return score;
    }
}

점수가 50 초과인 학생 수는 다음처럼 구할 수 있습니다.

List<Student> students = Arrays.asList(
        new Student("Kim", 45),
        new Student("Lee", 60),
        new Student("Park", 75)
);

long passedCount = students.stream()
        .filter(student -> student.getScore() > 50)
        .count();

System.out.println("50 초과 점수 학생 수: " + passedCount);

숫자 자체를 비교할 때는 n > 50을 사용했고, 객체에서는 student.getScore() > 50처럼 객체의 값을 꺼내 비교합니다. 구조는 동일합니다.

stream() → filter(조건) → count()

이 패턴을 익혀 두면 회원 목록에서 특정 조건을 만족하는 사용자 수, 상품 목록에서 재고가 남은 상품 수, 점수 목록에서 기준을 넘은 학생 수 등을 구할 때 응용할 수 있습니다.

기억해 둘 내용

Java Stream으로 리스트에서 50 초과 숫자 개수를 구할 때는 filter()와 count()를 구분해서 이해해야 합니다.

  • stream()은 리스트를 Stream 처리 흐름으로 바꿉니다.
  • filter(n -> n > 50)는 50 초과 숫자만 남깁니다.
  • count()는 남은 요소의 개수를 셉니다.
  • count()의 반환 타입은 long입니다.
  • “초과”는 >, “이상”은 >=로 작성합니다.

이 예제는 짧지만 Stream의 기본 흐름을 익히기에 좋습니다. 처음에는 숫자 리스트로 연습하고, 익숙해지면 객체 리스트의 특정 필드를 기준으로 조건을 걸어 보세요. 코드를 실행한 뒤에는 반드시 어떤 값이 조건을 통과했는지 직접 확인하는 과정까지 함께 해 보는 것이 좋습니다.

참고 자료

  • [Oracle Java Stream API 공식 문서](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/Stream.html)
  • [Oracle Java List 공식 문서](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/List.html)

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다