public class BeepPrintExample3 {
public static void main(String[] args) {
Thread thread = new BeepThread();
thread.start();
for(int i=0;i<5;i++) {
System.out.println("띵");
try { Thread.sleep(500); }
catch (Exception e) {}
}
}
}
12.2.3 스레드의 이름
thread.setName("스레드 이름");
public class ThreadNameExample {
public static void main(String[] args) {
Thread mainThread = Thread.currentThread();
System.out.println("프로그램 시작 스레드 이름: " + mainThread.getName());
ThreadA threadA = new ThreadA();
System.out.println("작업 스레드 이름:" + threadA.getName());
threadA.start();
ThreadB threadB = new ThreadB();
System.out.println("작업 스레드 이름:" + threadB.getName());
threadB.start();
}
}
public class ThreadA extends Thread{
public ThreadA() {
setName("ThreadA");
}
@Override
public void run() {
for(int i=0; i<2; i++) {
System.out.println(getName() + "가 출력한 내용");
}
}
}
thread.stNam
public class ThreadB extends Thread{
@Override
public void run() {
for(int i=0;i<2;i++) {
System.out.println(getName() + "가 출력한 내용");
}
}
}
12.3 스레드 우선순위
멀티 스레드는 동시성(Concurrency) 또는 병렬성(Parallelism) 으로 실행되기 때문에 이 용어들에 대해 정확히 이해하는 것이 좋다.동시성은 멀티 작업을 위해 하나의 코어에서 멀티 스레드가 번갈아가며 실행하는 성질을 말하고 , 병렬성은 멀티 작업을 위해 멀티 코어에서 개별 스레드를 동시에 실행하는 성질을 말한다.
스레드의 개수가 코어의 수 보다 많을 경우, 스레드를 어떤 순서에 의해 동시성으로 실행할 것인가를 결정해야 하는데, 이것을 스레드 스케줄링이라고 한다. 스레드 스케줄링에 의해 스레드들은 아주 짧은 시간에 번갈아가면서 그들의 run() 메소드를 조금씩 실행한다.
자바의 스레드 스케줄링은 우선순위(Priority) 방식과 순환 할당(Round-Robin) 방식을 사용한다.우선순위 방식은 우선순위가 높은 스레드가 실행 상태를 더 많이 가지도록 스케줄링하는 것을 말한다. 순환 할당 방식은 시간 할당량(Time Slice)을 정해서 하나의 스레드를 정해진 시간만큼 실행하고 다시 다른 스레드를 실행하는 방식을 말한다.
우선순위 방식에서 우선순위 방식은 우선순위는 1에서부터 10까지 부여되는데 , 1이 가장 우선순위가 낮고 10이 가장 높다.defualt=5
만약 우선순위를 변경하고 싶다면 Thread 클래스가 제공하는 setPriority() 메소드를 이용하면 된다.
public class StatePrintThread extends Thread {
private Thread targetThread;
public StatePrintThread(Thread targetThread) { // 상태를 조사할 스레드
this.targetThread = targetThread;
}
public void run() {
while(true) {
Thread.State state = targetThread.getState(); //스레드 상태 얻기
System.out.println("타겟 스레드 상태: " + state);
if(state == Thread.State.NEW) {//객체 새성 상태일 경우, 실행 대기 상태로 만듬
targetThread.start();
}
if(state == Thread.State.TERMINATED) { //종료 상태일 경우 while문을 종료
break;
}
try {
//0.5초간 일시 정지듬
Thread.sleep(500);
} catch(Exception e) {}
}
}
}
12.스레드 이름"); 11225.으로 변경
public class TargetThread extends Thread {
public void run() {
for(long i=0; i<1000000000; i++) {}
try {
//1.5초간 일시 정지
Thread.sleep(1500);
} catch(Exception e) {}
for(long i=0; i<1000000000; i++) {}
}
}
가
public class ThreadStateExample {
public static void main(String[] args) {
StatePrintThread statePrintThread = new StatePrintThread(new TargetThread());
statePrintThread.start();
}
}
12.6 스레드 상태 제어
실행 중인 스레드의 상태를 변경하는 것을 스레드 상태 제어라고 한다.
12.6.1 주어진 시간동안 일시 정지 sleep()
try{
Thread.sleep(1000);
}catch(InterruptedException e){
//interrupt() 메서드가 호출되면 실행
}
12thread.setN1
import java.awt.Toolkit;
public class SleepExample {
public static void main(String[] args) {
Toolkit toolkit = Toolkit.getDefaultToolkit();
for(int i=0; i<10; i++) {
toolkit.beep();
try {
Thread.sleep(1500); // 1.5초동안 메인 스레드를 일시 정지 상태로 만듭니다
} catch(InterruptedException e) {
}
}
}
}
12.6.2 다른 스레드에게 실행 양보 yield()
public void run() {
while(true) {
if(work) {
System.out.println("Thread1 작업 내용");
}
}
}
스레드가 시작되어 run() 메서드를 실행하면 while(true) {} 블록이 무한 루프를 돌게 됩니다. 만약 work의 값이 false 라면 그리고 work 값이 false 에서 true로 변경되는 시점이 불분명하다면, while문은 어떤한 실행문도 실행하지 않고 무의미한 반복을 한다.
public void run() {
while(true) {
if(work) {
System.out.println("Thread1 작업 내용");
} else {
Thread.yield();
}
}
}
12.6.3 다른 스레드의 종료를 기다림 join()
public class SumThread extends Thread {
private long sum;
public long getSum() {
return sum;
}
public void setSum(long sum) {
this.sum = sum;
}
public void run() {
for(int i=1; i<=100; i++) {
sum+=i;
}
}
}
public class JoinExample {
public static void main(String[] args) {
SumThread sumThread = new SumThread();
sumThread.start();
try {
sumThread.join();
} catch (InterruptedException e) {
}
System.out.println("1~100 합: " + sumThread.getSum());
}
}
12.6.4 스레드 간 협업 wait(), notify(), notifyAll()
public class WorkObject {
public synchronized void methodA() {
System.out.println("ThreadA의 methodA() 작업 실행");
notify();//일시정지상태에 있는 ThreadB를 실행대기상태로 만듬
try {
wait();//ThreadA를 일시 정지 상태로 만듬
} catch (InterruptedException e) {
}
}
public synchronized void methodB() {
System.out.println("ThreadB의 methodB() 작업 실행");
notify();//일시정지상태에 있는 ThreadA를 실행대기상태로 만듬
try {
wait();//ThreadB를 일시 정지 상태로 만듬
} catch (InterruptedException e) {
}
}
}
11ame("1스
public class ThreadA extends Thread {
private WorkObject workObject;
public ThreadA(WorkObject workObject) {
this.workObject = workObject; // 공유 객체를 매개값으로 받아 필드에 저장
}
@Override
public void run() {
for(int i=0; i<10; i++) {
workObject.methodA();
}//공유 객체의 methodA()를 10번 반복
}
}
12.111111
public class ThreadB extends Thread {
private WorkObject workObject;
public ThreadB(WorkObject workObject) {
this.workObject = workObject;// 공유 객체를 매개값으로 받아 필드에 저장
}
@Override
public void run() {
for(int i=0; i<10; i++) {
workObject.methodB();
}//공유 객체의 methodB()를 10번 반복
}
}
thread.
public class WaitNotifyExample {
public static void main(String[] args) {
WorkObject sharedObject = new WorkObject(); // 겅우 객체 생성
ThreadA threadA = new ThreadA(sharedObject);
ThreadB threadB = new ThreadB(sharedObject);
threadA.start();
threadB.start(); 스래드 A,B 실행
}
}
12.6.5 스레드의 안전한 종료 stop플래그, interrupt()
스레드는 자신의 run() 메서드가 모두 실행되면 자동적으로 종료된다.
스레드의 안전한 종료 stop플래그, interrupt()
스레드는 자신의 run() 메서드가 모두 실행되면 자동적으로 종료됩니다.
경우에 따라 실행 중인 스레드를 즉시 종료할 필요가 생길 수 있습니다.
예를 들면 동영상을 끝까지 보지 않고 사용자가 멈춤을 요구할 경우가 있을 수 있습니다.
Thread는 스레드를 즉시 종료시키기 위해 stop()메서드를 제공하지만
이 메서드는 Deprecated되어있습니다.
=>아래 두가지 방법은 스레드를 즉시 종료시키기 위한 최선의 방법입니다.
stop 플래그를 이용하는 방법
public class XXXThread extends Thread {
private boolean stop; // stop 플래그 필드
public void run() {
while(!stop){ stop가 true가 되면 run() 종료
스레드가 반복 실행하는 코드;
}
//스레드가 사용한 자원 정리
}
}
setN112.2a
public class StopFlagExample {
public static void main(String[] args) {
PrintThread1 printThread = new PrintThread1();
printThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
printThread.setStop(true);
}
}
d.setName("스레드 이름"); 으로 변경 가
public class PrintThread1 extends Thread {
private boolean stop;
public void setStop(boolean stop) {
this.stop = stop;
}
public void run() {
while(!stop) {
System.out.println("실행 중");
}
System.out.println("자원 정리");
System.out.println("실행 종료");
}
}
interrupt() 메서드를 이용하는 방법
public class InterruptExample {
public static void main(String[] args) {
Thread thread = new PrintThread2();
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
thread.interrupt();
}
}
public class PrintThread2 extends Thread {
public void run() {
try {
while(true) {
System.out.println("실행 중");
Thread.sleep(1);
}
} catch(InterruptedException e) {
}
System.out.println("자원 정리");
System.out.println("실행 종료");
}
}
12.7 데몬 스레드
데몬(daemon) 주 스레드의 작업 돕는 보조적인 역할 수행하는 스레드이다.
현재 실행 중인 스레드가 데몬 스레드인지 아닌지 구별하는 방법은 isDaemon()메소드의 리턴값을 조사해보면 된다.
public class AutoSaveThread extends Thread {
public void save() {
System.out.println("작업 내용을 저장함.");
}
@Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
save(); // 1초 주기로 save()메서드 호출
}
}
}
public class DaemonExample {
public static void main(String[] args) {
AutoSaveThread autoSaveThread = new AutoSaveThread();
autoSaveThread.setDaemon(true); // 데몬스레드로 만들기
autoSaveThread.start();
try {
Thread.sleep(3000); // 메인 스레드가 종료되면 데몬 스레드도 같이 종료
} catch (InterruptedException e) {
}
System.out.println("메인 스레드 종료");
}
}
Thread t = new Thread(ThreadGroup group, Runnable target);
Thread t = new Thread(ThreadGroup group, Runnable target, String name);
Thread t = new Thread(ThreadGroup group, Runnable target, String name, long stackSize);
Thread t = new Thread(ThreadGroup group, String name);
12.8.3 스레드 그룹의 일괄 interrupt()
스레드 그룹에서 제공하는 interrupt() 메서드를 이용하면 그룹 내에 포함된 모든 스레드들을 일괄 interrupt()할 수 있다.
코드 작성 시에 클래스 이름을 결정할 수 없고, 런타임 시에 클래스 이름이 결정되는 경우에
매우 유용합니다.
아래 코드처럼 Class.forName() 메서드로 Class 객체를 얻음 다음 newInstance()메서드를 호출하면 Object 타입의 객체를 얻을 수 있습니다.
try{
Class clazz = Class.forName("런타임 시 결정되는 클래스의 이름");
Object obj = clazz.newInstance();
}catch(ClassNotFoundException e){
}catch(InstantiationException e){
}catch(IllegalAccessException e){
}
newInstance() 메서드는 기본 생성자를 호출해서 객체를 생성하기 때문에 반드시 클래스에 기본 생성자가 존재해야 합니다. 매개 변수가 있는 생성자를 호출하고 싶다면 리플랙션으로 Constructor 객체를
얻어 newInstance() 메서드를 호출하면 됩니다.
newInstance() 메서드는 두 가지 예외가 발생할 수 있는데,
InstantiationException예외는 해당 클래스가 추상 클래스이거나 인터페이스일 경우에 발생하고,
IllegalAccessException 예외는 클래스나 생성자가 접근 제한자로 인해 접근할 수 없을 경우에
발생합니다. 그렇기에 예외 처리가 필요합니다.
newInstance() 메서드의 리턴 타입은 Object이므로 이것을 원래 클래스 타입으로 변환해야만 메서드를 사용할 수 있습니다. 그렇게 하기 위해 강제 타입 변환을 해야하는데 클래스타입을 모르는 상태이기에 변환을 할 수가 없습니다. 이 문제를 해결하기위해서는 인터페이스의 사용이 필요합니다.
Class clazz = Class.forName("SendAction"또는 "ReceiveAction");
if문의 조건식에서 특정 문자열이 포함되어 있는지 여부에 따라 실행 코드를 달리할 때 자주 사용됩니다. if(문자열.indexOf("찾는문자열") != -1){
//포함되어 있는 경우
}else{
//포함되어 잇지 않는 경우
}
문자열 포함 요부 조사
publicclass StringIndexOfExample {
publicstaticvoid main(String[] args) {
String subject = "자바 프로그래밍";
intlocation = subject.indexOf("프로그래밍");
System.out.println(location);// 자바 프로그래밍에서 "프로그래밍" 문자열의 인덱스 위치 가 3이기 때문에 3을 출력합니다.
if (subject.indexOf("자바") != -1) {
System.out.println("자바와 관련된 책이군요");
} else {
System.out.println("자바와 관련없는 책이군요");
}
}
}
문자열 길이(length()) – 공백도 문자에 포함
문자열이 문자 수 얻기
publicclass StringLengthExample {
publicstaticvoid main(String[] args) {
String ssn = "7306241230123";
intlength = ssn.length();
if (length == 13) {
System.out.println("주민번호 자리수가 맞습니다.");
} else {
System.out.println("주민번호 자리수가 틀립니다.");
}
}
}
문자열 대치(replace())
•첫 번째 매개값인 문자열 찾음
•두 번째 매개값인 문자열로 대치
•새로운 문자열 리턴
replace() 메소드가 리턴하는 문자열은 원래 문자열의 수정본이 아니라 완전한 새로운 문자열이다.
문자열 대치하기
publicclass StringReplaceExample {
publicstaticvoid main(String[] args) {
String oldStr = "자바는 객체지향 언어닙니다.자바는 풍부한 api를 지원합니다.";
String newStr = oldStr.replace("자바", "JAVA");
System.out.println(oldStr);
System.out.println(newStr);
}
}
문자열 잘라내기(substring())
•substring(int beginIndex, int endIndex)
주어진 시작과 끝 인덱스 사이의 문자열 추출
•substring(int beginIndex)
주어진 인덱스 이후부터 끝까지 문자열 추출
문자열 추출하기
publicclass StringSubstringExample {
publicstaticvoid main(String[] args) {
String ssn = "880815-1234567";
String firstNum = ssn.substring(0, 6);
System.out.println(firstNum);
String secondNum = ssn.substring(7);
System.out.println(secondNum);
}
}
알파벳 소∙대문자 변경 (toLowerCase(), toUpperCase())
전부 소문자 또는 대문자로 변경
publicclass StringToLowerUpperExample {
publicstaticvoid main(String[] args) {
String str1= "Java Programming";
String str2= "JAVA Programming";
System.out.println(str1.equals(str2));
String lowerStr1 = str1.toLowerCase();
String lowerStr2 = str2.toLowerCase();
System.out.println(lowerStr1.equals(lowerStr2));
System.out.println(str1.equalsIgnoreCase(str2));
}
}
v문자열 앞뒤 공백 잘라내기(trim())
문자열의 앞뒤 공백을 제거한 새로운 문자열을 생성하고 리턴하는 메서드.
이 메서드는 앞뒤 공백만 제거하고 문자열 사이의 공백은 제거하지 않습니다.
앞뒤 공백 제거
publicclass StringTrimExample {
publicstaticvoid main(String[] args) {
String tel1 = "02";
String tel2 = "123";
String tel3 = "1234";
String tel = tel1.trim() + tel2.trim() + tel3.trim();
System.out.println(tel);
}
}
문자열 변환(valueOf())
•기본 타입의 값을 문자열로 변환
기본 타입 값을 문자열로 변환
publicclass StringValueOfExample {
publicstaticvoid main(String[] args) {
String str1 = String.valueOf(10);
String str2 = String.valueOf(10.5);
String str3 = String.valueOf(true);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
}
}
11.8 StringTokenizer 클래스
문자열이 특정 구분자로 연결되어 있을 경우 구분자를 기준으로 부분 문자열을 분리하기 위해서는 String의 split () 메서드를 사용하거나 StringTokenizer 클래스를 사용할 수 있습니다.
split()은 정규 표현식으로 구분하고, StringTokenizer는 문자로 구분한다는 차이점이 있습니다.
v문자열 분리 방법
§String의 split() 메소드 이용
§java.util.StringTokenizer 클래스 이용
11.8.1 String의 split()
§정규표현식을 구분자로 해서 부분 문자열 분리
§배열에 저장하고 리턴
정규 표현식을 구분자로 해서 문자열을 분리한 후 배열에 저장하고 리턴.
String[] strs = "문자열".split("정규표현식");
문자열 분리
publicclass StringSplitExample {
publicstaticvoid main(String[] args) {
String text = "홍길동&이수홍,박연수,김자바-최명호";
String[] names = text.split("&|,|-"); // 제외하고 싶은 문자열을 |로 구분하여 작성합니다.
for (String name : names) {
System.out.println(name);
}
}
}
11.8.2 StringTokenizer 클래스
문자열이 한 종류의 구분자로 연결되어 있는 경우, 손쉽게 문자열을 분리할 수 있습니다.
StringTokenizer st = new StringTokenizer("문자열","구분자"); 구분자를 생략하면 공백이 기본 구분자가 됩니다.
문자열이 "/"로 구분되어있을 경우 아래처럼 할 수 있습니다. 만약구분자가 생략하면 공백이 기본 구분자가 된다.
nextToken() 메서드로 토큰을 하나 꺼내오면 StringTokenizer 객체에는 해당 토큰이 없어집니다.
StringTokenizer 객체에서 더 이상 가져올 토큰이 없다면 nextToken() 메서드는 java.util.NoSuchElementException 예외를 발생시킵니다. 그렇기 때문에 nextToken() 메서드를 사용하기 전에 hasMoreTokens() 메서드로 꺼내올 토큰이 있는지 여부를 조사한 후 nextToken() 메서드를 호출하는 것이 좋은 코딩 방법입니다.
StringTokenizer로 토큰 분리하기
publicclass StringTokenizerExample {
publicstaticvoid main(String[] args) {
String text = "티스토리/블로그/알통몬";
//how1: 전체 토큰 수를 얻어 for문으로 루핑
StringTokenizer st = new StringTokenizer(text,"/");
intcountTokens = st.countTokens();
for(inti = 0; i <countTokens ; i++) {
String token = st.nextToken();
System.out.println(token);
}
System.out.println();
//how2:남아 있는 토큰을 확인하고 while문으로 루핑
st= new StringTokenizer(text,"/");
while(st.hasMoreTokens()) {
String token = st.nextToken();
System.out.println(token);
}
}
}
11.9.StringBuffer, StringBuilder 클래스
v문자열 결합 연산자 +
String 은 내부의 문자열 수정 불가 -> 대치된 새로운 문자열 리턴
문자열을 변경하는 작업이 많을 경우 String 클래스를 사용하는 것보다는
java.lang 패키지의 StringBuffer 또는 StringBuilder 클래스를 사용하는 것이 좋습니다.
이 두 가지 클래스는 내부 버퍼에 문자열을 저장해 두고, 그 안에서 추가, 수정, 삭제 작업을 할 수 있도록 설계되어 있습니다.
문자열을 결합하는 + 연산자를 많이 사용할 수 록 그만큼 String 객체의 수가 늘어나기 때문에 .프로그램 성능을 느리게 하는 요인이 된다.
vStringBuffer, StringBuilder (p.514~516)
버퍼(buffer:데이터를 임시로 저장하는 메모리)에 문자열 저장
버퍼 내부에서 추가, 수정, 삭제 작업 가능
멀티 스레드환경: StringBuffer 사용 동기화가 적용되어 있어 스래드에 안전하지만
단일 스레드환경: StringBuilder 사용
StringBuilder 클래스 ->버퍼 크기를 늘린다.
몇 가지 생성자를 제공합니다. 기본 생서자인StringBuilder()는 16개 문자들을 저장할 수 있는 초기 버퍼를 만들고, StringBuilder(int capacity) 생성자는 capacity 로 주어진 개수만큼 문자들을 저장할 수 있는 초기 버퍼를 만듭니다. 그리고 StringBuilder는 버퍼가 부족할 경우 자동적으로 버퍼의 크기를 늘리기 떄문에 초기 버퍼의 크기는 크게 중요하지 않습니다. StringBuilder(String str) 생성자는 str로 주어진 매개값을 버퍼의 초기값으로 저장합니다.
append() 와 insert() 메서드는 매개 변수가 다양한 타입으로 오버로딩되어 있기 때문에 대부분의 값을 문자로 추가 또는 삽입할 수 있습니다.
StringBuilder에서 문자열 조작
publicclass StringBuilderExample {
publicstaticvoid main(String[] args) {
//StringBuilder 객체 생성
StringBuilder sb = new StringBuilder();
//문자열을 끝에 추가
sb.append("Java ");
sb.append("Program Stude");
System.out.println(sb.toString());
//index4위체에 2를 삽입
sb.insert(4,"2");
System.out.println(sb.toString());
//index4위치의 문자를 6으로 변경
sb.setCharAt(4, '6');
System.out.println(sb.toString());
//index6부터 index13 '전'까지를 'Book'문자열로 대치
sb.replace(6, 13, "Book");
System.out.println(sb.toString());
//index4ㅇ부터 index '전'까지 삭제
sb.delete(4, 5);
System.out.println(sb.toString());
// 총 문자수 얻기
intlength= sb.length();
System.out.println("총문자수: "+length);
//버퍼에 있는 것을 String 타입으로 리턴
String result = sb.toString();
System.out.println(result);
}
}
11.10 정규 표현식과 Pattern 클래스
문자열이 정해져 있는 형식(정규 표현식)으로 구성되어 있는지 검증해야 하는 경우가 있습니다.
이메일이나 전화변호를 사용자가 제대로 입력했는지 검증해야 할 때 정규 표현식과 비교합니다.
문자열이 정해져 있는 형식으로 구성되어 있는지 검증할 때 사용
Ex) 이메일, 전화번호, 비밀번호 등
11.10.1 정규 표현식(Regular Expression) 작성 방법
문자 또는 숫자 기호와 반복 기호가 결합된 문자열
java.util.regex.Pattern클래스를 찾아 Summary of regualr-expression construct를 참조하면 되는데 이해하기가 어렵지 않다.
(02|010)-\d{3,4}-\d{4}는 전화번호를 위한 정규 표현식입니다.
그리고
\w+@\w+\.\w+(\.\w+)? 이건
rain483@naver.com 과 같은 이메일을 위한 정규 표현식입니다.
주의할 점은 \. 과 . 은 다릅니다. \.은 점(.)을 말하고 .은 모든 문자 중에서 한 문자를 뜻합니다.
11.10.2 Pattern 클래스
정규 표현식으로 문자열을 검증하는 역할
결과는 boolean 타입 !!!
문자열을 정규 표현식으로 검증하는 기능은 java.util.regex.Pattern 클래스의 정적 메서드인 matches() 메서드가 제공합니다.
문자열 검증하기
publicclass PatternExample {
publicstaticvoid main(String[] args) {
String regExp = "(02|010)-\\d{3,4}-\\d{4}";
String data = "010-123-4567";
booleanresult = Pattern.matches(regExp, data);
if (result) {
System.out.println("정규식과 일치합니다.");
} else {
System.out.println("정규식과 일치하지 않습니다.");
}
regExp = "\\w+@\\w+\\.\\w+(\\.\\w+)?";
data = "rain483@navercom";
result = Pattern.matches(regExp, data);
if (result) {
System.out.println("정규식과 일치합니다.");
} else {
System.out.println("정규식과 일치하지 않습니다.");
}
}
}
11.11 Arrays 클래스
배열 조작 기능을 가지고 있는 클래스 - 배열 복사, 항목 정렬, 항목 검색
제공하는 정적 메소드
배열 조작 기능을 가지고 있습니다.
배열 조작이란 : 배열의 복사, 항목 정렬, 항목 검색과 같은 기능.
단순한 배열의 복사는 System.arrayCopy() 메서드를 사용할 수 있지만,
Arrays는 추가적으로 항목 정렬, 항목 검색, 항목 비교와 같은 기능을 제공해 줍니다.
전부 static 메서드이므로 Arrays 클래스로 바로 사용이 가능합니다.
11.1.1 배열 복사
•Arrays.copyOf(원본배열, 복사할 길이)
0 ~ (복사할 길이-1)까지 항목 복사
복사할 길이는 원본 배열의 길이보다 커도 되며 타겟 배열의 길이
•copyOfRange(원본 배열, 시작 인덱스, 끝 인덱스)
시작인덱스 ~ (끝 인덱스-1)까지 항목 복사
•System.arraycopy()
단순히 배열을 복사할 목적으로 사용하는 System.arraycopy()메서드와 위 메서드들의 사용 에제를 보겠습니다.System.arraycopy()메서드는 5개의 매개 값이 필요합니다.
System.arraycopy(Object o, int start, Object o2, int end, int length)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(sdf.format(now));
sdf = new SimpleDateFormat("yyyy년 MM월 dd일");
System.out.println(sdf.format(now));
sdf = new SimpleDateFormat("yyyy.MM.dd a HH:mm:ss");
System.out.println(sdf.format(now));
sdf = new SimpleDateFormat("오늘은 E요일");
System.out.println(sdf.format(now));
sdf = new SimpleDateFormat("올해의 D번째 날");
System.out.println(sdf.format(now));
sdf = new SimpleDateFormat("이달의 d번째 날");
System.out.println(sdf.format(now));
}
}
11.15.3 매개변수화 된 문자열 형식 클래스(MessageFormat)
데이터를 파일에 저장하거나, 네터워크로 전송할 때, 또는 데이터베이스 SQL 문을 작성할 때
등 많은 부분에서 일정한 형식의 문자열을 사용합니다. MessageFormat 클래스를 사용하면 문자열에 데이터가 들어갈 자리를 표시해 두고, 프로그램이 실행하면서 동적으로 데이터를 삽입해 문자열을 완성시킬 수 있습니다.예를 들어서 아래와 같은 회원 정보를 출력한다고 하면,
userId : blue
userName : 신용권
userTel : 010-123-1234
userId, userName, userTel 이라는 변수에 회원 정보가 저장되어 있다면, 아래와 같은 + 연산자로 출력할문자열을 생성할 수 있을 것입니다.
만약 다른 포맷터를 이용해서 문자열을 파싱하고 싶다면 parse(CharSequence, DateTimeFormatter)메서드를 사용할 수 있습니다. DateTimeFormatter는 ofPattern() 메서드로 정의할 수도 있는데 아래 코드는 "2024.05.31" 형식의 DateTimeFormatter를 정의하고 문자열을 파싱합니다.
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 M월 d일 a h시 m분");
String nowString = now.format(dateTimeFormatter);
System.out.println(nowString);
}
}
확인문제
1. Object 클래스에 대한 설명 중 틀린 것은 무엇입니까?
* 1. 모든 자바 클래스의 최상위는 부모 클래스이다.
* 2. Object의 equals() 메소드는 == 연산자와 동일하게 번지를 비교한다.
* 3. Object의 clone() 메소드는 얕은 복사를 한다.
* 4. Object의 toString() 메소드는 객체의 필드값을 문자열로 리턴한다.
*(X, Object의 toString은 객체의 생성번지를 이용해서 해시코드를 만든다음에, 그 해시코드의 문자열을 리턴하도록 되어있다.
*기본적으로 형식은 "클래스명@16진수해시코드" 로 구성된 문자 정보를 리턴하도록 되어있다.)
true
같음
2.여러분이 작성하는 클래스를 동등 비교하는 컬렉션 객체인 HashSet, HashMap, Hashtable을 사용하려고 합니다.Object의 equals()와 hashCode()메소드를 오버라이딩 했다고 가정할 경우 , 메소드 호출 순서를 생각하고 다음 괄호 ()안을 채워보세요
3. Student 클래스를 작성하되 Object의 equals() 와 hashCode()를 오버라이딩 해서 Student의 학번(studentNum) 이 같으면 동등객체가 될 수 있도록 해보세요. Student 클래스의 필드는 다음과 같습니다. hashCode()의 리턴 값은 studentNum 필드값의 해시코드를 리턴하도록 하세요.
package textbook.chapter11.excersize;
publicclass Student {
private String studentNum;
public Student(String studentNum) {
this.studentNum = studentNum;
}
public String getStudentNum() {
returnstudentNum;
}
@Override
publicboolean equals(Object object) {
if(objectinstanceof Student) {
Student student = (Student) object;
if(studentNum.equals(student.getStudentNum())) {
returntrue;
}
}
returnfalse;
}
@Override
publicint hashCode() {
returnstudentNum.hashCode();
}
}
package textbook.chapter11.excersize;
import java.util.HashMap;
publicclass StudentExample {
publicstaticvoid main(String[] args) {
//student키로 충점을 저장한느 HashMap 객체 생성
HashMap<Student, String> hashMap = new HashMap<>();
public class CatchByExceptionKindExample {
public static void main(String[] args) {
try {
String data1 = args[0];
String data2 = args[1];
int value1 = Integer.parseInt(data1);
int value2 = Integer.parseInt(data2);
int result = value1 + value2;
System.out.println(data1 + "+" + data2 + "=" + result);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("실행 매개값의 수가 부족합니다.");
System.out.println("[실행 방법]");
System.out.println("java CatchByExceptionKindExample num1 num2");
} catch (NumberFormatException e) {
System.out.println("숫자로 변환할 수 없습니다.");
} finally {
System.out.println("다시 실행하세요.");
}
}
}
실행 매개값의 수가 부족합니다.
[실행 방법]
java CatchByExceptionKindExample num1 num2
다시 실행하세요.
10.4.2 catch 순서
상위 예외 클래스가 하위 예외 클래스보다 아래쪽에 위치해야 한다.
차례대로 검색된다.
public class CatchOrderExample {
public static void main(String[] args) {
try {
String data1 = args[0];
String data2 = args[1];
int value1 = Integer.parseInt(data1);
int value2 = Integer.parseInt(data2);
int result = value1 + value2;
System.out.println(data1 + "+" + data2 + "=" + result);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("실행 매개값의 수가 부족합니다.");
} catch (Exception e) {
System.out.println("실행에 문제가 있습니다.");
} finally {
System.out.println("다시 실행하세요.");
}
}
}
실행 매개값의 수가 부족합니다.
다시 실행하세요.
10.4.3 멀티 catch
| 로 연결하면 된다.
public class MultiCatchExample {
public static void main(String[] args) {
try {
String data1 = args[0];
String data2 = args[1];
int value1 = Integer.parseInt(data1);
int value2 = Integer.parseInt(data2);
int result = value1 + value2;
System.out.println(data1 + "+" + data2 + "=" + result);
} catch (ArrayIndexOutOfBoundsException|NumberFormatException e) {
System.out.println("실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.");
} catch (Exception e) {
System.out.println("알수 없는 예외 발생");
} finally {
System.out.println("다시 실행하세요.");
}
}
}
실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.
다시 실행하세요.
10.5 자동 리소스 닫기
자바 7에서 새로 추가된 try-with-resources를 사용하면 예외 발생 여부와 상관없이 사용했던 리소스 객체(각종 입출력 스트림,서버소켓,소켓,각종 채널)의 close() 메소드를 호출해서 안전하게 리소스를 닫아준다.
리소스란 여러 가지 의미가 있겠지만 여기서는 데이터를 읽고 쓰는 객체라고 생각한다.
try-with-resources를 사용하기 위해서는 조건이 있다
리소스 객체는 java.lang.AutoCloseable 인터페이스를 구현하고 있어야 한다.
public class FileInputStream implements AutoCloseable{
private String file;
public FileInputStream(String file) {
this.file =file;
}
public void read() {
System.out.println(file + "을 읽습니다.");
}
@Override
public void close() throws Exception {
System.out.println(file + "을 닫습니다.");
}
}
public class TryWithResourceExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("file.txt")) {
fis.read();
throw new Exception(); // 강제적으로 예외 발생
} catch (Exception e) {
System.out.println("예외 처리 코드가 실행되었습니다.");
}
}
}
file.txt을 읽습니다.
file.txt을 닫습니다.
예외 처리 코드가 실행되었습니다.
10.6 예외 떠넘기기
메소드 내부에서 예외가 발생할 수 있는 코드를 작성할 때 try-catch 블록으로 예외를 처리하는 것이 기본이지만, 경우에 따라서는 메소드를 호출한 곳으로 예외를 떠넘길 수도 있다. 이때 사용 하는 키워드가 throws이다.
throws 키워드는 메소드 선언부 끝에 작성되어 메소드에서 처리하지 않은 예외를 호출한 곳으로 떠넘기는 역할을 한다.
다음 예제에서 Class.forName() 메소드를 사용하는 findClass() 메소드는 예외를 떠넘겼고, findClass()를 호출하는 main() 메소드에서 try-catch 블록을 사용해서 예외 처리를 했다.
public class ThrowsExample {
public static void main(String[] args) {
try {
findClass();
} catch (ClassNotFoundException e) {
System.out.println("클래스가 존재하지 않습니다.");
}
}
public static void findClass() throws ClassNotFoundException {
Class clazz = Class.forName("java.lang.String2");
}
}
클래스가 존재하지 않습니다.
10.7 사용자 정의 예외와 예외 발생
10.7.1 사용자 정의 예외 클래스 선언
일반 예외로 선언시 Exception을 상속하면 되고 , 실행 예외로 선언시 RuntimeException을 상속하면 된다.
public class BalanceInsufficientException extends Exception{
public BalanceInsufficientException() { }
public BalanceInsufficientException(String message) {
super(message);
}
}
10.7.2 예외 발생시키기
다음 예제는 은행 계좌 (Account) 클래스를 작성한 것이다. 출금(withdraw) 메소드에서 잔고(balance) 필드와 출금액을 비교해서 잔고가 부족하면 BalanceInsufficientException을 발생 시키도록 했다.
public class Account {
private long balance;
public Account() { }
public long getBalance() {
return balance;
}
public void deposit(int money) {
balance += money;
}
public void withdraw(int money) throws BalanceInsufficientException { //사용자 예외 떠넘기기
if(balance < money) {
throw new BalanceInsufficientException("잔고부족:"+(money-balance)+" 모자람"); //사용자 정의 예외 발생
}
balance -= money;
}
}
10.8 예외 정보 얻기
public class AccountExample {
public static void main(String[] args) {
Account account = new Account();
//예금하기
account.deposit(10000);
System.out.println("예금액: " + account.getBalance());
//출금하기
try {
account.withdraw(30000);
} catch (BalanceInsufficientException e) { //예외 메시지 얻기
String message = e.getMessage();
System.out.println(message);
System.out.println(); //예외 추적 후 출력
e.printStackTrace();
}
}
}
7. 로그인 기능을 Member 클래스의 login () 메소드에서 구현하려고 합니다. 존재하지 않는 ID를 입력했을 경우 NotExistIDException을 발생시키고, 잘못된 패스워드를 입력했을 경우 WrongPasswordException을 발생시키려고 합니다. LoginExample의 실행 결과를 보고 빈칸을 채워보세요.