개념
java.lang은 자바에서 가장 기본이 되는 클래스들이 들어 있는 패키지다.
여기서package는 서로 관련 있는 클래스들을 묶어 놓은 폴더 같은 단위라고 이해하면 된다.
클래스 이름이 같아도 어떤 패키지에 들어 있느냐에 따라 실제 클래스가 달라질 수 있다.
예를 들어 우리가 그냥
String이라고 쓰는 클래스의 실제 이름은java.lang.String이다.
System.out.println()에서 쓰는System의 실제 이름도java.lang.System이다.
앞에서 정리한Object역시 실제 이름은java.lang.Object다.
그런데 우리는
String,System,Object를 사용할 때 보통import java.lang.String;처럼 적지 않는다.
그 이유는java.lang패키지가 자바 프로그램에서 너무 기본적으로 쓰이기 때문에 자동으로 준비되는 패키지이기 때문이다.
java.lang은 자바가 기본으로 준비해 주는 핵심 클래스 묶음이다.
그래서String,System,Object같은 클래스는 따로import하지 않아도 바로 사용할 수 있다.
반대로
Scanner는java.lang에 들어 있는 클래스가 아니다.
Scanner의 실제 이름은java.util.Scanner다.
그래서Scanner를 사용할 때는 보통import java.util.Scanner;를 적거나, 코드에서java.util.Scanner처럼 전체 이름을 직접 써야 한다.
핵심 특징
package는 관련 있는 클래스를 묶어 놓은 단위다.String의 실제 이름은java.lang.String이다.System의 실제 이름은java.lang.System이다.Object의 실제 이름은java.lang.Object다.java.lang패키지의 클래스는 따로import하지 않아도 된다.Scanner는java.lang이 아니라java.util패키지에 있으므로import가 필요하다.이 흐름을 먼저 잡으면 뒤에서
String,Scanner,main()을 볼 때 왜 어떤 클래스는 바로 쓰고, 어떤 클래스는import해야 하는지 덜 헷갈린다.
개념
String은 자바에서 문자열을 다루는 가장 기본적인 클래스다.
정확한 클래스 이름은java.lang.String이지만,java.lang패키지는 자동으로 준비되므로 보통은String이라고만 쓴다.
프로그램을 만들다 보면 글자, 단어, 문장, 파일 이름, 아이디, 검색어처럼
문자열을 다루는 일이 아주 자주 나온다.
그래서String은 단순히 “문자 여러 개를 담는 클래스”가 아니라,
문자열을 읽고, 자르고, 찾고, 바꾸고, 나누는 기본 도구라고 이해하는 것이 좋다.
그리고
String을 이해할 때 가장 먼저 잡아야 하는 특징이 하나 있다.
String은 한 번 만들어지면 그 내용이 바뀌지 않는 객체다.
겉으로 보기에는 문자열을 바꾸는 것처럼 보여도,
실제로는 원래 문자열을 수정하는 것이 아니라 바뀐 결과를 가진 새로운 문자열을 만들어서 돌려주는 방식으로 동작한다.
예를 들어
toUpperCase(),replace(),substring()같은 메서드는
원래 문자열을 직접 고치는 것이 아니라,
가공된 결과를 새 문자열로 돌려준다.
이 점을 이해해야String메서드들이 왜 그렇게 동작하는지 헷갈리지 않는다.
이번 예제는 문자열 메서드를 그냥 하나씩 외우는 용도가 아니다.
문자열 전체를 읽고 → 일부를 꺼내 보고 → 필요한 부분을 잘라 보고 → 위치를 찾고 → 바꾸고 → 배열이나 문자 단위로 풀어 보는 흐름까지 한 번에 보여준다.
즉, 문자열을 점점 더 세밀하게 다루는 흐름으로 보면 이해가 쉬워진다.
핵심 특징
String은 문자열을 다루는 가장 기본적인 클래스다.String은 한 번 만들어지면 내용을 직접 바꿀 수 없다.length()는 문자열 길이를 구한다.charAt()은 특정 위치의 문자 하나를 꺼낸다.substring()은 문자열 일부를 잘라낸다.indexOf()와lastIndexOf()는 원하는 문자의 위치를 찾는다.replace()는 바뀐 결과를 새 문자열로 돌려준다.repeat()는 같은 문자열을 여러 번 반복한다.split()은 문자열을 기준에 따라 나누어 배열로 만든다.toCharArray()는 문자열 전체를 문자 배열로 바꾼다.- 문자열을 계속 수정하거나 이어 붙이는 작업이 많다면
StringBuffer나StringBuilder를 함께 생각해야 한다.
예제별 역할
StringTest: 문자열 메서드를 한 번에 확인하는 기본 예제- 앞부분 출력 : 문자열 길이, 문자 접근, 대문자 변환 확인
- 중간 부분 : 잘라내기, 위치 찾기, 치환, 반복 확인
- 뒷부분 :
split()으로 배열 만들기와toCharArray()로 문자 배열 만들기 확인
코드 예제
예제:
StringTest// StringTest.java package day10; public class StringTest { public static void main(String[] args) { // 1. 문자열 길이를 확인함 System.out.println("1".length()); // 문자 1개이므로 1 System.out.println("가나다".length()); // 문자 3개이므로 3 // 2. 특정 위치의 문자 하나를 꺼냄 // 인덱스는 0부터 시작하므로 1번 위치는 'b' System.out.println("abc".charAt(1)); // b // 3. 문자열을 대문자로 바꾼 결과를 확인함 // 원본을 직접 바꾸는 것이 아니라 새 문자열 결과를 돌려줌 System.out.println("abc".toUpperCase()); // ABC // 4. 잘라내기와 위치 찾기, 문자 바꾸기용 문자열 준비 String str1 = "ABCDEFGHIJ"; String str2 = "abcdefgfhij"; // 5. 4번 위치부터 끝까지 잘라냄 System.out.println(str1.substring(4)); // EFGHIJ // 6. 0번 이상 3번 미만까지 잘라냄 System.out.println(str1.substring(0, 3)); // ABC // 7. 앞에서부터 처음 나오는 'f'의 위치를 찾음 System.out.println(str2.indexOf("f")); // 5 // 8. 뒤에서부터 마지막 'f'의 위치를 찾음 System.out.println(str2.lastIndexOf("f")); // 7 // 9. 'h'를 'H'로 바꾼 새 문자열 결과를 확인함 // str2 자체가 직접 바뀌는 것은 아님 System.out.println(str2.replace('h', 'H')); // abcdefgfHij // 10. 문자열을 여러 번 반복한 결과를 확인함 System.out.println("abc".repeat(5)); // abcabcabcabcabc System.out.println("@".repeat(3)); // @@@ // 11. 긴 문자열을 공백 기준으로 잘라 배열로 만듦 String str3 = "java jdbc html5 css javascript servlet jsp ajax"; String[] ary = str3.split(" "); // 12. 잘린 문자열 배열의 각 요소를 하나씩 출력함 for (int i = 0; i < ary.length; i++) { System.out.println(ary[i]); } // 13. 문자열 전체를 문자 배열로 변환함 char ch[] = str3.toCharArray(); // 14. 문자열 길이와 문자 배열 길이가 같은지 확인함 // 공백도 길이에 포함되므로 둘 다 47이 나옴 System.out.println(str3.length() + " ---- " + ch.length); // 15. 문자 배열의 각 문자를 하나씩 출력함 for (int i = 0; i < ch.length; i++) { System.out.print(ch[i] + " "); } } }// 출력결과 // 1 // 3 // b // ABC // EFGHIJ // ABC // 5 // 7 // abcdefgfHij // abcabcabcabcabc // @@@ // java // jdbc // html5 // css // javascript // servlet // jsp // ajax // 47 ---- 47 // j a v a j d b c h t m l 5 c s s j a v a s c r i p t s e r v l e t j s p a j a x이 예제는 문자열 메서드를 무작정 나열하는 코드가 아니다.
앞에서는 문자열을 그대로 읽는 방법을 보고,
중간에서는 문자열을 가공하는 방법을 보고,
뒤에서는 문자열을 배열과 문자 단위로 풀어 보는 방법까지 이어진다.
즉, 문자열을 다루는 기본 흐름을 한 번에 묶어 놓은 예제라고 보면 된다.
1. 문자열 길이와 문자 꺼내기
문자열을 다룰 때 가장 먼저 필요한 것은
“문자열이 얼마나 긴가”,
“몇 번째 문자가 무엇인가”를 확인하는 일이다.여기서 쓰는 메서드가
length()와charAt()이다.System.out.println("1".length()); // 1 System.out.println("가나다".length()); // 3 System.out.println("abc".charAt(1)); // b
length()는 문자열의 길이를 반환한다.
"1"은 문자 하나이므로1,
"가나다"는 세 글자이므로3이 나온다.
charAt(1)은"abc"에서 인덱스가1인 위치의 문자를 꺼낸다.
여기서 중요한 것은 문자열의 위치 번호는 0부터 시작한다는 점이다.즉,
a→ 0번b→ 1번c→ 2번이므로 결과는
b가 된다.또 하나 같이 기억하면 좋은 점은
charAt()이 돌려주는 값은 문자열이 아니라 문자 하나(char)라는 것이다.
즉,"b"같은 문자열 조각을 꺼내는 느낌이 아니라
문자 하나를 집어 오는 메서드라고 이해하면 된다.이 부분은 아주 중요하다.
문자열도 배열처럼 첫 번째가 1번이 아니라 0번부터 시작한다는 감각을 여기서 확실히 잡아야 한다.
2. 문자열을 바꾸는 것처럼 보여도 원본은 안 바뀐다
다음 코드는 문자열을 가공하는 메서드가 어떤 느낌인지 보여준다.
System.out.println("abc".toUpperCase()); // ABC
toUpperCase()는 소문자를 대문자로 바꾼 결과를 돌려준다.
여기서 중요한 점은"abc"자체가 직접 바뀌는 것이 아니라,
"ABC"라는 새로운 문자열 결과를 돌려준다는 것이다.
이 감각은 뒤의
replace()에서도 그대로 이어진다.즉,
String에서는
“문자열을 바꾼다”보다
“바뀐 결과를 새로 받는다”
라고 이해하는 편이 맞다.예를 들어
String s = "abc"; s.toUpperCase();이렇게만 쓰면
s자체가"ABC"로 바뀌는 것이 아니다.
바뀐 결과를 계속 쓰고 싶다면 그 결과를 다시 변수에 받아야 한다.
3. 문자열 일부 자르기와 위치 찾기
문자열을 다루다 보면 전체 문자열이 아니라
필요한 부분만 꺼내야 할 때가 많다.
이때 많이 쓰는 것이substring()이다.String str1 = "ABCDEFGHIJ"; System.out.println(str1.substring(4)); // EFGHIJ System.out.println(str1.substring(0, 3)); // ABC
substring(4)는 인덱스4부터 끝까지 잘라낸다.
A B C D E F G H I J에서E가 4번 위치이므로 결과는EFGHIJ다.
substring(0, 3)은0부터3전까지 자른다.
여기서 초보자가 가장 많이 헷갈리는 부분이 나온다.
substring(0, 3)은
0부터3까지가 아니라
0 이상 3 미만이다.그래서 잘려 나오는 문자는
- 0번 →
A- 1번 →
B- 2번 →
C까지만 포함되어 결과가
ABC가 된다.문자열 안에서 어떤 문자가 어디 있는지 찾고 싶을 때는
indexOf()와lastIndexOf()를 쓴다.String str2 = "abcdefgfhij"; System.out.println(str2.indexOf("f")); // 5 System.out.println(str2.lastIndexOf("f")); // 7
indexOf("f")는 앞에서부터 찾았을 때 처음 나오는f의 위치를 돌려준다.
lastIndexOf("f")는 뒤쪽 기준으로 마지막f의 위치를 돌려준다.즉, 같은 문자가 여러 번 들어 있을 때
“처음 나온 위치”와 “마지막 나온 위치”를 각각 구할 수 있는 것이다.이 메서드는 검색, 포함 여부 확인, 특정 위치 기준 분리 같은 작업에서 자주 쓰인다.
4. 문자열 바꾸기와 반복하기
문자열 안의 일부를 바꾸고 싶을 때는
replace()를 쓴다.System.out.println(str2.replace('h', 'H')); // abcdefgfHij여기서는
h를H로 바꿨다.
결과는abcdefgfHij가 된다.여기서도 중요한 점은 같다.
replace()는 원래 문자열str2를 직접 고치는 것이 아니라,
바뀐 결과 문자열을 새로 돌려준다.그래서 아래처럼 생각해야 한다.
- 원래 문자열 : 그대로 있음
replace()결과 : 바뀐 새 문자열문자열을 반복해서 붙이고 싶을 때는
repeat()를 쓴다.System.out.println("abc".repeat(5)); // abcabcabcabcabc System.out.println("@".repeat(3)); // @@@
repeat(5)는 같은 문자열을 다섯 번 이어 붙인다.
이 메서드는JDK 11부터 사용할 수 있다.
즉, 직접 반복문을 돌리지 않아도 같은 문자열을 쉽게 반복해서 만들 수 있다.이런 메서드는 구분선 만들기, 특정 패턴 반복, 간단한 출력 꾸미기에서 자주 쓸 수 있다.
5. split()으로 문자열을 배열로 나누기
문자열 전체를 한 덩어리로 다루는 것도 중요하지만,
필요할 때는 여러 조각으로 나누어서 다뤄야 한다.String str3 = "java jdbc html5 css javascript servlet jsp ajax"; String[] ary = str3.split(" ");
split(" ")은 공백 하나를 기준으로 문자열을 잘라서 배열로 만든다.
공백이 여러 개 들어올 수 있는 입력이라면split(" +")처럼 하나 이상의 공백을 기준으로 자르는 방식도 함께 생각할 수 있다.
여기서+는 바로 앞의 공백이 하나 이상 반복될 수 있다는 뜻의 정규식 표현이다.즉, 원래는 하나의 긴 문자열이었지만
잘라 놓고 나면 이렇게 된다.
ary[0]→javaary[1]→jdbcary[2]→html5- ...
그래서 아래 반복문으로 배열의 각 요소를 하나씩 출력할 수 있다.
for (int i = 0; i < ary.length; i++) { System.out.println(ary[i]); }이 부분이 중요한 이유는
문자열을 읽는 단계에서 끝나지 않고,
문자열을 여러 조각으로 나누어 프로그램에서 다시 활용하는 단계로 넘어가기 때문이다.예를 들어 이름 목록, 메뉴 목록, 명령어 입력처럼
구분자를 기준으로 잘라야 하는 경우에 많이 쓰인다.여기서 한 가지 더 같이 보면 좋은 점은
split()의 결과가 문자열 하나가 아니라 문자열 배열이라는 것이다.
그래서 결과를 다시 다룰 때는 배열처럼 인덱스로 접근하거나 반복문으로 꺼내 써야 한다.
6. toCharArray()로 문자 단위로 풀어 보기
문자열을 단어 단위보다 더 작게,
즉 문자 하나하나 단위로 다루고 싶을 때는toCharArray()를 사용한다.char ch[] = str3.toCharArray(); System.out.println(str3.length() + " ---- " + ch.length);
toCharArray()는 문자열 전체를char[]배열로 바꿔 준다.
그래서 이제 문자열이 아니라 문자 배열처럼 다룰 수 있다.예제에서
str3.length()와ch.length를 같이 출력했을 때 둘 다47이 나온다.
이것은 문자열 전체 길이와, 그것을 문자 배열로 바꿨을 때의 문자 개수가 같다는 뜻이다.
여기서 길이에는 알파벳만 들어가는 것이 아니라 공백도 함께 포함된다는 점을 같이 봐야 한다.그리고 아래 반복문으로 문자 하나씩 출력할 수 있다.
for (int i = 0; i < ch.length; i++) { System.out.print(ch[i] + " "); }이렇게 하면 문자열이
단어 덩어리가 아니라 문자 하나하나의 배열로 보이기 시작한다.이 단계가 중요한 이유는
암호 처리, 문자 검사, 알파벳 개수 세기처럼
문자 단위 작업으로 넘어갈 때toCharArray()가 유용하기 때문이다.
7. StringBuffer와 StringBuilder는 왜 같이 알아야 할까
여기까지 보면 자연스럽게 이런 생각이 든다.
“문자열을 자꾸 바꾸고 이어 붙여야 하면 어떻게 하지?”
“String은 안 바뀐다면서, 계속 수정하는 작업은 뭐로 하지?”이때 같이 알아두면 좋은 것이
StringBuffer와StringBuilder다.
String은 불변 객체라서 문자열을 바꾸는 것처럼 보여도 매번 새 문자열 결과를 만든다.
반면StringBuffer와StringBuilder는 가변 객체라서 내부 내용을 직접 바꾸면서 문자열을 편집할 수 있다.
즉, 문자열을 계속 수정하고 이어 붙이는 작업에는 이 둘이 더 잘 맞는다.예를 들어
append(),delete(),insert(),replace()같은 메서드를 써서
하나의 버퍼 안에서 문자열을 계속 바꿔 나갈 수 있다.
이 점이String과 가장 큰 차이다.String은 새 결과를 돌려주고,StringBuffer와StringBuilder는 자기 내용을 바꾸면서 이어 간다.둘의 차이도 같이 정리해 두면 좋다.
StringBuffer: 동기화가 되어 있어서 멀티쓰레드 환경에서 더 안전하다.StringBuilder: 동기화가 빠져 있어서 보통 더 가볍고 빠르다.즉, 지금 단계에서는 이렇게 기억하면 충분하다.
- 읽기, 자르기, 찾기, 비교 중심이면
String- 계속 수정하고 이어 붙이기가 많으면
StringBuffer또는StringBuilder그리고 초보자 기준에서는
“둘 다 문자열 편집용 클래스인데, 보통 단일 흐름에서는StringBuilder를 더 많이 떠올리면 된다”
정도까지 잡아두면 충분하다.이번
StringTest예제 자체는String메서드를 익히는 기본 예제이지만,
문자열을 다루는 전체 그림에서는StringBuffer,StringBuilder까지 같이 알아야
왜String이 불변 객체인지, 왜 편집용 클래스가 따로 필요한지 더 잘 이해된다.
헷갈리기 쉬운 부분
1. String은 한 번 만들면 직접 바뀌지 않는다
toUpperCase(),replace(),substring()같은 메서드를 보면
원래 문자열이 바뀐 것처럼 느껴질 수 있다.
하지만String은 내용을 직접 바꾸지 않고,
바뀐 결과를 가진 새 문자열을 돌려주는 방식으로 동작한다.2.
charAt()과substring()은 위치가 0부터 시작한다문자열 위치는 배열처럼
0부터 시작한다.
그래서charAt(1)은 두 번째 문자이고,
substring(0, 3)은0부터3전까지라는 뜻이다.3.
substring(0, 3)은 3번까지가 아니다초보자가 가장 많이 실수하는 부분이다.
끝 위치는 포함되지 않는다.
그래서 결과는ABC이지ABCD가 아니다.4. 문자열 비교는 == 가 아니라 equals()를 쓴다
문자열은 내용이 같아도 서로 다른 객체일 수 있다.
그래서 문자열 비교는==보다equals()를 쓰는 것이 맞다.5.
split()결과는 문자열이 아니라 배열이다
split()을 하면 결과가String하나가 아니라String[]배열이 된다.
그래서 잘린 결과를 하나씩 꺼내 쓰려면 배열처럼 다뤄야 한다.6.
toCharArray()결과는 문자 배열이다
toCharArray()를 호출하면 문자열이 문자 배열로 바뀐다.
즉,String이 아니라char[]가 된다.
그래서 이후에는 배열처럼 반복문으로 접근하는 흐름으로 읽어야 한다.7. 문자열을 많이 수정하는데도 무조건 String만 쓰는 것은 비효율적일 수 있다
문자열을 계속 이어 붙이고, 중간을 바꾸고, 지우는 작업이 많다면
StringBuffer나StringBuilder가 더 자연스럽다.
String은 편집용 클래스가 아니라 기본 문자열 클래스라는 점을 같이 기억해야 한다.
참고
String은 단순히 글자를 담는 클래스가 아니라,
문자열을 필요한 형태로 가공하기 위한 기본 도구다.처음에는 메서드 이름이 많아 보여서 복잡해 보일 수 있다.
하지만 흐름으로 보면 생각보다 단순하다.
- 문자열 길이와 문자 확인
- 문자열 일부 자르기
- 원하는 문자 위치 찾기
- 문자열 바꾸기와 반복하기
- 배열로 나누기
- 문자 단위로 풀어 보기
- 많이 수정할 때는
StringBuffer,StringBuilder까지 같이 보기즉,
String클래스는
문자열을 점점 더 세밀하게 다루기 위한 기본 도구이고,
StringBuffer,StringBuilder는
문자열을 계속 편집해야 할 때 같이 떠올려야 하는 보조 도구라고 이해하면 된다.
개념
프로그램은 화면에 결과를 출력만 하는 것이 아니라,
사용자가 값을 입력하면 그 값을 받아서 처리해야 할 때가 많다.
예를 들어 이름을 입력받거나, 두 수를 입력받아 계산하거나,
여러 개의 단어를 나누어 받는 작업이 모두 여기에 해당한다.
자바에서 이런 입력 작업을 쉽게 할 때 자주 사용하는 클래스가
Scanner다.
Scanner는java.util.Scanner가 정확한 이름이고, 키보드로 입력한 값을 읽어서 프로그램 안으로 가져오는 도구라고 이해하면 된다.
즉,
Scanner는 단순히 “입력받는 클래스”가 아니라
입력된 값을 어떤 단위로 끊어서 받을지 정하는 도구라고 보는 것이 중요하다.왜냐하면
Scanner는
- 공백 단위로 받을 수도 있고
- 한 줄 전체를 받을 수도 있고
- 숫자로 바로 받을 수도 있기 때문이다.
그래서
Scanner를 공부할 때는
메서드 이름만 외우기보다
입력이 어디에서 끊기는지를 먼저 이해하는 것이 훨씬 중요하다.
핵심 특징
Scanner는 키보드 입력을 읽어 오는 클래스다.next()는 공백을 기준으로 끊어서 읽는다.nextLine()은 한 줄 전체를 읽는다.nextInt()는 정수를 바로 읽는다.nextDouble()은 실수를 바로 읽는다.- 입력 방식이 다르면 결과도 달라진다.
next()뒤에nextLine()을 바로 쓰면 입력 버퍼 문제를 주의해야 한다.
예제별 역할
ScannerTest1:next()로 공백 단위 입력 받기ScannerTest2:nextLine()으로 한 줄씩 입력 받기ScannerTest3: 숫자를 입력받아 계산하기ScannerTest4:next()와nextLine()을 함께 쓸 때 버퍼 처리가 왜 필요한지 확인하기
1. Scanner는 어떻게 준비할까
Scanner를 쓰려면 먼저 객체를 하나 만들어야 한다.Scanner sc = new Scanner(System.in);여기서
System.in은 키보드 입력을 뜻한다.
즉, 이 코드는
“키보드로 들어오는 값을 읽을 준비를 한다”
라고 보면 된다.보통은 파일 맨 위에
import java.util.Scanner;를 적은 다음
Scanner sc = new Scanner(System.in);처럼 쓴다.
반대로ScannerTest1처럼java.util.Scanner sc = new java.util.Scanner(System.in);이라고 쓰면
import없이도 사용할 수 있다.
즉, 둘은 방식만 다를 뿐 결국 같은Scanner클래스를 쓰는 것이다.
Scanner를 만들고 나면 그다음부터는
next(),nextLine(),nextInt(),nextDouble()같은 메서드로
입력값을 원하는 방식으로 읽을 수 있다.그리고 입력 작업이 끝나면 마지막에
sc.close();처럼 닫아 주는 습관도 같이 잡는 것이 좋다.
2. next()는 어떻게 입력을 끊어서 받을까
next()는Scanner에서 가장 먼저 이해해야 할 입력 방식이다.
next()는 공백을 기준으로 입력을 끊어서 읽는다.여기서 공백은 단순히 스페이스만 뜻하는 것이 아니다.
띄어쓰기, 탭, 엔터처럼 입력 사이를 나누는 구분을 모두 공백처럼 본다고 이해하면 된다.예제:
ScannerTest1// ScannerTest1.java package day6; public class ScannerTest1 { public static void main(String[] args) { System.out.print("입력 : "); // 1. 키보드 입력을 받을 Scanner 객체를 생성함 java.util.Scanner sc = new java.util.Scanner(System.in); String a, b, c, d; // 2. next()는 공백 기준으로 문자열을 하나씩 읽음 a = sc.next(); // 첫 번째 단어 입력 b = sc.next(); // 두 번째 단어 입력 c = sc.next(); // 세 번째 단어 입력 d = sc.next(); // 네 번째 단어 입력 // 3. 입력된 단어들을 순서대로 출력함 System.out.println("a = [" + a + "]"); System.out.println("b = [" + b + "]"); System.out.println("c = [" + c + "]"); System.out.println("d = [" + d + "]"); // 4. 입력 작업이 끝났으므로 Scanner를 닫음 sc.close(); } }예를 들어 사용자가 이렇게 입력했다고 해 보자.
// 화면 흐름 // 입력 : java jdbc html css // a = [java] // b = [jdbc] // c = [html] // d = [css]그러면
next()는 이 입력을 공백 기준으로 끊어서 읽는다.
- 첫 번째
next()→java- 두 번째
next()→jdbc- 세 번째
next()→html- 네 번째
next()→css즉,
next()는 “한 단어씩 읽는다”라고 이해하면 된다.이 방식은 단어 목록, 아이디와 비밀번호처럼
공백 없이 나뉘는 짧은 입력을 받을 때 편하다.다만 문장 전체처럼 공백이 포함된 값을 한 번에 받고 싶을 때는 맞지 않는다.
왜냐하면 중간 공백에서 끊겨 버리기 때문이다.
3. nextLine()은 왜 결과가 다를까
nextLine()은next()와 완전히 다른 방식으로 입력을 읽는다.
nextLine()은 엔터를 칠 때까지 한 줄 전체를 읽는다.즉, 중간에 공백이 있어도 거기서 끊지 않고
줄 전체를 하나의 문자열로 받아온다.예제:
ScannerTest2// ScannerTest2.java package day6; import java.util.Scanner; public class ScannerTest2 { public static void main(String[] args) { System.out.print("입력 : "); // 1. 키보드 입력을 받을 Scanner 객체를 생성함 Scanner sc = new Scanner(System.in); String a, b, c, d; // 2. nextLine()은 엔터를 칠 때까지 한 줄 전체를 읽음 a = sc.nextLine(); // 첫 번째 줄 입력 b = sc.nextLine(); // 두 번째 줄 입력 c = sc.nextLine(); // 세 번째 줄 입력 d = sc.nextLine(); // 네 번째 줄 입력 // 3. 입력된 각 줄을 그대로 출력함 System.out.println("a = [" + a + "]"); System.out.println("b = [" + b + "]"); System.out.println("c = [" + c + "]"); System.out.println("d = [" + d + "]"); // 4. 입력 작업이 끝났으므로 Scanner를 닫음 sc.close(); } }예를 들어 사용자가 입력을 이렇게 했다고 하자.
// 화면 흐름 // 입력 : java jdbc // html css // javascript servlet // jsp ajax // a = [java jdbc] // b = [html css] // c = [javascript servlet] // d = [jsp ajax]그러면
nextLine()은 각 줄을 통째로 읽는다.
- 첫 번째
nextLine()→java jdbc- 두 번째
nextLine()→html css- 세 번째
nextLine()→javascript servlet- 네 번째
nextLine()→jsp ajax즉,
nextLine()은 한 줄 전체를 읽는 메서드다.그래서 문장, 주소, 공백이 들어 있는 설명처럼
띄어쓰기를 포함해서 받고 싶은 입력에는nextLine()이 더 잘 맞는다.
4. next()와 nextLine() 차이는 어디서 끊기느냐이다
초보자가 가장 많이 헷갈리는 이유는
next()와nextLine()이 둘 다 “문자열을 입력받는다”는 공통점이 있기 때문이다.하지만 둘의 차이는 아주 분명하다.
next()→ 공백에서 끊는다.nextLine()→ 엔터를 칠 때까지 한 줄을 통째로 받는다.즉, 차이는 자료형이 아니라
입력을 어디에서 끊는가에 있다.이 차이만 확실히 잡으면
Scanner의 절반은 이해한 것이라고 봐도 된다.
5. 숫자를 입력받을 때는 어떻게 할까
Scanner는 문자열만 입력받는 도구가 아니다.
숫자도 바로 읽어 올 수 있다.이때 자주 쓰는 메서드가
nextInt()와nextDouble()이다.예제:
ScannerTest3// ScannerTest3.java package day6; import java.util.Scanner; public class ScannerTest3 { public static void main(String[] args) { // 1. 키보드 입력을 받을 Scanner 객체를 생성함 Scanner sc = new Scanner(System.in); System.out.print("두 개의 숫자(정수)를 입력해 주세요 : "); // 2. nextInt()는 입력값을 정수로 읽어 옴 int number1 = sc.nextInt(); // 첫 번째 정수 입력 int number2 = sc.nextInt(); // 두 번째 정수 입력 // 3. 입력한 두 정수의 합을 출력함 System.out.printf("합 : %d%n", number1 + number2); System.out.print("두 개의 숫자(실수)를 입력해 주세요 : "); // 4. nextDouble()은 입력값을 실수로 읽어 옴 double number3 = sc.nextDouble(); // 첫 번째 실수 입력 double number4 = sc.nextDouble(); // 두 번째 실수 입력 // 5. 입력한 두 실수의 합을 소수 둘째 자리까지 출력함 System.out.printf("합 : %.2f%n", number3 + number4); // 6. 입력 작업이 끝났으므로 Scanner를 닫음 sc.close(); } }이 코드는 먼저 정수 두 개를 입력받고 합을 구한 뒤,
다음으로 실수 두 개를 입력받고 합을 구한다.예를 들어 이렇게 입력하면
// 화면 흐름 // 두 개의 숫자(정수)를 입력해 주세요 : 10 20 // 합 : 30 // 두 개의 숫자(실수)를 입력해 주세요 : 1.5 2.3 // 합 : 3.80
nextInt()는 정수를 바로int로 읽고,
nextDouble()은 실수를 바로double로 읽는다.그래서 숫자를 계산에 바로 써야 할 때 편하다.
다만 여기서도 입력은 공백을 기준으로 구분된다.
즉, 숫자 두 개를 한 줄에 입력하든,
엔터로 줄을 바꾸어 입력하든
Scanner는 공백 기준으로 숫자를 차례대로 읽어 간다고 보면 된다.또 하나 주의할 점은
nextInt()나nextDouble()은 입력값이 숫자 형식이 아닐 때 에러가 날 수 있다는 것이다.
즉, 정수를 기대했는데 글자를 입력하면 정상적으로 읽지 못한다.
그래서 숫자 입력은 입력 형식이 맞아야 한다는 점도 같이 기억해야 한다.
6. next() 다음에 nextLine()이 왜 헷갈릴까
Scanner를 쓰면서 가장 많이 막히는 부분이 바로 이것이다.
next()나nextInt()를 쓴 다음에 바로nextLine()을 쓰면
생각했던 것과 다르게nextLine()이 빈 문자열처럼 동작하는 경우가 있다.이건
next()가 입력값만 읽고,
줄 끝의 엔터 문자까지는 그대로 남겨 두기 때문이다.그래서 바로 다음
nextLine()은
남아 있던 엔터를 읽고 끝나 버릴 수 있다.예제:
ScannerTest4// ScannerTest4.java package day6; import java.util.Scanner; public class ScannerTest4 { public static void main(String[] args) { // 1. 키보드 입력을 받을 Scanner 객체를 생성함 Scanner sc = new Scanner(System.in); System.out.printf("데이터를 입력하세요 : "); // 2. next()는 공백 기준으로 단어를 하나씩 읽음 String str1 = sc.next(); // 첫 번째 단어 입력 String str2 = sc.next(); // 두 번째 단어 입력 // 3. 앞에서 next()를 쓰고 남아 있는 엔터를 한 번 처리함 sc.nextLine(); // 입력 버퍼에 남아 있는 개행문자를 비움 // 4. 이제 nextLine()으로 한 줄 전체를 읽음 String line1 = sc.nextLine(); // 다음 줄 전체 입력 String line2 = sc.nextLine(); // 그다음 줄 전체 입력 // 5. 입력된 단어 2개와 줄 입력 2개를 모두 출력함 System.out.printf("[%s] [%s] [%s] [%s]", str1, str2, line1, line2); // 6. 입력 작업이 끝났으므로 Scanner를 닫음 sc.close(); } }이 코드의 핵심은 이 줄이다.
sc.nextLine();이 줄은 실제 내용 입력용이 아니라,
앞에서next()를 쓰고 남아 있는 엔터를 한 번 처리해 주는 역할을 한다.즉, 흔히 말하는 입력 버퍼 정리를 하는 것이다.
예를 들어 사용자가 이렇게 입력했다고 하자.
// 화면 흐름 // 데이터를 입력하세요 : java jdbc // html css // javascript servlet // [java] [jdbc] [html css] [javascript servlet]그러면 동작 흐름은 이렇게 된다.
str1 = sc.next();→javastr2 = sc.next();→jdbcsc.nextLine();→ 첫 줄 끝에 남아 있던 엔터 처리line1 = sc.nextLine();→html cssline2 = sc.nextLine();→javascript servlet즉,
next()와nextLine()을 섞어 쓸 때는
중간에 남아 있는 엔터를 어떻게 처리할지를 꼭 생각해야 한다.이 부분은 초보자가 정말 자주 실수한다.
그래서next()뒤의nextLine()이 이상하게 동작하면
대부분은 버퍼에 남은 엔터 문제부터 먼저 떠올리는 것이 좋다.
7. Scanner는 결국 입력을 어디서 끊을지 정하는 도구다
Scanner를 처음 배우면 메서드가 많아 보여서 복잡해 보일 수 있다.
하지만 핵심은 생각보다 단순하다.
next()→ 공백 단위nextLine()→ 한 줄 단위nextInt()→ 정수 단위nextDouble()→ 실수 단위즉,
Scanner는
입력값을 어떤 형태로,
어디에서 끊어서,
어떤 타입으로 받아올지 정하는 도구라고 이해하면 된다.이 흐름만 잡히면 나중에 입력 관련 문제가 나와도 훨씬 덜 헷갈린다.
헷갈리기 쉬운 부분
1.
next()는 한 줄 전체를 읽는 메서드가 아니다
next()는 공백에서 끊는다.
그래서 문장 전체를 받고 싶을 때는 맞지 않는다.
2.
nextLine()은 공백을 포함해서 한 줄 전체를 읽는다중간에 띄어쓰기가 있어도 엔터를 치기 전까지는 계속 읽는다.
그래서 공백 포함 입력에는nextLine()이 더 잘 맞는다.
3.
nextInt()와nextDouble()도 공백 기준으로 읽는다숫자라고 해서 특별한 방식으로 읽는 것이 아니라,
입력값을 공백 기준으로 끊어서 숫자로 해석하는 것이다.
4.
next()다음에nextLine()은 바로 연결하면 헷갈릴 수 있다앞에서 남아 있는 엔터 때문에
다음nextLine()이 기대와 다르게 동작할 수 있다.
그래서 중간에 버퍼 정리용nextLine()이 필요한 경우가 있다.
5. Scanner는 메서드 이름보다 입력이 어디서 끊기는지가 더 중요하다
초보자는 메서드 이름만 외우다가 더 헷갈리기 쉽다.
먼저 “공백에서 끊는가, 줄 전체를 읽는가, 숫자로 받는가”를 기준으로 이해하는 것이 좋다.
참고
Scanner는 키보드 입력을 처리하는 가장 기본적인 도구다.
처음에는next(),nextLine(),nextInt()가 비슷해 보여 헷갈릴 수 있지만,
입력을 어디서 끊는지 기준으로 보면 정리가 쉽다.
- 단어처럼 공백 기준으로 받기 →
next()- 한 줄 전체를 받기 →
nextLine()- 정수 바로 받기 →
nextInt()- 실수 바로 받기 →
nextDouble()- 입력 방식을 섞어 쓸 때는 버퍼 처리까지 생각하기
즉,
Scanner는
입력값을 원하는 단위와 타입으로 끊어서 읽기 위한 기본 도구라고 이해하면 된다.
개념
main 클래스라고 부를 때 실제로 중심이 되는 것은main()메서드가 들어 있는 클래스다.
즉, 특별한 종류의 클래스가 따로 있는 것이 아니라,
그 클래스 안에main()메서드가 있으면 그 클래스가 프로그램의 시작점 역할을 하게 된다.
자바 프로그램은 실행하면 아무 곳에서나 시작하는 것이 아니다.
반드시main()메서드부터 시작한다.
그래서main()은 자바 애플리케이션의 출발점이라고 이해하면 된다.
예를 들어 프로그램 안에 클래스가 여러 개 있어도
실행할 때는 그중 아무 클래스나 시작하는 것이 아니라,
main()이 들어 있는 클래스를 기준으로 시작한다.
즉,
main 클래스를 이해한다는 것은
“자바 프로그램이 어디서부터 시작해서 어떤 순서로 흘러가는가”를 이해하는 것과 같다.
핵심 특징
- 자바 프로그램은
main()메서드에서 시작한다.- 모든 클래스가
main()을 가질 필요는 없다.- 하지만 실행 가능한 프로그램에는
main()이 들어 있는 클래스가 적어도 하나는 있어야 한다.main()안에는 프로그램 시작에 필요한 실행 문장들이 들어간다.- 객체 생성, 메서드 호출, 입력, 출력도 보통
main()에서 시작된다.main()은 프로그램 전체 흐름이 한눈에 보이도록 정리하는 것이 좋다.
예제별 역할
Hello: 가장 단순한main()구조 확인ObjectTest1:main()안에서 객체를 생성하고 비교하는 흐름 확인StringTest:main()안에서 메서드를 순서대로 호출하는 흐름 확인ScannerTest3:main()안에서 입력 → 계산 → 출력이 이어지는 흐름 확인
1. 자바 프로그램은 어디서부터 시작할까
가장 기본 형태는 이런 구조다.
예제:
Hello// Hello.java class Hello { public static void main(String[] args) { System.out.println("Hello, Java."); } }// 출력결과 // Hello, Java.이 코드는 아주 단순하지만
main()의 역할을 이해하기에는 가장 좋다.프로그램을 실행하면 바로
main()안으로 들어와서
System.out.println("Hello, Java.");를 실행하고 끝난다.즉, 흐름은 이렇게 보면 된다.
프로그램 실행
→main()시작
→println()실행
→main()끝
→ 프로그램 종료여기서 중요한 점은
자바 프로그램이 클래스 전체를 위에서 아래로 그냥 읽는 방식이 아니라,
main()을 시작점으로 삼아 그 안의 문장부터 실행한다는 것이다.그래서 초보자는
“자바 프로그램은 일단main()부터 시작한다”
이 감각을 가장 먼저 잡는 것이 중요하다.
2. main() 메서드의 기본 형태는 왜 항상 비슷할까
main()은 보통 이렇게 적는다.public static void main(String[] args)이 모양이 늘 비슷하게 보이는 이유는
프로그램이 시작될 때 자바가 알아볼 수 있도록 미리 약속된 형태이기 때문이다.하나씩 아주 쉽게 풀면 이렇다.
public
밖에서 이 메서드를 호출할 수 있게 연다.
static
객체를 먼저 만들지 않아도 바로 실행할 수 있게 한다.
void
실행만 하고 값을 돌려주지는 않는다는 뜻이다.
main
시작점으로 쓰는 메서드 이름이다.
String[] args
실행할 때 바깥에서 전달되는 문자열들을 받는 자리다.여기서 초보자에게 가장 중요한 것은
지금 당장 이 뜻을 전부 깊게 외우는 것이 아니라,
main()은 프로그램 시작용으로 정해진 형태라는 점을 먼저 받아들이는 것이다.특히
String[] args는 아직 배열을 배우기 전이라면
“문자열들을 받을 수 있는 자리구나” 정도로만 이해해도 충분하다.
3. main() 안에 코드를 작성한다는 것은 무슨 뜻일까
main()안에는 프로그램이 시작하자마자 해야 하는 작업들을 적는다.예를 들어 이런 일들이 들어갈 수 있다.
- 객체 생성
- 메서드 호출
- 입력 받기
- 계산하기
- 결과 출력하기
즉,
main()은
프로그램이 시작되었을 때 처음 실행해야 하는 문장들을 모아 둔 곳이라고 보면 된다.이 점은 네가 본 예제들에서도 그대로 드러난다.
예를 들어
ObjectTest1에서는main()안에서 객체를 만들고 비교한다.Member1 obj1 = new Member1(10, "자바", "duke"); Member1 obj2 = new Member1(10, "자바", "duke"); System.out.println(obj1.equals(obj2)); System.out.println(obj1 == obj2);이 흐름을 보면
main()은
객체를 만드는 곳, 비교를 시작하는 곳, 결과를 출력하는 곳 역할을 한 번에 한다.또
StringTest에서는main()안에서 여러 문자열 메서드를 순서대로 호출한다.System.out.println("1".length()); System.out.println("abc".charAt(1)); System.out.println("abc".toUpperCase());즉,
main()은
문자열 길이 확인 → 문자 꺼내기 → 대문자 변환
처럼 실행 흐름을 순서대로 보여 주는 곳이 된다.그리고
ScannerTest3에서는int number1 = sc.nextInt(); int number2 = sc.nextInt(); System.out.printf("합 : %d%n", number1 + number2);이렇게 입력 → 계산 → 출력이
main()안에서 이어진다.그래서
main()은 단순히 시작점일 뿐 아니라,
작은 예제에서는 프로그램 전체 흐름이 실제로 펼쳐지는 공간이라고 볼 수 있다.
4. main()에서 다른 메서드를 부르면 어떤 흐름으로 실행될까
main()이 시작점이라고 해서
모든 코드를 꼭main()안에만 다 써야 하는 것은 아니다.오히려 프로그램이 조금만 커져도
main()안에서 다른 메서드를 호출하는 흐름으로 가게 된다.예를 들어 이런 식이다.
public static void main(String[] args) { firstMethod(); }이 경우 실행 흐름은 이렇게 된다.
- 프로그램 시작
main()실행main()이firstMethod()호출firstMethod()실행firstMethod()종료- 다시
main()으로 돌아옴main()종료- 프로그램 종료
즉,
main()은 항상 첫 시작점이지만,
실행 도중에는 다른 메서드를 불러서 일을 나누어 맡길 수도 있다.이 감각이 중요하다.
프로그램이 커질수록main()혼자 모든 일을 하는 것이 아니라,
main()이 전체 흐름을 잡고 필요한 메서드들을 호출하는 구조로 가기 때문이다.
5. main()은 길게 다 적는 곳이 아니라 흐름을 보여주는 곳이다
처음 자바를 배울 때는 예제가 작아서
main()안에 모든 문장을 다 써도 큰 문제가 없어 보인다.하지만 프로그램이 길어질수록
main()안에 모든 코드를 몰아넣으면
읽기도 어렵고, 수정도 어렵고, 흐름도 잘 안 보이게 된다.그래서
main()은 보통
프로그램 전체 흐름이 한눈에 보이도록 단순하게 정리하는 편이 좋다.예를 들어 이런 느낌이다.
public static void main(String[] args) { showMenu(); inputData(); processData(); printResult(); }이렇게 쓰면
세부 작업은 각각 다른 메서드가 맡고,
main()은 전체 진행 순서만 깔끔하게 보여주는 역할을 하게 된다.즉,
main()은
코드를 전부 다 넣는 창고라기보다
프로그램의 큰 흐름을 보여 주는 안내판처럼 생각하는 것이 좋다.작은 예제에서는
main()안에 직접 써도 괜찮지만,
코드가 길어질수록 “흐름은main()에서, 세부 작업은 다른 메서드에서”라는 감각을 가져가는 것이 좋다.
6. 예제에서 main()은 어떤 역할을 하는가
지금까지 본 예제들을 기준으로 보면
main()의 역할은 크게 세 가지로 정리할 수 있다.1) 실행 시작점
프로그램이 시작되면 가장 먼저
main()으로 들어온다.
그래서 모든 예제는 결국main()을 기준으로 움직인다.2) 작업 순서 정리
main()안에는
객체 생성 → 메서드 호출 → 입력 → 계산 → 출력
같은 작업 순서가 드러난다.즉, 초보자는
main()을 볼 때
“이 프로그램이 어떤 순서로 움직이는지”를 먼저 읽으면 된다.3) 다른 메서드 호출의 출발점
지금 예제들은 대부분
main()안에서 바로 실행하는 구조지만,
나중에는main()이 다른 메서드를 호출하는 구조가 많아진다.그래서
main()은
작업을 직접 다 하는 곳이기도 하고,
필요한 메서드들을 불러오는 출발점이기도 하다.
헷갈리기 쉬운 부분
1.
main 클래스와main 메서드는 같은 말이 아니다엄밀하게 말하면 특별한 “main 클래스”가 따로 있는 것은 아니다.
main()메서드가 들어 있는 클래스가 프로그램 시작 클래스 역할을 하는 것이다.2. 모든 클래스에
main()이 필요한 것은 아니다실행 가능한 애플리케이션에는
main()이 적어도 하나 있어야 하지만,
모든 클래스가main()을 가질 필요는 없다.
보조 역할 클래스에는 없어도 된다.3.
main()안에만 코드를 써야 하는 것은 아니다
main()은 시작점일 뿐이다.
필요하면 다른 메서드를 호출해서 작업을 나눌 수 있다.4.
main()은 자동으로 아무 클래스나 찾는 것이 아니다실행할 때는
main()이 들어 있는 클래스를 기준으로 시작한다.
그래서 시작 클래스를 정확히 알아야 한다.5.
String[] args는 지금 단계에서 너무 어렵게 생각하지 않아도 된다실행할 때 바깥에서 전달되는 문자열들을 받는 자리라고만 이해해도 충분하다.
배열 자체는 나중에 더 자세히 배우면 된다.
참고
main()을 이해할 때는 너무 복잡하게 생각할 필요가 없다.
- 자바 프로그램은
main()에서 시작한다.main()안의 문장들이 위에서 아래로 실행된다.- 필요하면
main()이 다른 메서드를 호출한다.- 프로그램이 끝날 때는 결국 다시
main()이 끝나면서 종료된다.즉,
main 클래스와 프로그램 시작 구조에서 가장 중요한 핵심은
main()은 자바 프로그램의 시작점이고, 프로그램의 큰 흐름이 처음 드러나는 자리라는 점이다.