Java 정리 17
05 Dec 2018
Reading time ~8 minutes
Java 정리 17 - StringBuffer, StringBuilder, StringTokenizer, Math, Date, Calendar
문자열 다루기
- String
- 문자열 저장소의 주소를 참조, 같은 문자열이 없도록 하나만 생성된다.
- method를 호출하여 일을 하면 원본 문자열이 변경되지 않는다.
- StringBuffer
- multi thread 환경에서 동시접근이 불가능
- StringBuilder
- jdk 1.5에서 추가된 클래스
- StringBuffer와 사용법은 동일
- String-StringBuffer-StringBuilder 순으로 빠르다.
- 객체의 문자열을 바로 저장, 같은 문자열이 생성된다.
- StringBuffer도 동일
- method 호출하여 일을 하면 문자열이 변경된다.
- multi thread 환경에서 동시접근이 가능
- 문자열 +연산시 Compiler가 jdk1.5 이하면 StringBuffer로 처리하고 jdk 1.5이상이면 StringBuilder로 처리한다.
StringBuffer, StringBuilder
- 문자열을 heap에 저장
- 같은 문자열을 여러개를 저장하게 됨
- 메소드를 불러서 일을하면 원본문자열이 변경이 됨
- 둘 중 하나만 사용가능하면 다 쓸 수 있게됨 (사용법 동일)
- 차이점
- StringBuffer - 멀티쓰레드 동시접근 불가능
- StringBuilder - 멀티쓰레드 동시접근가능
- 속도때문에 Builder 많이 사용한다.
// 생성
StringBuffer sb = new StringBuffer();
// 값 덧붙임(오버로드로 많이 구현되어 있음)
// 정수, 실수, 문자, 문자열, boolean들을 문자열로 추가 가능
// 추가한 값을 저장한 문자열의 주소를 반환
sb.append(값);
// append 반환형이 StringBuffer이므로 메소드체인 가능
sb.append("Hello ").append("World!");
// 문자열로 반환할 때
String s = sb.toString();
// 값을 삽입, 0번 인덱스에 값 삽입
sb.insert(인덱스, 값);
// 문자열의 순서를 뒤집을 수 있음
sb.reverse();
// 값 삭제
sb.delete(시작인덱스, 끝인덱스+1);
// String과 동일한 기능의 메소드들이 많다
sb.indexOf("12");
sb.lastIndexOf("5");
sb.charAt(23);
sb.substring(sb.indexOf("안녕"));
- String은 짧은 문자열 다룰 때 StringBuilder와 StringBuffer는 긴 문자열을 다룰 때 사용
- 짧은 문자열은 글자수 상관없이 “로 시작, “로 끝나는 문자열
- 긴 문자열은 “안”+”녕”과 같이 추가적인 연산이 들어가는 문자열
- String은 ‘+’사용하지 않는다.(StringBuilder 사용!)
String str1 = "안";
// 문자열에 '+'가 붙어서 긴 문자열이 된다.
System.out.println(str1+"녕"+"하"+"세"+"요"+".");
// new StringBuilder().append(str1).append("녕").append("하")...;
// decompiler로 바이트코드를 보면 자바는 긴문자열을 StringBuilder로 처리
StringTokenizer
- java.util 패키지에서 제공
- 문자열을 짧은 한 마디(token)로 구분할 때 사용
- StringTokenizer는 포인터
- 단어 하나하나를 토큰으로 분리
- nextToken()메소드를 호출하여 값을 얻고 다음 토큰으로 포인터 이동
- 포인터는 뒤로 갈 수 없다.
- String의 split과는 다르게 StringTokenizer는 구분자로 ’.’로도 자를 수 있다.
// 공백으로 토큰을 구분한다
String s = "";
StringTokenizer stk = new StringTokenizer(s);
// 토큰의 개수를 알아내는 countTokens()
stk.countTokens();
// 토큰이 존재하면 true, 없으면 false를 리턴하는 hasMoreTokens()
stk.hasMoreTokens();
// 값(String)을 얻고 다음 토큰으로 포인터를 이동하는 nextToken()
stk.nextToken();
// 문자열을 구분자 나눌 땐 인수2개짜리 생성자 호출
String = str = "오늘은, 수요일, 입니다.";
StringTokenizer strStk = new StringTokenizer(str, ",");
// 구분자도 토큰으로 사용할 땐 인수3개짜리 생성자 호출, true면 보호
StringTokenizer strStk2 = new StringTokenizer(str, ",", true);
import java.util.StringTokenizer;
public class STKTest {
public static void main(String[] args) {
String s = "";
s = "오늘은 수요일 입니다.";
StringTokenizer stk = new StringTokenizer(s);
System.out.println(stk.countTokens()); // 3
while(stk.hasMoreTokens()) {
System.out.println(stk.nextToken());
}
String str = "오늘은, 수요일, 입니다.";
StringTokenizer stk1 = new StringTokenizer(str, ",");
while(stk1.hasMoreTokens()) {
System.out.println(stk1.nextToken());
}
StringTokenizer stk2 = new StringTokenizer(str, ",", true);
while(stk2.hasMoreTokens()) {
System.out.println(stk2.nextToken());
}
String names = "이재현,이재찬~정택성,김희철.김정운~김정윤,공선의";
// ',~.'로 구분
StringTokenizer stk4 = new StringTokenizer(names, ",~.");
System.out.println("토큰의 수 : "+stk4.countTokens());
while(stk4.hasMoreTokens()) {
System.out.println(stk4.nextToken());
}
}
}
Math
- java.lang 패키지에 있는 클래스
- 수학적인 일을 할 때 사용하는 클래스
- API Doc을 보면 생성자가 없음
- 생성자에 private이 붙은 것
- 객체화해서 사용하는 클래스가 아님
- method만 호출하여 사용하는 클래스
// 절대값
Math.abs(-10); // 10
// 반올림, 자바는 소수점이하 첫 번째자리에서 반올림(오라클 처럼 자리수 지정 못함)
Math.round(10.4); // 10
Math.round(10.5); // 11
// 올림, 0은 올리지 않는다.
Math.ceil(10.1); // 11
// 절삭, 소수 이하를 절삭하는 메소드는 없다. => 그냥 casting
(int)10.1
// 내림, 소수점 이하 첫번째자리에서 내림
Math.floor(10.6); // 10
// 난수, 0~1사이 임의의 실수(double, 소수점이하 16자리)을 반환
Math.random();
// 0~9 사이 난수를 얻기 위해선
Math.random()*10;
// A-Z 중 하나의 문자를 반환하는 일.알파벳은 26개. 65-90(대문자), 97-122(소문자)
// 랜덤 대문자 출력
for(int j=0; j<5; j++) {
System.out.println((char)((int)(Math.random()*26)+65));
}
// 랜덤 소문자 출력
for(int j=0; j<5; j++) {
System.out.println((char)((int)(Math.random()*26)+97));
}
// 난수 메소드를 이용해서 임의의 비밀번호 구하기
// 계정 비번찾기시 새비번을 반환해주는 메소드
// 48~57 숫자 65~90 대문자, 97~122 소문자
// 영문자대문자,소문자,숫자로 이루어진
// 임의의 비밀번호 8자리를 생성하여 반환하는 일
public class UseMath {
public char[] createPassword() {
char[] tempPass = new char[8];
int rNum=0;
for(int i=0; i<tempPass.length; i++) {
while(true) {
rNum = (int)(Math.random()*122)+1;
if ((rNum > 47 && rNum < 58) || (rNum > 64 && rNum <91)
|| (rNum > 96 && rNum < 123)) {
break;
}
}
System.out.println((char)rNum);
tempPass[i] = (char)rNum;
}
System.out.println(tempPass);
return tempPass;
}
// 다른 짧은 방식
public char[] createPassword2() {
char[] tempPass = new char[8];
String flag=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for(int i=0; i<tempPass.length; i++) {
tempPass[i] = flag.charAt((int)(Math.random()*flag.length()));
}
System.out.println(tempPass);
return tempPass;
}
public static void main(String[] args) {
new UseMath().createPassword();
new UseMath().createPassword2();
}
// switch문 사용한 방식(if보다 좋은 방식)
public char[] createPassword3() {
char[] tempPass = new char[8];
int flag = 0;
for(int i=0; i<tempPass.length; i++) {
flag = (int)(Math.random()*3)+1;
switch(flag) {
case 1: // 숫자
tempPass[i] = (char)((int)(Math.random()*10)+48);
break;
case 2: // 대문자
tempPass[i] = (char)((int)(Math.random()*26)+65);
break;
case 3: // 소문자
tempPass[i] = (char)((int)(Math.random()*26)+97);
break;
}
}
System.out.println(tempPass);
return tempPass;
}
}
System.currentTimeMillis
- 메인보드 CMOS가 날짜정보를 갖고 있고 OS는 CMOS로부터 날짜를 받아온다.
- JVM System클래스가 OS로부터 날짜정보를 전달받아 사용
- 시간을 얻는 일을 하는 메소드 System.currentTime
- 1970-01-01 00:00:00 부터 현재 시간의 차를 long형으로 반환
- System클래스엔 더 정밀한 시간을 반환하는 nanoTime() 메소드(1/억)도 있다.
- 코드 수행시간을 잴 때 많이 사용
public class UseCurrentTime {
public void test() {
long st = System.currentTimeMillis();
long sum = 0;
for(int i=0; i<10000; i++) {
sum = sum + i;
// System.out.println(); 출력하면 처리속도가 엄청 느려진다.
// 테스트 때를 제외하면 System.out.println은 거의 안쓴다
System.out.println(i);
}
long et = System.currentTimeMillis();
// 코드 수행 시간
System.out.println((et-st)+"ms");
}
public static void main(String[] args) {
UseCurrentTime uct = new UseCurrentTime();
uct.test();
}
}
// 프로그램 평균 시간 구하기 - 10~15회 반복,
// 평균값을 구하면 평균수행시간을 구할 수 있음
public class ProcessTime {
public static void main(String[] args) {
// 프로그램 평균시간 구하기
long[] processTime = new long[17];
long st = 0, et = 0;
long sumTime = 0;
long avgTime = 0;
for (int i = 0; i < processTime.length; i++) {
st = System.currentTimeMillis();
for (int j = 0; j < 50000; j++) {
System.out.print(j);
}
System.out.println();
et = System.currentTimeMillis();
processTime[i] = (et - st);
sumTime += processTime[i];
}
avgTime = sumTime / processTime.length;
System.out.println("소요되는 평균시간(ms) : " + avgTime);
}
}
날짜 관련 클래스
- java.util 패키지에 존재
- Date : 형식이 있는 날짜 정보를 얻을 때
- 객체 생성해서 사용
- java.text 패키지에 있는 SimpleDateFormat과 같이 사용
- Date 클래스는 거의 모든 메소드가 Deprecated 따라서 Calendar 클래스 사용
- Calendar : 단일 날짜 정보를 얻을 때
Date
- 날짜 정보를 얻을 때 사용
- 형식을 맡는 SimpleDateFormat과 같이 사용
- 객체 생성해서 사용
- Date 클래스는 거의 모든 메소드가 Deprecated 따라서 Calendar 클래스 사용권장
SimpleDateFormat
- java.text 패키지에서 제공
- 날짜 형식을 제공
- pattern을 사용해서 형식을 지정
- 년 - y, 월 - M, 일 - d, 오전 - a
- 시
- h - 12시간제
- K - 0~11시간제
- H - 0~23시간제
- k - 1~24시간제
- 분 - m, 초 - s, 요일 - E
- pattern을 사용해서 형식을 지정
- 패턴 예시
// 1.생성 - 사용할 날짜 형식을 만드는 일
SimpleDateFormat sdf = new SimpleDateFormat(String pattern);
// 2.날짜 객체를 생성
Date d = new Date();
// 3.날짜 객체를 넣어서 지정한 형식의 날짜를 얻는다.
// has-a 관계라 말한다(SimpleDateFormat객체가 Date객체를 갖는 관계)
sd.format(date);
- 오라클과 다르게 패턴이 길어도 에러가 없다.
public class UseDate {
public UseDate() {
Date date = new Date();
System.out.println(date);
// 1900을 더해야 제대로된 Year나옴(Deprecated)
System.out.println(date.getYear()+1900);
SimpleDateFormat sdf = new SimpleDateFormat("y");
String formatDate = sdf.format(date);
System.out.println(formatDate); // 2018
sdf = new SimpleDateFormat("yy");
formatDate = sdf.format(date);
System.out.println(formatDate); // 18
sdf = new SimpleDateFormat("yyyy");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018
sdf = new SimpleDateFormat("yyyy년MM");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12
sdf = new SimpleDateFormat("yyyy년M");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12
sdf = new SimpleDateFormat("yyyy년MM월dd일");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12월05일
sdf = new SimpleDateFormat("yyyy년MM월dd일 a");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12월05일 오후
sdf = new SimpleDateFormat("yyyy년MM월dd일 a HH");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12월05일 오후 15
sdf = new SimpleDateFormat("yyyy년MM월dd일 a hh");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12월05일 오후 03
sdf = new SimpleDateFormat("yyyy년MM월dd일 a HH(hh,kk)");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12월05일 오후 15(03,15)
sdf = new SimpleDateFormat("yyyy년MM월dd일 a HH(hh,kk):mm");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12월05일 오후 15(03,15):39
sdf = new SimpleDateFormat("yyyy년MM월dd일 a HH(hh,kk):mm:ss");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12월05일 오후 15(03,15):39:36
sdf = new SimpleDateFormat("yyyy년MM월dd일 a HH(hh,kk):mm:ss E요일");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12월05일 오후 15(03,15):39:36 수요일
sdf = new SimpleDateFormat("yyyy년MM월dd일 a HH(hh,kk):mm:ss EEEE");
formatDate = sdf.format(date);
System.out.println(formatDate); // 2018년12월05일 오후 15(03,15):39:36 수요일
}
public static void main(String[] args) {
new UseDate();
}
}
- 로케일을 사용하면 다른 나라의 날짜형식을 사용가능
// 2018 12 05 PM 15(03,15):47:23 Wednesday
sdf = new SimpleDateFormat("yyyy MM dd a HH(hh,kk):mm:ss EEEE", Locale.UK);
// 2018 12 05 午後 15(03,15):47:23 水曜日
sdf = new SimpleDateFormat("yyyy MM dd a HH(hh,kk):mm:ss EEEE", Locale.JAPAN);
// 2018 12 05 PM 15(03,15):47:23 mercredi
sdf = new SimpleDateFormat("yyyy MM dd a HH(hh,kk):mm:ss EEEE", Locale.FRANCE);
// 2018 12 05 下午 15(03,15):47:23 星期三
sdf = new SimpleDateFormat("yyyy MM dd a HH(hh,kk):mm:ss EEEE", Locale.CHINESE);
// 2018 12 05 PM 15(03,15):47:23 Mittwoch
sdf = new SimpleDateFormat("yyyy MM dd a HH(hh,kk):mm:ss EEEE", Locale.GERMANY);
Calendar
- java.util 패키지에서 제공
- 단일 날짜정보를 얻을 때 사용
- Calendar는 추상클래스
- 객체화가 안된다
- GregorianCalendar(자식클래스)를 객체화하거나 getInstance라는 static 메소드를 사용해서 Calendar 인스턴스를 받아와야 사용가능
- Calendar 클래스는 생성되는 시점의 시간정보를 갖는다.
// Calendar 클래스가 제공하는 getInstance메소드로 사용하는 방법
Calendar c = Calendar.getInstance();
// is-a 관계 객체화로 Gregorian Calendar를 사용하는 방법
Calendar c1 = new GregorianCalendar();
GregorianCalendar c2 = new GregorianCalendar();
- get, set메소드에 넣는 field와 그렇지 않은 field로 나뉨
- java API doc참조
// 사용방법) get메소드에 field(Constant)를 집어넣어서 값을 얻는다.
System.out.println(c.get(Calendar.YEAR)); // 2018
// MONTH는 0~11을 반환 +1을 해줘야 함
System.out.println(c.get(Calendar.MONTH)+1);
// 요일을 나타낼 때 DAY_OF_MONTH 사용
System.out.println(c.get(Calendar.DAY_OF_MONTH));
// 숫자로 1~7 출력됨(일~토). 숫자는 요일의 인덱스를 뜻함
System.out.println(c.get(Calendar.DAY_OF_WEEK));
// 오늘이 올해 몇번째 날인지 출력
System.out.println(c.get(Calendar.DAY_OF_YEAR));
// AM/PM 출력 : 0(오전) 1(오후)
System.out.println(c.get(Calendar.AM_PM));
// 12시간제
System.out.println(c.get(Calendar.HOUR));
// 24시간제
System.out.println(c.get(Calendar.HOUR_OF_DAY));
// 분, 초
System.out.println(c.get(Calendar.MINUTE));
System.out.println(c.get(Calendar.SECOND));