이 페이지의 내용
Java 튜토리얼: 일상적인 Java 문제를 해결하는 How-To 가이드
Java는 JVM에서 동작하는 정적 타입 객체 지향 언어이며, 같은 코드가 기업용 백엔드, Android 앱, 은행 시스템을 구동합니다. 대부분의 사람은 Java를 실제로 사용하는 방식 그대로 배웁니다. 구체적인 문제를 하나씩 해결해 가는 방식이죠. 이 페이지는 DelftStack에 있는 1,000개가 넘는 Java How-To 가이드의 지도입니다. 아래 가이드는 문자열 다듬기, 컴파일러 오류 해석, 배열 합산, 파일 읽기처럼 “하려는 작업"을 기준으로 그룹이 나뉘어 있고, 각 그룹의 앞부분에는 독자들이 가장 자주 묻는 질문에 답하는 엄선 가이드를 배치했습니다. 첫 Java 프로그램을 작성하는 중이라면 학습 경로에서 시작하고, 특정 오류나 작업을 안고 찾아왔다면 그에 맞는 그룹으로 바로 이동하세요.
Java 학습 경로
1,000개의 가이드를 순서대로 모두 읽을 필요는 없습니다. 확실한 경로는 문자열과 문자부터 시작하는 것입니다. 모든 프로그램이 텍스트를 다루기 때문입니다. 다음으로 배열과 리스트가 데이터를 어떻게 담는지 배우고, 날짜, 난수, 파일 같은 일상적인 유틸리티를 더한 뒤, 그다음에야 컴파일러 오류와 바인딩 같은 객체 지향 개념에 본격적으로 시간을 쓰세요. Java에서는 이 순서가 효과적입니다. 코드가 무엇을 표현하려는지를 알게 되면 컴파일러의 엄격한 오류 메시지도 읽을 수 있게 되기 때문입니다. 아래 단계를 체크리스트처럼 활용하고, 한 단계가 쉽게 느껴지면 다음으로 넘어가세요.
- 텍스트부터 시작하기. 문자열의 마지막 문자 가져오기와 문자열을 char로 변환하기를 익히세요.
char처리는 거의 모든 입문 프로그램에 등장합니다. - 핵심 데이터. 배열 합산하기와 배열 요소를 0으로 초기화하기를 배우면 반복문과 인덱스가 머릿속에서 자리를 잡습니다.
- 일상적인 작업. 오늘 날짜 출력, 난수 생성, 폴더 안의 모든 파일 읽기. 아래의 날짜 그룹과 파일 그룹이 이런 일상 작업을 다룹니다.
- 오류 고치기. 컴파일러가 코드를 거부할 때, identifier expected 가이드를 비롯한 오류 가이드가 추측이 아니라 원인을 찾는 방법을 보여줍니다.
- 한 걸음 더 나아가기. 정적 바인딩과 동적 바인딩의 차이를 확인하거나, GUI에 관심이 있다면 아래 GUI 그룹으로 이동하세요.
이 경로를 마친 뒤에는 이 페이지를 레퍼런스로 활용하세요. 아래의 모든 그룹은 독립적으로 읽을 수 있고, 각 섹션 아래의 전체 알파벳순 색인에는 엄선 목록에 담지 못한 긴 꼬리의 가이드까지 1,000개가 넘는 가이드가 모두 나열되어 있습니다.
문자열과 문자
Java의 텍스트 작업은 어색한 사실 하나에서 시작합니다. String은 객체이고 char는 기본형이며, 이 둘 사이를 오가는 지점에서 모두가 처음에는 헷갈립니다. 처음 두 가이드는 한 쌍으로 읽으세요. 같은 마지막 문자를 서로 반대 방향에서 다룹니다. 하나는 문자열의 마지막 문자를 읽는 방법을, 다른 하나는 곳곳에서 서로를 참조하며 그 문자를 제거하는 방법을 보여줍니다. 말미의 구분자나 개행 문자를 다듬을 때 실제로 필요한 것은 대개 후자입니다. 이어지는 char 가이드들은 선언과 관련된 의문을 정리합니다. char가 기본값으로 무엇을 가지는지, 왜 null이 될 수 없는지, 한 글자씩 처리해야 할 때 문자열 전체를 어떻게 char 배열로 바꾸는지를 다룹니다.
- Java에서 문자열의 마지막 문자 가져오기 — 마지막 문자를 세 가지 방법으로 읽습니다.
char가 필요하면charAt(), 한 문자짜리 문자열이면substring(), 또는 char 배열로의 변환을 사용합니다. - Java에서 문자열의 마지막 문자 제거하기 — 위 가이드의 삭제 버전입니다.
substring()이나replaceFirst()로 마지막 문자를 떨어뜨리고, Java 8 이상에서는 Commons Lang의removeEnd()와chop()도 쓸 수 있습니다. - Java에서 char 초기화하기 — 빈 값으로
char를 선언하고, 기본형에는null이 적용되지 않는 이유와 필드가 시작될 때 갖는 기본값'\u0000'을 이해합니다. - Java에서 문자열을 char로 변환하기 — 문자 하나는
charAt()으로, 전체 내용은toCharArray()로 가져오고,getBytes()가 맞는 경우와 그렇지 않은 경우를 확인합니다.
오류, 예외 및 문제 해결
Java 컴파일러 오류는 정확한 지적이지만, 그것이 어떤 가정에 대한 지적인지 알 때만 의미가 있습니다. 첫 번째 가이드는 단독 섹션을 차지합니다. 그 배경에 있는 검색어 군 — identifier expected와 그 변형들 — 은 이 사이트에서 가장 많이 검색되는 Java 문제 중 하나이면서도 그 답변들은 첫 페이지 바로 아래에 머물러 있기 때문입니다. 이 오류는 이름(변수, 메서드, 매개변수의 이름)이 나타나야 할 자리에 컴파일러가 다른 토큰을 발견했다는 뜻이며, 대개 문이 어떤 메서드 밖에 놓여 있거나 매개변수에 타입이 빠져 있을 때 발생합니다. 설치 가이드는 성격이 다릅니다. 코드는 멀쩡한데 Windows가 실행을 거부하는 경우입니다. 나머지 두 가이드는 직접 만든 클래스가 커지기 시작하면 만나게 되는 오류, 즉 잘못된 타입에 적용된 연산자와 호출한 타입에서 컴파일러가 찾지 못하는 메서드를 다룹니다.
- Java에서
<identifier> expected오류 수정하기 — 컴파일러는 이름을 기대했지만 다른 것을 발견했습니다. 매개변수 타입이나 이름 누락, 메서드 밖에 놓인 문, 잘못된 try-with-resources 선언을 진단하고, 다시 컴파일하기 전에 확인할 체크리스트를 제공합니다. - Java 설치 오류 “다음 스위치에 오류가 있습니다” 해결하기 — Windows의
.jar파일 연결을javaw.exe로 복구하고, 명령 프롬프트에서 JAR를 테스트하며, 런처 자체가 없거나 손상된 경우에만 Java를 재설치합니다. - Java에서 bad operand types 오류 수정하기 —
&,&&,==,<=에 대한bad operand type보고를 호환되지 않는 피연산자 타입과 연산자 우선순위 함정으로 나누어 사례별로 살펴봅니다. - Java에서 타입에 대해 메서드가 정의되지 않았다는 오류 — 컴파일러가 확인할 수 없는 호출입니다. 오타를 확인하고, 객체의 실제 타입을 확인하고, 메서드 시그니처를 맞추거나, 메서드가 존재하도록 상속을 고칩니다.
배열과 컬렉션
배열은 Java의 첫 번째 자료구조이자 다른 모든 컬렉션이 그 위에 세워지는 토대이므로, 이 그룹은 가장 자주 쓰게 될 두 가지 연산으로 시작합니다. 전부 합산하는 것과 전부 알려진 시작 값으로 설정하는 것입니다. 합산 가이드는 현대 Java 스타일의 투어이기도 합니다. 같은 반복문을 스트림으로 쓴 모습을 보면 언어가 얼마나 달라졌는지 알 수 있습니다. 0 초기화 가이드는 C 프로그래머들을 놀라게 하는 질문에 답합니다. Java는 이미 배열 요소를 자동으로 초기화해 주며, 명시적인 메서드들은 이미 사용 중인 배열을 재설정할 때 필요합니다. 정렬 가이드는 실무로 건너가는 다리입니다. 기본형이 아니라 날짜 같은 필드를 기준으로 객체를 정렬해야 하는 상황을 다룹니다.
- Java에서 배열의 합 구하기 — 단순한
for반복문으로int배열을 합산하거나, 스트림으로Arrays.stream(...).sum(),reduce,IntStream.of(...).sum()을 사용합니다. - Java에서 배열의 모든 요소를 0으로 초기화하기 — 반복문,
Arrays.fill(),nCopies(), 재할당,Arrays.setAll()로 배열을 재설정하는 방법과, Java의 기본 0 초기화가 이미 대신해 주는 경우를 다룹니다. - Java에서 ArrayList의 객체를 날짜순으로 정렬하기 — 사용자 정의 객체를 날짜 필드 기준으로 세 가지 방법으로 정렬합니다.
Comparable,Collections.sort(), 비교자를 사용하는list.sort()입니다.
타입 변환과 연산자
Java의 타입 시스템은 엄격합니다. 그 때문에 변환과 연산자는 입문자의 질문이 끊이지 않는 원천입니다. 가장 많이 검색되는 것은 존재하지 않는 기능에 대한 질문입니다. JavaScript나 Python에서 온 프로그래머들은 typeof를 찾고, Java의 답 — 객체에게 런타임 클래스를 묻는 것 — 에서 이 언어가 타입을 어떻게 생각하는지가 드러납니다. != 가이드는 실제 결과를 초래하는 유명한 오타를 다룹니다. 문자의 순서를 바꾸면 비교가 아니라 부정을 동반한 할당이 되어 버립니다. 음수에 대한 나머지 가이드를 읽어 보세요. Java의 %와 Math.floorMod()가 실제로 의견이 갈리는 지점입니다.
- Java에서 객체의 런타임 클래스 가져오기(
typeof문제) — Java에는typeof연산자가 없습니다.getClass()로 객체에게 런타임 클래스를 묻고, 비교에서 헷갈리기 쉬운 래퍼 클래스 경우까지 다룹니다. - Java에서
!=와=!의 차이 —!=는 두 값이 다른지를 비교합니다.=!는 연산자조차 아닙니다.a = !b에서는 부정된 불리언 값이 할당되며, 컴파일이 통과되어 사람을 속이는 오타입니다. - Java에서 나머지 연산 —
%연산자로 나머지를 계산하고, 음수 피연산자에서도 음이 아닌 결과가 필요할 때는Math.floorMod()로 전환합니다.
날짜, 난수 및 유틸리티
이 작은 그룹은 페이지 안에서 전환율이 가장 높습니다. 각 가이드가 짧고 정확한 질문에 답하기 때문입니다. 날짜 가이드들은 전환기에 있는 라이브러리의 모습을 보여줍니다. 오래된 java.util.Date와 Calendar 클래스는 여전히 기존 코드에 가득하지만, 오늘 작성해야 할 것은 java.time(LocalDate, LocalDateTime, ZonedDateTime)이며, 가이드들은 어느 것이 어느 쪽인지 표시해 둡니다. 난수 가이드는 세 가지 생성기와 각각이 적합한 경우를 다룹니다. 콘솔 지우기와 지연은 모든 명령줄 프로그램이 언젠가 필요로 하는 유틸리티로, 솔직한 주의 사항이 함께 붙습니다. Java가 의도적으로 터미널을 숨긴다는 점, 그리고 블로킹 방식의 sleep이 때로 잘못된 도구라는 점 때문입니다.
- Java에서 1부터 10 사이의 난수 생성하기 —
java.util.Random,Math.random(),ThreadLocalRandom으로 1–10(양 끝 포함) 값을 뽑고, 동시성 환경에서 무엇을 골라야 하는지 알아둡니다. - Java에서 오늘 날짜 가져오기 —
java.util.Date로 오늘 날짜를 구하거나, 시간대가 중요할 때는 최신LocalDate,LocalDateTime,ZonedDateTime을 사용합니다. - Java에서 현재 연도 가져오기 —
LocalDate,Calendar,Date,YearMonth, Joda Time으로 현재 연도를 읽습니다. 완전한 날짜부터 정수 하나까지 다룹니다. - Java에서 콘솔 지우기 — 터미널과 운영 체제가 무엇을 지원하는지 확인한 뒤, ANSI 이스케이프 시퀀스나
ProcessBuilder를 통한 OS 명령으로 터미널을 지웁니다. - Java에서 몇 초 지연시키기 —
Thread.sleep()이나TimeUnit.sleep()으로 일시停止하고, 다른 작업을 계속해야 할 때는 블로킹 대신ScheduledExecutorService로 예약합니다.
파일 입출력과 프로퍼티
Java의 파일 코드는 하나의 형태 — 찾고, 읽고, 비교하거나 설정하는 것 — 를 따르며, 이 그룹의 가이드들은 그 일상의 형태를 다룹니다. 파일을 비교하는 것에는 현대적인 답(Files.mismatch())과 알아 둘 가치가 있는 오래된 방법들이 여럿 있는데, 그것들이 “같다"는 것이 무엇을 뜻하는지 — 같은 바이트인지, 같은 행인지, 같은 길이인지 — 를 드러내기 때문입니다. 폴더 읽기는 평평한 목록에서 완전한 재귀 탐색까지 규모가 달라지며, 가이드는 디렉터리 트리의 깊이에 따라 접근법을 순서대로 정렬합니다.
- Java에서 두 파일의 내용 비교하기 —
Files.mismatch(), Apache Commons IO,Arrays.equals()를 이용해 두 파일이 바이트 단위 또는 행 단위로 같은지 테스트합니다. - Java에서 폴더의 모든 파일 읽기 —
Files클래스,newDirectoryStream(), 중첩 폴더를 위한 재귀적walkFileTree()로 디렉터리를 나열하고 읽습니다.
GUI와 JavaFX
Java의 데스크톱 이야기는 오래되었지만 지금도 활발히 검색되며, 그 원동력은 하나의 질문입니다. 버튼마다 레이아웃 코드를 손으로 쓰지 않고 창을 만들려면 어떻게 해야 할까요? 솔직한 답은, 기존 코드의 대다수는 여전히 Swing이고 새로운 툴킷은 JavaFX이며, 어느 쪽이든 비주얼 빌더를 쓰면 작업이 “코드에서 부품을 배치하는 것"에서 “캔버스 위에 배열하고 이벤트를 연결하는 것"으로 바뀐다는 것입니다. Swing 애플리케이션을 유지 보수하거나 새로 시작한다면 빌더 가이드부터 읽으세요. 이 그룹의 엄선 가이드는 현재 영어 버전만 제공되므로, 아래에서는 가이드 본문만 소개하고 다른 가이드는 아래 색인에서 찾아볼 수 있습니다.
클래스와 메서드
이 그룹은 의도적으로 선별되어 있습니다. 두 가이드가 각각 더 큰 주제의 문을 엽니다. 디컴파일은 실무적인 비상 상황에 대한 답입니다. .class 파일이나 라이브러리 JAR는 있는데 소스가 없어서 그 코드가 무엇을 하는지 알아야 할 때입니다. 바인딩은 면접과 시험이 좋아하는 개념적인 질문에 답합니다. 실제로 어떤 메서드가 실행될지를 결정하는 것이 참조 타입에서 이루어지는 컴파일 타임의 선택인지, 객체 자체에서 이루어지는 런타임의 선택인지가 핵심입니다. 바인딩 가이드는 오류 그룹과 함께 읽으세요. “메서드가 정의되지 않음"이라는 혼란의 절반은 사실 바인딩에 대한 오해입니다.
- Java 클래스 디컴파일하기 — JD-GUI, FernFlower, JD-CLI를 쓰거나 Eclipse, IntelliJ IDEA 안에서
.class파일로부터 읽을 수 있는 소스를 복원합니다. - Java에서 정적 바인딩과 동적 바인딩의 차이 — 오버로드와 정적 메서드에 대한 컴파일 타임 바인딩과 오버라이드된 메서드에 대한 런타임 바인딩을, 어떤 호출이 언제 결정되는지의 예와 함께 비교합니다.
자주 묻는 질문
Java에서 “identifier expected” 오류가 발생하는 원인은 무엇인가요?
컴파일러가 문법상 이름(변수, 메서드, 매개변수의 이름)이 필요한 자리에 도달했는데 거기서 다른 것을 발견했을 때 발생합니다. 흔한 원인은 문이 메서드 안이 아니라 클래스 본문에 직접 작성된 경우, 매개변수에 타입이 빠져 있는 경우, 중괄호 위치가 어긋나 메서드가 일찍 끝난 경우, try-with-resources의 리소스 선언이 잘못된 경우입니다. 지목된 행을 읽고, 그 바로 앞부분을 확인하세요. 각 원인의 구분과 컴파일 전 체크리스트는 identifier expected 가이드에서 순서대로 다룹니다.
Java에서 1부터 10 사이의 난수를 생성하려면 어떻게 하나요?
Random을 만들고 nextInt(10) + 1을 호출합니다. nextInt(10)은 0–9를 반환하므로, 이 이동으로 양 끝을 모두 포함하는 범위가 됩니다. 한 번만 빠르게 쓸 경우 (int) (Math.random() * 10) + 1도 같은 일을 하고, 동시성 코드에서는 ThreadLocalRandom.current().nextInt(1, 11)이 경합을 피합니다. 그 상한은 배타적이라는 점에 유의하세요. 세 가지 방법의 비교와 범위 설명은 난수 가이드에 있습니다.
Java에도 typeof가 있나요?
없습니다. Java에는 typeof 연산자가 없습니다. 가장 가까운 것은 객체의 런타임 클래스를 반환하는 obj.getClass()와, 객체가 어떤 타입이나 그 서브타입에 속하는지 테스트하는 instanceof입니다. 어느 것이 필요한지는 질문에 따라 다릅니다. getClass()는 “이것은 정확히 무엇인가"에 답하고, instanceof는 “이것을 이 타입으로 취급할 수 있는가"에 답합니다. 래퍼 객체에는 주의할 점이 있습니다. Integer는 Integer.class를 보고하고, 절대로 int가 되지 않습니다. 래퍼의 경우까지 포함한 설명은 런타임 클래스 가이드에 있습니다.
Java에서 실행을 몇 초간 지연시키려면 어떻게 하나요?
Thread.sleep(3000)을 호출하면 현재 스레드가 3초간 멈춥니다. 선언된 InterruptedException의 처리(잡거나 전파시키거나)도 필요합니다. TimeUnit.SECONDS.sleep(3)은 같은 지연을 단위 이름으로 표현한 것으로, 리뷰되는 코드에서 더 읽기 좋습니다. 스레드에 다른 일이 있다면 아예 블로킹하지 마세요. 지연될 단계는 대신 ScheduledExecutorService로 예약하세요. 블로킹 호출과 예약 방식 모두 지연 가이드에서 다룹니다.
Java 설치가 “errors in the following switches"로 실패하는 이유는 무엇인가요?
이 Windows 메시지는 보통 .jar 파일이 이해할 수 없는 스위치와 함께 Java 설치 프로그램이나 런처에 전달되었다는 뜻입니다. 가장 흔한 경우는 .jar 파일 연결이 잘못된 실행 파일을 가리키고 있어, 프로그램을 더블클릭하면 설치 형식의 오류가 발생하는 것입니다. 연결을 javaw.exe로 되돌리고, 같은 JAR를 명령 프롬프트에서 테스트해 연결 문제인지 다운로드 손상인지 구분하세요. Java 재설치가 도움이 되는 것은 런처 자체가 없거나 손상된 경우뿐입니다. 확인 순서는 설치 스위치 가이드에서 순서대로 다룹니다.
다음 단계
위의 그룹 중 두 그룹은 전용 서브 가이드로 성장하고 있습니다. 절박한 문제를 안고 찾아오는 독자들이 도착하고, identifier expected 검색어 군이 이미 독립된 주제처럼 움직이는 “오류, 예외 및 문제 해결"과, 이 컬렉션에서 가장 많이 클릭되는 그룹인 “문자열과 문자"입니다. 그것들이 공개되기 전까지는 위의 섹션들이 입구입니다. 동적 타입 언어나 다른 생태계로 작업이 옮겨 간다면, 같은 “문제에서 출발하는” 구성의 Python How-To 가이드나 C# How-To 가이드로 이어 가세요.