문자열
문자 덩어리를 하나의 데이터로 다루는 처리
문자열의 기초지식
자바에서는 문자열 데이터를 String 클래스로 다루는 것이 기본
기본형인 char를 이용해 1문자씩 다룰수 있지만, 방법이 불편해서 사용하지 않는다.
일반적으로 문자열 조작에는 String형을 사용한다.
String 클래스는 일반 클래스와 구별되어 특별 취급.
new를 사용하지 않고도 인스턴스화할 수 있다.
String test = "String 클래스이다.";
new 연산자로 선언
String test = new String("String 클래스이다.");
하지만 new 연산자로 선언하는 것은 의미도 없고 이중으로 인스턴스를 만들게 된다.
String 클래스는 인스턴스의 데이터가 변하지 않는 불변(immutable)클래스이다.
String형 데이터에 어떤 변경을 가하면 인스턴스의 문자열 데이터가 변하는 것이 아니라 인스턴스를 새로 생성한다.
public static void main(String[] args) {
String text1 = "안녕 ";
String test2 = "하세요.";
test1 = test1 + test2;
System.out.println(test1);
}
String 클래스인 2개의 문자열을 + 연산자로 결합.
프로그램 내부에서는 text1과 text2 그리고 결합 후의 text1이라는 3개의 String 인스턴스가 생성된다.
text1 인스턴스는 보이지 않지만 여전히 메모리상에 존재.
문자열을 연결할때는 새로운 인스턴스가 만들어지고, 원래 참조하던 text1 인스턴스에서 새로운 인스턴스로 교체된다.
루프안에서 문자여을 몇번이고 연결하게 되면 반복할때마다 인스턴스를 새로 만든다.
즉 사용하지 않는 인스턴스가 계속 쌓인다.
문자열 연결에는 StringBuilder를 사용
+ 연산자 대신 문자열 연결에 이용할 수 있는 클래스가 StringBuilder이다.
StringBuilder 클래스는 append 메서드로 문자열을 축적하고 마지막에 toString메서드로 모아둔 문자열을 출력한다.
public static void main(String[] args) {
String text1 = "안녕 ";
String test2 = "하세요.";
StringBuilder sb = new StringBuilder();
sb.append(text1);
sb.append(text2);
String resultString = sb.toString();
System.out.println(resultString);
}
StringBuilder를 이용하면 인스턴스 내부에서 문자열을 연결할 수 있다.따라서 연결하고 싶은 문자열이 늘어나도 사용하는 메모리는 일정하게 억제할 수 있다.
자바8에는 StringJoiner 클래스가 추가됨.
문자열의 형식
문자열을 출력
public class Detail {
private String itemName;
private BigDecimal amount;
//getter setter
}
public static void main(String[] args) {
//구매 내역 데이터
Detail detail = new Detail();
detail.setItemName("쌀5kg");
detail.setAmount(new BigDecimal(15000));
//구매 내역 데이터가공
StringBuilder sb = new StringBuilder();
sb.append(detail.getItemName());
sb.append(" ");
sb.append(detail.getAmount());
sb.append("원");
//구매 내역 출력
System.out.println(sb.toString());
}
결과
쌀 5kg 15,000원
다양한 의견 및 수정
-금액에 따라서는 위치가 어긋남
-상품명이 길면 점점 오른쪽으로 밀려 금액이 인쇄 안됨
-금액이 3자리마다 콤마로 구분되지 않음
-여러 내역을 추력할 수 없음
-합계 행이 없음.
-가게 이름과 전화번호가 없음
문자열의 포맷
일정한 틀에 따라 문자열의 형식을 바꾸는 것을 포맷이라고 한다.
규칙
-상세 내역 1행 전체가 20칸
-상품명과 금액이 각각 10칸씩 사용
-상품명은 왼쪽 맞춤, 금액은 오른쪽 맞춤
StringBuilder로 구현하기 힘듬.
String 클래스의 정적 메서드 format를 사용.
문자열을 첫번째 인수로 설정하고 두번째 인수 이후에 지정된 값을 차례대로 서식 위치에 채워가는 기능
%s - 문자열
%d - 수
%10s - 문자열을 오른쪽 정렬 10자리로 한다. 남는 자리엔 공백이 채워진다.
%-10s - 문자열을 왼쪽 정렬 10자리로 한다. 남는 자리엔 공백이 채워진다.
public static void main(String[] args) {
//구매 내역 데이터
Detail detail1 = new Detail();
detail1.setItemName("쌀 5kg");
detail1.setAmount(new BigDecimal(15000));
Detail detail2 = new Detail();
detail2.setItemName("사과9개");
detail2.setAmount(new BigDecimal(9000));
//구매 내역 문자열 서식 정의
String lineBase = "%-10s%10d원";
//구매 내역 데이터가공
String result1 = String.format(lineBase, detail1.getItemName(), detail1.getAmount().longValue());
String result2 = String.format(lineBase, detail2.getItemName(), detail2.getAmount().longValue());
//구매 내역 출력
System.out.println(result1);
System.out.println(result2);
}
수치의 포맷
금액이 3자리마다 콤마로 구분되지 않는 문제
String lineBase = "%-10s%,10s원";
%뒤에 콤마를 입력하면 3자리마다 콤마로 구분해줌.
DecimalFormat은 수치를 서식에 따라 문자로 변환하는 클래스
0 - 여기에 수치가 들어감(설정한 자리수에 모자라면 0으로 채움)
# - 여기에 수치가 들어감(설정한 자리수에 모자라면 아무것도 들어가지 않는다.)
, - 해당 위치에 콤마가 그대로 들어감.
. - 해당 위치에 도트가 그대로 들어감.
###,##0
000,000
12
12
000,012
1234
1,234
001,234
1234567
1,234,567
1,234,567
public void stringFormat() {
//구매 내역 데이터
Detail detail1 = new Detail();
detail1.setItemName("쌀 5kg");
detail1.setAmount(new BigDecimal(15000));
Detail detail2 = new Detail();
detail2.setItemName("사과9개");
detail2.setAmount(new BigDecimal(9000));
//구매 내역 문자열 서식 정의
String lineBase = "%-10s%10s원";
//금액표시용 서식 정의
DecimalFormat df = new DecimalFormat("###,##0");
//금액 데이터가공
String dispAmount1 = df.format(detail1.getAmount().longValue());
String dispAmount2 = df.format(detail2.getAmount().longValue());
String result1 = String.format(lineBase, detail1.getItemName(), dispAmount1);
String result2 = String.format(lineBase, detail2.getItemName(), dispAmount2);
//구매 내역 출력
System.out.println(result1);
System.out.println(result2);
}
정리
-문자열은 불변.
-문자열의 연결은 StringBuilder를 사용.
-문자열 서식은 String클래스의 format 메서드 사용.
-수치 서식은 DecimalForamt을 사용.
날짜와 시간
java.util.Date - 특정 날짜를 저장한다.
java.util.Calendar - 일시에 대한 다양한 조작을 한다.
java.text.SimpleDateFormat - 지정한 서식에 따라 문자열을 Date 클래스로 변환하거나, 반대로 처리
현재날짜를 이용한 데이터 조작
public void dateTest() {
Date now = new Date();
System.out.println(now);
}
Mon Apr 23 17:43:09 KST 2018
날짜 변경
임의의 날짜를 생성할때는 Calender 클래스 사용
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_MONTH, 1);
//출력용으로 Calender 클래스에서 Date 클래스를 얻는다.
Date nextMonth = cal.getTime();
System.out.println(nextMonth);
Calendar 클래스는 인스턴스를 만든 방법이 다르다.
new 연산자로 인스턴스를 만들수 없다.
임의로 인스턴스를 만들지 못하게 하는 것을 목적으로 한다.
클래스에 따라서 그런 제한이 걸린 것이 있으므로 만약 new 연산자로 클래스를 만들었는데, 컴파일 오류가 발생하면 javadoc을 보고 클래스 사용법을 확인해야 한다. (싱글톤 패턴)
Calender 클래스의 상수
YEAR - 연
MONTH - 월
DATE - 일
DAY_OF_MONTH - 일
HOUR_OF_DAY - 24시간제 시간
HOUR - 12시간제 시간
MINUTE - 분
SECONDE - 초
MILISECOND- 밀리초
지정한 날짜로 변경
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, 1);
//출력용으로 Calender 클래스에서 Date 클래스를 얻는다.
Date nextMonth = cal.getTime();
System.out.println(nextMonth);
set() 지정된 값이 현재 날짜와 관계없이 그대로 설정.
특정항목을 추출
get() 날짜 데이터에서 결과를 추출
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, 1);
//출력용으로 Calender 클래스에서 Date 클래스를 얻는다.
Date nextMonth = cal.getTime();
System.out.println(nextMonth);
int intmonth = cal.get(Calendar.MONTH);
System.out.println(intmonth);
날짜 데이터를 지정 서식으로 출력
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, 1);
//출력용으로 Calender 클래스에서 Date 클래스를 얻는다.
Date nextMonth = cal.getTime();
System.out.println(nextMonth);
//날짜형식을 지정
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
String formatedStr = sdf.format(nextMonth);
System.out.println(formatedStr);
SimpleDateFormat 서식
yyyy - 4자리 연도
yy - 2자리 연도
MM - 월
dd - 일
HH - 시
mm - 분
ss - 초
SSS - 밀리초
날짜 데이터 비교
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.set(Calendar.DAY_OF_MONTH, 1);
cal2.set(Calendar.DAY_OF_MONTH, 2);
System.out.println(cal1.getTime());
System.out.println(cal2.getTime());
int result = cal1.compareTo(cal2);
System.out.println(result);
Calendar 클래스의 compareTo 메서드
기준일보다 비교대상 날짜가 작을 때는 1
기준일보다 비교대상 날짜가 같을 때는 0
기준일보다 비교대상 날짜가 클을 때는 -1
after 비교할 인스턴스가 비교 대상보다 미래인지 비교
before 비교할 인스턴스가 비교 대상보다 과거인지 비교
equals 비교할 인스턴스가 비교 대상과 같은지 비교
compareTo 비교할 인스턴스가 비교 대상보다 미래면 1, 과거면 -1, 같으면 0을 반환
Date-Time API
자바 8부터는 Date-Time API로 제공하고 있다.
java.time 패키지
종류 - 연월일 시간 일시 시차정보 지역규칙
Local - LocalDate LocalTime LocalDateTime X O
Zoned - ZonedDateTime O O
Offset - OffsetTime OffSetDateTime O X
단순히 시차를 다를뿐만 아니라 서머타임 등 지역별로 시간에 관계된 규칙도 다룰 수 있다.
-시차를 다루지 않으면 Local로 시작되는 클래스를 사용
-시차를 다루면 Offset으로 시작되는 클래스를 사용
-시차뿐만 아니라 그 지역의 일시가 고려된 편이 바람직하면 ZonedDateTime을 사용
String 클래스와 마찬가지로 이뮤터블로 스레드안전성이 있는 클래스가 됨.
이전에 밀리초까지만 다룰 수 있었던 것이 나노초까지 다룰 수 있게 됨.
//시차 미사용
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
//시차를 가미한 날자와 시간 생성
OffsetDateTime offsetDateTime = OffsetDateTime.of(2020, Month.APRIL.getValue(), 8, 10, 20, 30, 0, ZoneOffset.of("+09:00"));
System.out.println(offsetDateTime);
//시차와 지역 정보를 가미한 날짜와 시간 생성
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2025-07-24T11:12+09:00[Asia/Seoul]");
System.out.println(zonedDateTime);
LocalDateTime의 now로 현재 시간 생성
LocalDateTime은 new를 사용할수 없다.
반드시 static 메서드로 인스턴스를 생성해야 한다.
OffsetDateTime of메서드로 연월일, 시분초, 밀리초까지 지정하고 ZoneOffset 클래스로 시차를 지정.
ISO-8601이라는 국제규격에 따른 날자와 시간으로 표현
ZonedDateTime 클래스로 지역정보가 확인.
2가지 시간 구하기
Period - 날짜의 간격을 다룬다.
Duration - 시각의 간격을 다룬다.
LocalDateTime localDateTime1 = LocalDateTime.of(2018, Month.JUNE.getValue(), 10, 10, 10, 10, 000000000);
LocalDateTime localDateTime2 = LocalDateTime.of(2019, Month.JULY.getValue(), 11, 11, 11, 11, 100000001);
Period period = Period.between(localDateTime1.toLocalDate(), localDateTime2.toLocalDate());
System.out.println("-------- period 특정 항목의 차이 --------");
System.out.println("년차: " + period.getYears());
System.out.println("월차: " + period.getMonths());
System.out.println("일차: " + period.getDays());
System.out.println("-------- period 누적 -------");
System.out.println("누적 월차: " + period.toTotalMonths());
Duration duration = Duration.between(localDateTime1, localDateTime2);
System.out.println("-------- duration 특정 항목의 차이 --------");
System.out.println("밀리초~나노초차: " + duration.getNano());
System.out.println("-------- duration 누적 -------");
System.out.println("누적 일차: " + duration.toDays());
System.out.println("누적 시간차: " + duration.toHours());
System.out.println("누적 분차: " + duration.toMinutes());
System.out.println("누적 초차: " + duration.getSeconds());
System.out.println("누적 밀리초차: " + duration.toMillis());
System.out.println("누적 나초초차: " + duration.toNanos());
LocalDate localDate1 = LocalDate.of(2018, Month.MAY.getValue(), 1);
LocalDate localDate2 = LocalDate.of(2018, Month.JUNE.getValue(), 2);
Period period = Period.between(localDate1, localDate2);
LocalDate localDate3 = localDate2.plus(period);
System.out.println(localDate3);
2개의 날자를 비교하여 그 차이를 2번째 날짜에 더한다.
두 날짜의 차이는 1년 1개월 1일이다.
그차이를 2번째 날짜에 더했으므로 2번째 날짜에서 1년 1개월 1일 뒤의 날짜를 최종적으로 얻는다.
Date-Time API에선 단순히 날짜와 시간을 구할 뿐만 아니라 기간 등 날짜와 시간에 관한 개념을 클래스로 모아서 편리한 기능을 제공한다.
Date-Time API와 Calendar, Date 클래스의 중개
Date-Time API를 사용하려면 데이터를 상황에 맞는 클래스로 변환해야 한다.
이런 용도로 사용하고자 Date-Time API는 Instant라는 클래스를 제공
Instant 클래스를 이용하면 Date-Time API와 Calendar, Date 클래스를 서로 변환.
Instant 클랫는 에폭타임부터 경과된 시간을 가진다.(1970년 1월 1일 자정을 기준)
클래스명 대응방향 Date-Time API의 클래스
java.util.Date <-> java.time.Instant
java.util.Calendar -> java.time.Instant
클래스명 메서드 반환형
java.util.Date toInstant() java.time.Instant
java.util.Date from(Instant instant) java.util.Date
java.util.Calendar toInstant() java.time.Instant
LocalDateTime localDateTime1 = LocalDateTime.of(2025, Month.DECEMBER.getValue(), 1, 2, 3, 4, 567890123);
System.out.println("-------- 시작 시의 시간과 날짜 --------");
System.out.println(localDateTime1);
Instant instant1 = localDateTime1.toInstant(ZoneOffset.of("+09:00"));
//Instant에서 Date로 변환
Date date = Date.from(instant1);
System.out.println("-------- java.util.Date의 일시 --------");
System.out.println(date);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
System.out.println("-------- java.util.Calendar의 일시 --------");
System.out.println(calendar);
Instant instant2 = date.toInstant();
LocalDateTime localDateTime2 = LocalDateTime.ofInstant(instant2, ZoneId.of("Asia/Seoul"));
System.out.println("-------- java.util.Date에서 LocalDateTime으로 되돌린 값 --------");
System.out.println(localDateTime2);
//Calendar에서 Instant로 변환
Instant instant3 = calendar.toInstant();
LocalDateTime localDateTime3 = LocalDateTime.ofInstant(instant3, ZoneId.of("Asia/Seoul"));
System.out.println("-------- java.util.Calendar에서 LocalDateTime으로 되돌린 값 --------");
System.out.println(localDateTime3);
출처-실무에서 바로 통하는 자바
'issue & tip' 카테고리의 다른 글
부동소수점 (0) | 2018.04.24 |
---|---|
스레드 (0) | 2018.04.24 |
백세코딩#소프트웨어 개발의 기본 (0) | 2018.04.16 |
백세코딩#코드리뷰 (0) | 2018.04.16 |
백세코딩 #빅데이터 (0) | 2018.04.16 |