JAVA

모던 자바 12문제로 복습 — JAVA4 총정리

PANCO_IT
#자바#JAVA#람다#스트림#Optional#복습

여기까지 오셨다면 자바 8 이후의 문법, 이른바 모던 자바의 골격은 한 바퀴 다 도신 겁니다. 마지막 편은 새 내용 없이 시즌 전체를 점검합니다. 구성은 두 부입니다. 1부는 개념 12문제, 2부는 시즌 내내 마주쳤던 에러 화면 다섯 개를 직접 고치는 실습입니다.

람다에서 Optional까지, 지도 한 장

일곱 편은 사실 한 문장으로 이어져 있습니다. 할 일을 값으로 만들고(람다), 그 값이 끼워질 자리를 정의하고(함수형 인터페이스), 컨베이어에 태워 가공한 뒤(스트림), 결과를 상자로 받는다(Optional). 메서드 참조는 그 부품을 더 짧게 깎는 도구였죠.

람다 부품이 함수형 인터페이스 소켓에 꽂히고, 스트림 벨트에서 filter가 원소 하나를 떨어뜨리고 map이 모양을 바꾼 뒤, 물음표 뚜껑이 달린 상자에 담기는 시즌 전체 지도

그림 1. 벨트 위에서 실제로 일어나는 일 — 하나는 걸러져 떨어지고, 남은 것은 모양이 바뀌고, 물음표 뚜껑 상자에 담깁니다.

주제한 줄 압축대표 함정
1람다식추상 메서드 하나짜리 구현을 화살표로중괄호를 열면 return도 써야 함
2함수형 인터페이스람다가 끼워질 자리. 표준 4종이 이미 있음추상 메서드 2개면 람다 불가
3스트림 기초열기 → 손보기 → 닫기 세 토막최종 연산 없으면 아무 일도 없음
4중개 연산flatMap·distinct·sorted·limit·skip붙이는 순서가 결과를 바꿈
5최종 연산collect·count·reduce·find스트림은 일회용
6Optional값이 없을 수도 있음을 타입으로빈 상자에 get() 하면 그대로 터짐
7메서드 참조·클로저부르기만 하면 ::로 축약캡처한 지역변수는 사실상 final

1부 — 개념 12문제

빠르게 훑습니다. 틀린 문항은 해설 끝의 편 번호가 복습 좌표입니다.

미니 퀴즈

OX 5문제 + 4지선다 7문제

9개 이상이면 2부로, 그 아래라면 표의 복습 좌표를 먼저 다녀오시는 편이 빠릅니다.

2부 — 고장 난 코드 다섯 개

시즌 내내 이 화면들을 만났습니다. 이번에는 전부 여러분 손으로 고칩니다.

시즌에서 만난 컴파일 오류·런타임 예외·무출력·오답을 모아 놓은 터미널 화면

그림 2. 컴파일 오류 셋, 예외 둘, 그리고 오류도 없이 틀리는 답 하나.

각 문제는 실행창에 코드가 채워져 있습니다. 고친 뒤 실행해 기대 출력이 나오는지 확인하고, 막히면 아래 정답을 펼치세요.

문제 1. return이 사라졌습니다

컴파일부터 실패합니다. 한 글자도 지우지 말고, 한 단어만 추가해서 30이 출력되게 만들어 보세요.

문제 1 — 람다와 중괄호
interface Calculator {
  int calculate(int a, int b);
}

public class Main {
  public static void main(String[] args) {
      Calculator add = (a, b) -> { a + b; };   // 이 줄이 문제입니다
      System.out.println(add.calculate(10, 20));
  }
}

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

정답 보기

{ return a + b; } — 중괄호를 여는 순간 일반 메서드 본문이라 return이 필요합니다. 아예 중괄호를 지우고 (a, b) -> a + b로 써도 됩니다. 1편의 규칙: 타입을 적으면 괄호도, 중괄호를 열면 return도.

문제 2. 분명히 filter를 불렀는데 조용합니다

실행하면 아무것도 출력되지 않습니다. 오류도 없습니다. 짝수 [2, 4, 6]이 출력되도록 고쳐 보세요.

문제 2 — 지연 연산
import java.util.List;

public class Main {
  public static void main(String[] args) {
      List<Integer> nums = List.of(1, 2, 3, 4, 5, 6);

      nums.stream()
          .filter(n -> n % 2 == 0);   // 여기서 끝나 있습니다
  }
}

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

정답 보기

끝에 .forEach(System.out::println); 을 붙이면 됩니다(또는 .collect(...)로 받아서 출력). 중간 연산은 주문서일 뿐, 최종 연산이 나와야 벨트가 돕니다. 3편의 핵심이자 5편의 출발점이었습니다.

문제 3. 오류는 없는데 답이 틀립니다

상위 3개 점수를 원했는데 [95, 72, 60]이 나옵니다. 최고점 100이 사라졌죠. [100, 95, 88]이 나오게 고쳐 보세요.

문제 3 — 순서가 바꾼 답
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
      List<Integer> scores = List.of(72, 95, 60, 88, 100, 51);

      System.out.println(scores.stream()
              .limit(3)
              .sorted(Comparator.reverseOrder())
              .collect(Collectors.toList()));
  }
}

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

정답 보기

sortedlimit의 순서를 바꿉니다 — .sorted(Comparator.reverseOrder()).limit(3). 원래 코드는 앞의 세 명만 잘라서 줄 세운 것이었습니다. 컴파일러가 못 잡아 주는 4편의 함정이라, 이런 버그는 데이터를 눈으로 봐야 드러납니다.

문제 4. 두 번째 줄에서 터집니다

첫 출력은 정상인데 두 번째에서 IllegalStateException이 납니다. 두 결과가 모두 출력되게 고쳐 보세요.

문제 4 — 일회용 스트림
import java.util.List;
import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
      List<Integer> nums = List.of(1, 2, 3, 4, 5);
      Stream<Integer> s = nums.stream();

      System.out.println("개수: " + s.count());
      System.out.println("최대: " + s.max(Integer::compare).orElse(0));
  }
}

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

정답 보기

변수에 담긴 스트림을 재사용한 것이 원인입니다. 두 번째 줄을 nums.stream().max(...)로 바꿔 흐름을 새로 열면 됩니다. 스트림은 일회용이라(5편) 최종 연산 한 번에 소모됩니다. 애초에 변수에 담지 않고 그때그때 여는 습관이 안전합니다.

문제 5. 빈 상자를 억지로 열었습니다

NoSuchElementException이 납니다. 조건에 맞는 값이 없을 때 "없음"이 출력되도록 고쳐 보세요.

문제 5 — Optional 열기
import java.util.List;
import java.util.Optional;

public class Main {
  public static void main(String[] args) {
      List<String> names = List.of("kim", "lee", "park");

      Optional<String> found = names.stream()
              .filter(n -> n.startsWith("z"))
              .findFirst();

      System.out.println(found.get());   // 빈 상자를 그냥 엽니다
  }
}

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

정답 보기

found.get() 대신 found.orElse("없음") 으로 바꾸면 됩니다. get()은 상자가 비어 있으면 그대로 예외를 던지므로 6편에서 쓰지 말라고 했던 바로 그 메서드입니다. Optional을 받았다면 orElse·orElseGet·ifPresent 중 하나로 "없을 때"를 항상 정해 주세요.

시즌을 닫으며 — 다음 갈림길

다섯 문제를 스스로 고쳤다면 모던 자바의 핵심 근육은 잡힌 겁니다. 이제 컬렉션을 다루는 코드에서 for문과 스트림 중 읽기 좋은 쪽을 고를 수 있는 눈이 생겼을 테니, 그것이 이 시즌의 진짜 수확입니다.

JAVA1(기초) → JAVA2(객체지향) → JAVA3(예외·컬렉션·네트워크) → JAVA4(모던 자바)까지, 언어 문법의 여정은 여기서 일단락됩니다. 다음 시즌은 방향이 바뀝니다. 콘솔을 벗어나 창을 띄우고(Swing), 웹에서 데이터를 긁어 오고(크롤링), 공공 API를 호출하는 실전 응용으로 갑니다. 지금까지 배운 람다와 스트림이 그 코드들 속에서 계속 재등장할 겁니다.

수고 많으셨습니다. 궁금한 문제나 막힌 지점은 댓글로 남겨 주세요.


JAVA4 시즌 완결. 예제는 강사 개인 GitHub 저장소의 강의 코드를 다듬은 것입니다. 다음 시즌 예고: JAVA5 — 창을 띄우는 자바.

PANCO_IT

IT 지식을 정리하는 개발자

관련 글