반응형
반응형
package multi_thread;

import java.awt.Toolkit;

public class ThreadPriority {

	public static void main(String[] args) {
		
		// 방법1
		Thread thread = new BeepThread();
		thread.start();

		thread.setPriority(Thread.MAX_PRIORITY); // 우선순위 10
		thread.setPriority(Thread.NORM_PRIORITY); // 우선순위 5
		thread.setPriority(Thread.MIN_PRIORITY); // 우선순위 1
		
		// 방법2 (익명 객체를 이용한 방법)
		/*
		Thread thread2 = new Thread() {
			public void run() {
				Toolkit toolkit = Toolkit.getDefaultToolkit();
				for(int i = 0 ; i < 5 ; i++) {
					toolkit.beep();
					try {Thread.sleep(500);} catch(Exception e) {}
				}
			}
		};
		thread2.start();
		*/
		
		for (int i = 0 ; i < 5 ; i++) {
			System.out.println("띵");
			try {Thread.sleep(500);} catch(Exception e) {}
		}

	}

}

위는 저번에 했던 예제를 그냥 가져왔습니다. 이번 내용은 큰 실습내용이 없기 때문입니다.


멀티스레드가 병렬적으로 실행되는 거라고 했는데 실제로는 번갈아가면서 실행하는 작업입니다.

자바에서 스레드 스케줄링은 우선순위(Priority) 방식과 순환 할당 (Round-Robin) 방식을 사용합니다.
우선순위가 높은 스레드가 실행 상태를 더 많이 가져가게 되는 것이소
시간 할당량(Time slice)를 정해서 하나의 스레다가 정해진 시간만큼 실행 하고 다른 스레드를 실행하는 방식입니다.

thread.setPriorty(우선순위); 를 이용해 우선순위를 정해줄 수 있습니다.
1 ~ 10까지 값이 들어갑니다. 기본적으로 모든 스레드는 5 우선순위를 할당 받습니다.
1은 가장 낮고 10이 가장 높습니다.

우선순위는 최소한 5개 이상의 스레드가 실행 되어야 우선순위의 영향을 받습니다.

thread.setPriority(Thread.MAX_PRIORITY)
thread.setPriority(Thread.NORM_PRIORITY)
thread.setPriority(Thread.MIN_PRIORITY)

 

이런식으로 10 5 1이라는 숫자를 대신 넣을 수 있습니다.

MAX는 가장 큰 수라는 의미 10 NORM은 평균이라는 의미 5 MIN은 가장 적은 수라는 의미 1을 의미합니다.

반응형
반응형
package multi_thread;

public class SetAndGetThread extends Thread{
	public SetAndGetThread() {
		setName("ThreadA");
	}
	
	public void run() {
		for(int i = 0 ; i < 2 ; i++) {
			System.out.println(getName() + "가 출력한 내용");
		}
	}
}

생성자setName을 이용해 스레드 이름을 설정할 수 있습니다.

그리고 getName으로 스레드의 이름을 가져올 수 있습니다.

 

이번엔 귀찮아서 메인스레드는 안 만들었습니다.

반응형
반응형
package multi_thread;

import java.awt.Toolkit;

public class BeepThread extends Thread {
	@Override
	public void run() {
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		for(int i = 0 ; i < 5 ; i++) {
			toolkit.beep();
			try {Thread.sleep(500);} catch(Exception e) {}
		}
	}
}
package multi_thread;

import java.awt.Toolkit;

public class BeepPrintExample2 {

	public static void main(String[] args) {

		// 기존 방법
        // Runnable beepTask = new BeepTask(); // Runnable 상속 받은 BeepTask 클래스
		// Thread thread = new Thread(beepTask);

		// 방법1 (Runnable 객체 선언 후 Injection 안 해줘도 된다.
		Thread thread = new BeepThread();
		thread.start();
        

		
		// 방법2 (익명 객체를 이용한 방법)
		/*
		Thread thread2 = new Thread() {
			public void run() {
				Toolkit toolkit = Toolkit.getDefaultToolkit();
				for(int i = 0 ; i < 5 ; i++) {
					toolkit.beep();
					try {Thread.sleep(500);} catch(Exception e) {}
				}
			}
		};
		thread2.start();
		*/
		
		for (int i = 0 ; i < 5 ; i++) {
			System.out.println("띵");
			try {Thread.sleep(500);} catch(Exception e) {}
		}

	}

}

Runnable을 이용하지 않고 Thread의 하위 클래스로 스레드를 정의하면서 작업 내용을 포함 시킬 수도 있습니다.

 

extends로 Thread를 받고 run() 안에 스레드 실행할 코드를 정의합니다.

아니면 저번에 한 거 처럼 익명객체로 이용해 클래스 생성하지 않고 사용할 수 있습니다.

 

Thread thread = new BeepThread();

 

Thread를 상속 받는 BeepThread하위 클래스 입니다.

큰 Thread에 담게 되는 것이죠 Runnable역할을 해주면서 코드를 더 줄일 수 있습니다.

 

반응형
반응형
package multi_thread;

import java.awt.Toolkit;

public class BeepTask implements Runnable{
	public void run() {
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		for(int i = 0 ; i < 5 ; i++) {
			toolkit.beep();
			try {Thread.sleep(500);} catch(Exception e) {}
			}
		}
	}
package multi_thread;

import java.awt.Toolkit;

public class BeepPrintExample {

	public static void main(String[] args) {
		
		// 방법 1
		Runnable beepTask = new BeepTask(); // Runnable 상속 받은 BeepTask 클래스
		Thread thread = new Thread(beepTask);
		thread.start();

		// 방법 2 (익명 객체 이용)
		/* 
		Thread thread2 = new Thread(new Runnable() {
			@Override
			public void run() {
				Toolkit toolkit = Toolkit.getDefaultToolkit();
				for(int i = 0 ; i < 5 ; i++) {
					toolkit.beep();
					try {Thread.sleep(500);} catch(Exception e) {}
					}
				}
			});
		thread2.start();
		*/
		
		for (int i = 0 ; i < 5 ; i++) {
			System.out.println("띵");
			try {Thread.sleep(500);} catch(Exception e) {}
		}
		
		
	}
}

스레드하나를 실행시키는 역할을 하는 것을 의미합니다. 

(말이 하나지 100개의 업무를 한 사람이 하는 거라고 생각하시면 됩니다.)

(예를 들어 자바를 실행시키면 메인스레드만 돌아감)

 

멀티스레드란 여러개를 동시에 실행 시킬 수 있게 만들어서 병렬적으로 처리할 수 있는 것이죠

병렬적으로 처리하면 여러개의 일을 분담하니 효율적이겠죠?


메인 스레드가 작업스레드보다 먼저 종료되더라도

다른 스레드가 계속 실행중이라면 프로세스는 종료되지 않는 특징이 있습니다.

Runnable작업 스레드가 실행 할 수 있는 코드가지고 있는 객체라고 해서 붙여진 이름입니다.
인터페이스 타입이기 때문에 구현 객체를 만들어 대입해야한다. run()을 재정의해서 실행할 코드를 적어야합니다.

class Task implements Runnable{
	public void run(){
		실행할 자바코드
	}
}

이런 식이 기본 구조입니다. 

 

위에 예제는 컴퓨터에서 띵소리를 내게 하는 toolkit이라는 걸을 이용해 소리를 내면서

그와 동시에 for문을 이용해 띵이라는 걸 출력해보려고 합니다. 그러면 두개가 동시에 작동해야 겠죠?

 

public class BeepTask implements Runnable{
	public void run() {
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		for(int i = 0 ; i < 5 ; i++) {
			toolkit.beep();
			try {Thread.sleep(500);} catch(Exception e) {}
			}
		}
	}

 

run안에 스레드 내용에는 toolkit.beep()이 0.5초의 간격을두고 5번 반복하게 끔 만들었습니다.

 

beepTask라는 객체를 만듭니다.

또한 Runnable내용을 실행시킬 스레드만듭니다.(thread)

그리고 Runnable 내용을 그 안에 넣습니다. ( Thread thread = new Thread(beepTask) ) 선언과 Runnable 내용 넣기

thread.start로 Thread를 실행시킵니다.

 

이러면 메인 Thread에서는 이걸 일 하고 다른 스레드에서는 컴퓨터에서 띵소리를 내게하는 일을 합니다. (병렬)

 

Runnable을 상속받는 클래스를 만들어서 쓰는 위에 방법과 그렇지 않고 바로 메인쓰레드에서 선언과 동시에

쓰는 익명 객체를 이용하는 방식이 있습니다.

익명 객체란 일회성이고 파일을 줄일 수 있는 장점이 있습니다. 자세한 건 나중에 포스팅하겠습니다.

 

Thread thread2 = new Thread (new Runnable() {
    @Override
    public void run() {
        스레드내용
    }
});

이러한 구조가 됩니다. Thread 매개변수에는 Runnable객체가 들어가야하는데 그걸 밑에 바로 정의시켜주는 것이죠

 

반응형
반응형
package error_throws;

public class Calculator {
	
	public static int add (int x, int y) throws 천을_넘는_예외, 음수가_되는_예외 {
		int result = x + y;
		if(result > 1000) {
			throw new 천을_넘는_예외();
			// throw new NullPointerException();
		}
		
		if(result < 0) {
			throw new 음수가_되는_예외();
		}
		return x + y;
	}
}
package error_throws;

public class 음수가_되는_예외 extends Exception {
	
	@Override
	public String getMessage() {
		return "입력 값이 음수인 오류가 발생했습니다.";
	}
	
}
package error_throws;

public class 천을_넘는_예외 extends Exception {
	
}​
package error_throws;

public class ErrorThrows {
	

	public static void main(String[] args) {
	
		Calculator calc = new Calculator();
		int result = 0;
		// result = Calculator.add(6, 4); 예외처리를 해줘야한다.
		try {
			result = Calculator.add(-6, 4);
			
		}catch(음수가_되는_예외 e) {
			System.out.println(e.getMessage());
			System.out.println("음수가 발생 되었습니다.");
		}catch(천을_넘는_예외 e) {
			
		}
		System.out.println("add : " + result);
	}
}

컴파일하기 전에 빨간줄이 그어지는 에러가 있고 그렇지 않은 것이 있는데요 만약 값이 제대로 안 넘어갈 경우

컴파일은 됐지만 NullPointException이라는 에러가 나오게 됩니다. 이러한 것들을 처리하기 위해서 저번에

try catch문을 썼는데요 그걸 이제 더 발전 시켜서 사용해보려고 합니다.

 

더하기 계산 기능을 넣으려고 합니다. 

	public static int add (int x, int y) throws 천을_넘는_예외, 음수가_되는_예외 {
		int result = x + y;
		if(result > 1000) {
			throw new 천을_넘는_예외();
			// throw new NullPointerException();
		}
		
		if(result < 0) {
			throw new 음수가_되는_예외();
		}
		return x + y;
	}

static으로 선언해 주세요 throws는 신경 쓰지마시고 저희가 임의로 에러를 만드려고 합니다.

1000이라는 합이 나오면 에러가 나오도록 그리고 합이 음수가 나오면 에러가 나오도록 하려고 합니다.

 

throw new라는 건 에러를 강제로 발생시키는 것입니다. 

여기에서 우리가 만든 걸 쓸 수도 원래 있는 에러를 넣을수도 있습니다.

throw new 천을_넘는_예외(); 이런식으로 하면 천을_넘는_예외를 만들라고 빨간줄이 그어집니다.

가져다대시고 class를 만든다를 클릭해서 만들어주세요

 

package error_throws;

public class 천을_넘는_예외 extends Exception {
	
}

이렇게 만들어지게 됩니다.

 

이 클래스에서는 에러를 처리해주는 역할을 해줍니다. 어떤식으로 메세지를 반환할지 등...

아무것도 안 적을 수도 있습니다.

 

그리고 throws를 추가해줘야합니다.

public static int add (int x, int y) throws 천을_넘는_예외, 음수가_되는_예외 {
....

throws란 무엇이냐면 던진다는 뜻인데 s라서 여러개를 던질 수 있게 한다는 의미입니다.

여기에선 2개를 넘기도록 되어있는데 이게 어디로 던지냐고한다면 해당 에러가 발생한다면

예를 들어 result가 1000이 넘어가서 예외가 발생하면 그걸

위에 천을_넘는_예외라는 클래스에서 처리하겠다는 의미입니다.

 

package error_throws;

public class 음수가_되는_예외 extends Exception {
	
	@Override
	public String getMessage() {
		return "입력 값이 음수인 오류가 발생했습니다.";
	}
	
}

또한 예외 메세지를 넘길 때 이러한 방법으로도 넘길 수 있습니다.

getMessage()를 오버라이드 해서 사용 가능합니다.

	try {
			result = Calculator.add(-6, 4);
			
		}catch(음수가_되는_예외 e) {
			System.out.println(e.getMessage());
			System.out.println("음수가 발생 되었습니다.");
		}catch(천을_넘는_예외 e) {
			
		}

getMessage()를 통해서 메세지를 출력할수도 있고

저번에 try catch에서 한 거처럼 catch문에다가 에러처리를 할 수도 있습니다.

반응형
반응형
package nesting_interface_class.nesting_interface;

public class Button {
	
	OnClickListener listener; // 인터페이스 타입 필드
	
	void setOnClickListner(OnClickListener listener) {
		this.listener = listener;
	}

	void touch() {
		listener.onClick();
	}
	
	interface OnClickListener{ // 중첩 인터페이스
		void onClick();
	}
}
package nesting_interface_class.nesting_interface;

public class CallListener implements Button.OnClickListener{
	
	@Override
	public void onClick() {
		System.out.println("전화를 겁니다.");
	}
}​
package nesting_interface_class.nesting_interface;

public class MessageListener implements Button.OnClickListener{

	@Override
	public void onClick() {
		System.out.println("메시지를 보냅니다.");
	}
}
package nesting_interface_class.nesting_interface;

public class ButtonExample {

	public static void main(String[] args) {
		
		Button btn = new Button();
		
		btn.setOnClickListner(new CallListener());
		btn.touch();
		
		btn.setOnClickListner(new MessageListener());
		btn.touch();
	}

}

 

클래스 내부안에 선언한 인터페이스
주로 UI프로그래밍에서 이벤트 처리할 목적으로 사용 됩니다.

Button 이라는 클래스 안에 OnClickListener라는 인터페이스가 있고 무조건 구현해야하는 onClick 메소드가 있습니다.

 

void touch() 와 void setOnClickListener는 listener라고 선언한 인터페이스 타입 필드에 값이 들어갔을 때 

사용할 메소드입니다.

 

btn.setOnClickListner(new CallListener());
btn.setOnClickListner(new MessageListener());

이렇게 인터페이스를 상속받은 클래스를 넣는 것입니다. 그러면 각각 클래스에서 구현한 interface부분 메소드

다르게 출력이 되는 것입니다.

 

 

반응형
반응형
package nesting_interface_class;

public class NestingClassA {
	int aField = 5;
	void aMethod1() {};
	
	static int aField2 = 10;
	static void aMethod2() {};
	
    class NestingClassB{
		NestingClassB() {} 	// 생성자
		int field1; // 인스턴스 필드
		// static int field2; // 정적 필드 사용불가(x)
		void method1() { System.out.println("중첩 클래스B");} // 인스턴스 메소드
		// static void method2() {} // 정적 메소드 사용불가(x)
		
		void method2() {
			class NestingClassD { // *로컬 클래스*
				NestingClassD() {} 	// 생성자
				int field1;	// 인스턴스 필드
				// static int field2;	// 정적 필드 사용불가(x)
				void method1() {System.out.println("로컬 클래스");} // 인스턴스 메소드
				// static void method2() {}	// 정적 메소드 사용불가(x)
			}
			NestingClassD  D = new NestingClassD();
			D.field1 =3 ;
			D.method1();
		}
		
		// 멤버 클래스 에서 사용 제한 가능 여부
		void callA () {
			aField = 10; // A 인스턴스 필드
			aMethod1();  // A 인스턴스 메소드
			
			aField2 = 10; // A 정적 필드
			aMethod2(); // A 정적 메소드
			

			NestingClassA.this.aMethod1();  // 바깥 클래스 메소드 참조 (A 인스턴스 메소드)
			NestingClassA.this.aField = 10; // 바깥 클래스 필드 참조 (A 인스턴스 필드)
			this.field1 = 10; // 현재 클래스의 필드 참조 (B 인스턴스 필드)
			this.method1();	// 현재 클래스의 메소드 참조 (B 인스턴스 메소드)
		}
	}
	
	static class NestingClassC{
		NestingClassC() {};  // 생성자
		int field1; // 인스턴스 필드
		static int field2; // 정적 필드
		void method1() {System.out.println("중첩 클래스C");}; // 인스턴스메소드
		static void method2() {System.out.println("static 중첩 클래스C");}; // 정적 메소드
		
		void callA () {
			// aField = 10; // A 인스턴스 필드 사용불가(x)
			// aMethod1(); // A 인스턴스 메소드 사용불가(x)
			
			aField2 = 10; // A 정적 필드
			aMethod2();	// A 정적 메소드
		}
	}
}
package nesting_interface_class;

public class NestingClass {

	public static void main(String[] args) {
		
		NestingClassA A = new NestingClassA();
		NestingClassA.NestingClassB B = A.new NestingClassB();				
		B.field1 = 3; // 인스턴스 필드
		B.method1(); // 인스턴스 메소드
		
		NestingClassA.NestingClassC C = new NestingClassA.NestingClassC();
		C.field1 =3; // 인스턴스 필드
		C.method1(); // 인스턴스 메소드
		NestingClassA.NestingClassC.field2 = 3; // 정적 필드
		NestingClassA.NestingClassC.method2(); // 정적 메소드
	}

}


클래스 내부에 선언한 클래스입니다.
두 클래스의 멤버들을 서로 쉽게 접근할 수 있다는 특징과
클래스를 감춤으로서 코드의 복잡성을 줄일 수 있다는 특징을 가지고 있습니다.

멤버클래스도 하나의 클래스이기 때문에 컴파일하면 바이트 코드파일이 별도로 생성됩니다.

 

NestingClassA A = new NestingClassA();
NestingClassA.NestingClassB B = A.new NestingClassB();				
B.field1 = 3; // 인스턴스 필드
B.method1(); // 인스턴스 메소드

먼저 A객체(바깥클래스)를 생성후 B객체(내부클래스)를 생성해야 합니다.

 

static class NestingClassC{
		NestingClassC() {};  // 생성자
		int field1; // 인스턴스 필드
		static int field2; // 정적 필드
		void method1() {System.out.println("중첩 클래스C");}; // 인스턴스메소드
		static void method2() {System.out.println("static 중첩 클래스C");}; // 정적 메소드
		
		void callA () {
			// aField = 10; // A 인스턴스 필드 사용불가(x)
			// aMethod1(); // A 인스턴스 메소드 사용불가(x)
			
			aField2 = 10; // A 정적 필드
			aMethod2(); // A 정적 메소드
		}

또한 내부 클래스를 static으로 만든 경우에만 static으로 필드나 메소드를 정의할 수 있습니다.

 

  class NestingClassB{
  	...
    void callA () {
        aField = 10; // A 인스턴스 필드
        aMethod1();  // A 인스턴스 메소드

        aField2 = 10; // A 정적 필드
        aMethod2(); // A 정적 메소드


        NestingClassA.this.aMethod1();  // 바깥 클래스 메소드 참조 (A 인스턴스 메소드)
        NestingClassA.this.aField = 10; // 바깥 클래스 필드 참조 (A 인스턴스 필드)
        this.field1 = 10; // 현재 클래스의 필드 참조 (B 인스턴스 필드)
        this.method1();	// 현재 클래스의 메소드 참조 (B 인스턴스 메소드)
	}
}

내부 클래스가 static이 아니라면 바깥 클래스가 정적으로 정의되든 안 되든 접근이 가능합니다.

 

또 다른 접근 방법은 this를 이용해 접근할 수 있습니다. (바깥클래스.this.필드 or 메소드)

현재 클래스의 필드나 메소드도 접근할 수 있습니다. (this.필드 or 메소드)

 

static class NestingClassC{
	....
	void callA () {
			// aField = 10; // A 인스턴스 필드 사용불가(x)
			// aMethod1(); // A 인스턴스 메소드 사용불가(x)
			
			aField2 = 10; // A 정적 필드
			aMethod2();	// A 정적 메소드
	}
}

내부 클래스 static 선언된 경우에는 static으로 선언된 필드 메소드만 접근이 가능합니다.

 

class NestingClassB{
		void method2() {
			class NestingClassD { // *로컬 클래스*
				NestingClassD() {} 	// 생성자
				int field1;	// 인스턴스 필드
				// static int field2;	// 정적 필드 사용불가(x)
				void method1() {System.out.println("로컬 클래스");} // 인스턴스 메소드
				// static void method2() {}	// 정적 메소드 사용불가(x)
			}
			NestingClassD  D = new NestingClassD();
			D.field1 =3 ;
			D.method1();
		}
}

내부 클래스안에 메소드 안에 클래스를 또 만들어서 사용할 수도 있습니다.

이걸 로컬 클래스라고 합니다.

반응형
반응형
package try_catch;

public class TryCatch {

	public static void main(String[] args) {
		String data1 = null;
		String data2 = null;
		try {
			data1 = args[0];
			data2 = args[1];
		} catch(ArrayIndexOutOfBoundsException e) {
			System.out.println("실행 매개값의 수가 부족합니다.");
			System.out.println("[실행 방법]");
			System.out.println
                      ("java TryCatchFinallyRuntimeExceptionExample num1 num2");
			
		}
		
		try {
			int value1 = Integer.parseInt(data1);
			int value2 = Integer.parseInt(data2);
			int result = value1 + value2;
			System.out.println(data1 + "+" + data2 + "=" + result);
		} catch(Exception e) {
			System.out.println("에러를 찾아주겠습니다.");
			System.out.println("에러는 : " + e + " 입니다.");
		}
		  finally {
			System.out.println("다시 실행하세요");
		}

	}

}

Try Catch문이란 오류를잡아주는 역할을 해줍니다.

일반적인 문법오류가 아닌 실행시 값이 안 들어갔다던지 등에 대한 오류를 잡아줍니다.

 

일단 Try에서 실행할 문을 넣어줍니다. 

 

Catch에서는 에러를 잡아주는 역할을 합니다.

Catch(에러 종류 에러 종류가 들어갈 변수) 입니다.

Catch(Exception e) 여기에서 Exception이란 모든 에러를 의미합니다.

특정한 에러를 알고 있지 않는 이상 Exception을 e로 받아서 e를 출력해보면 알 수 있죠

 

Finally에서는 에러가 나던 안 나던 무조건 실행시키는 부분입니다.

 

어떤식으로 이용할 수 있냐면 만약 값이 안 들어간 null 에러가 난다면 catch(Null값에 대한 에러)를 주고

안에 내용에서 다시 값을 받아오는 역할이라든가 아니면 다른 처리를 해주는 식으로 사용할 수 있습니다.

반응형
반응형
package src;

import java.util.*;

// Ex) ArrayList, LinkedList, Vector 등 * 내부적으로 Arrays.sort()를 사용

class People implements Comparable<People> {
	

    private String name;
	private int age;
	
    public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

    
    public People(String name, int age){
        this.name = name;
        this.age= age;
    }

    @Override
    public int compareTo(People people) {
         if (this.age < people.age) {
             return -1; 
         } else if (this.age == people.age) {
             return 0;
         } else {
             return 1;
         }
     }

	
	
}

 

package src;

class Point implements Comparable<Point> {
	
	
	
//	현재 객체 < 파라미터로 넘어온 객체: 음수 리턴
//	현재 객체 == 파라미터로 넘어온 객체: 0 리턴
//	현재 객체 > 파라미터로 넘어온 객체: 양수 리턴
//	음수 또는 0이면 객체의 자리가 그대로 유지되며, 양수인 경우에는 두 객체의 자리가 바뀐다.
		
    int x, y;

    Point(int x,int y){
    	this.x = x;
    	this.y = y;
    }
    
    public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	@Override
    public int compareTo(Point p) {
        if(this.x > p.x) {
            return 1; // x에 대해서는 오름차순
        }
        else if(this.x == p.x) { // x좌표가 같으면 
            if(this.y < p.y) { // y에 대해서는 내림차순
                return 1;
            }
        }
        return -1;
    }
}
package src;

import java.util.*;



public class Sort {

	public static void main(String[] args) {
		
		// 기본타입 배열 오름차순
		
		int arr[] = {4,23,33,15,17,19};
        Arrays.sort(arr);
        
        for (int i : arr) {
            System.out.print("["+i+"]");
	}
        System.out.println();
        
        // String 배열 오름차순 기본 타입과 동일
        // ----------------------------------------------------------------
        
        String arr2[] = {"apple","orange","banana","pear","peach","melon"};
        Arrays.sort(arr2);
        
        for (String i : arr2) {
            System.out.print("["+i+"]");
        }

        System.out.println();
        
        // 기본타입 배열 내림차순 정렬
        // ----------------------------------------------------------------
        
        Integer arr3[] = {4,23,33,15,17,19};
        Arrays.sort(arr3,Collections.reverseOrder());
        
        for (int i : arr3) {
            System.out.print("["+i+"]");
        }
        
        String arr4[] = {"apple","orange","banana","pear","peach","melon"};
        Arrays.sort(arr4,Collections.reverseOrder());
        System.out.println();
        
        
        // String 배열 내림차순 정렬
        // ----------------------------------------------------------------
        
        for (String i : arr4) {
            System.out.print("["+i+"]");
        }
     
        int arr5[] = {4,23,33,15,17,19};
        // int[] arr5 = {4,23,33,15,17,19};
        // int[] arr5 = new int[] {4,23,33,15,17,19};
        // int arr5[] = new int[] {4,23,33,15,17,19};
        // 다 동일
        
        Arrays.sort(arr5, 0, 4); // 0,1,2,3 요소만 정렬
        System.out.println();
        
        // 배열 일부분만 정렬 
        // ----------------------------------------------------------------
        
        for (int i : arr5) {
            System.out.print("["+i+"]");
        }
        System.out.println();
        
        //  객체 배열 정렬할시에는 comparable 이나 comparator을 사용해야 한다.
        // ----------------------------------------------------------------
        
        People[] arr6 = { new People("상현", 20)
                , new People("철수", 14)
                , new People("경완", 31)
                , new People("대호", 40)
                , new People("지운", 24) 
            };
    		
            Arrays.sort(arr6); //오름차순 정렬        
            
                        
            for (People i : arr6) { //오름차순 출력
                System.out.print("["+ i.getName() + i.getAge() +"]");
            }
    		
            Arrays.sort(arr6,Collections.reverseOrder()); // [철수(14)][상현(20)][지운(24)][경완(31)][대호(40)]
            System.out.println();
    		
            for (People i : arr6) { //내림차순 출력
                System.out.print("["+i.getName() + i.getAge()+"]"); //[대호(40)][경완(31)][지운(24)][상현(20)][철수(14)]
            }
         // ------------------------------------------------- Comparable
          
            System.out.println();
            
            List<Point> pointList = new ArrayList<>();
            pointList.add(new Point(5 , 4));
            pointList.add(new Point(3 , 9));
            pointList.add(new Point(2 , 1));
            
            Collections.sort(pointList);
            
            for (Point i : pointList) {
            	System.out.print(" X : "+ i.getX() + " Y : "+ i.getY());
            	System.out.println();
            }
         
            System.out.println();
         // -------------------------------------------------- Comparator
         // 만약 정렬 대상 클래스의 코드를 직접 수정할 수 없는 경우에는 어떻게 객체의 정렬 기준을 정의할 수 있을까요? 
         // 또는 정렬 하고자 하는 객체에 이미 존재하고 있는 정렬 기준과 다른 정렬 기준으로 정렬을 하고 싶을 때는 어떻게 해야할까요?
         
         // 첫 번째 파라미터로 넘어온 객체 < 두 번째 파라미터로 넘어온 객체: 음수 리턴
         // 첫 번째 파라미터로 넘어온 객체 == 두 번째 파라미터로 넘어온 객체: 0 리턴
         // 첫 번째 파라미터로 넘어온 객체 > 두 번째 파라미터로 넘어온 객체: 양수 리턴
         
            
         Comparator<Point> myComparator = new Comparator<Point>() {
            	  @Override
            	  public int compare(Point p1, Point p2) {
            		  if (p1.x > p2.x) {
            	      return 1; // x에 대해서는 오름차순
            	    }
            	    else if (p1.x == p2.x) {
            	      if (p1.y < p2.y) { // y에 대해서는 내림차순
            	        return 1;
            	      }
            	    }
            	    return -1;
            	  }
            	};

            List<Point> pointList2 = new ArrayList<>();
            pointList2.add(new Point(1, 5));
            pointList2.add(new Point(5, 19));
            pointList2.add(new Point(3, 7));
            Collections.sort(pointList2, myComparator); // myComparator에 선언한대로 정렬
            
            for (Point i : pointList2) {
            	System.out.print(" X : "+ i.getX() + " Y : "+ i.getY());
            	System.out.println();
            }
            
         // 참고 Arrays.sort()와 Collections.sort()의 차이
         // Arrays.sort() 배열 정렬의 경우 vs Collections.sort() List Collection 정렬의 경우

	}
	
}

Arrays.sort(배열)을 이용해 오름차순 정렬을 할 수 있습니다.

Arrays.sort(arr1)

 

또한 String 타입의 배열또한 오름차순 정렬 할 수 있습니다. (알파벳 A부터 시작 정렬)

Arrays.sort(arr2)

 

Arrays.sort(배열,Collections.reverseOrder())을 이용해 내림차순 정리할 수 있습니다.

Arrays.sort(arr3,Collections.reverseOrder())

 

또한 String 타입의 배열또한 내림차순 정렬을 할 수 있습니다. (알파벳 Z부터 시작 정렬)

Arrays.sort(arr4,Collections.reverseOrder())

 

Arrays.sort(arr5, 인덱스, 인덱스끝)를 이용해 범위를 정해서 정렬할 수 있습니다. (인덱스 ~ 인덱스끝 -1 까지)

Arrays.sort(arr5, 0, 4)

 

객체도 정렬할 수 있는데 class People implements Comparable<People> {.... 와 같이 

Comparable 또는Comparator를 사용해야 합니다.

Arrays.sort(배열)정렬이 가능한데 여기서 arr6해당하는 배열은 People이라는 객체를 의미합니다.

별반 다른 거 없어 보이는데 위에랑 People 클래스를 정의한 곳에 보면 CompareTo라는 것을 오버라이드했습니다.

객체 같은 특별한 거라든가 내가 원하는대로 커스터마이징 하고 싶은 경우에는 오버라이드해서 적용시켜야합니다.

 

public int compareTo(People people) {
         if (this.age < people.age) {
             return -1; 
         } else if (this.age == people.age) {
             return 0;
         } else {
             return 1;
         }
     }

compareTo라는 함수를 알아봐야하는데 어떤 함수냐면 말 그대로 비교하는 함수입니다.

현재 객체 < 인자로 넘어온 객체(여기선people) : return 음수 
현재 객체 == 인자로 넘어온 객체(여기선people) : return 0
현재 객체 > 인자로 넘어온 객체(여기선people) : return 양수 입니다.

그런데 이렇게 return만 있으면 뭐 어떻게 작성해야할지도 모르잖아요 더 자세히 알아보면

음수 또는 0이면 객체의 자리가 그대로 유지되며, 양수인 경우에는 두 객체의 자리가 바뀝니다.

 

this.age < people.age을 보면 현재 객체의 나이와 인자값 people의 나이를 비교해서

people의 나이가 더 크면-1 즉 그대로 유지됩니다.

같을 경우도 0을 반환함으로써 자리가 그대로 유지 됩니다.

그렇지 않은 경우는 1을 반환합니다. 두 객체의 자리가 바뀌죠 

이 맥락으로 봤을 때 이렇게 만든 사람의 의도는 나이를 비교해서 오름차순으로 정리하는 걸 알 수 있습니다.

예시를 들어서 people 객체의 이름은 무시하고 age가 6 4 이면 6하고 4을 비교하죠? 그러면 6 < 4 이기 때문에

1을 반환합니다. 그러면 자리가 바뀌어서 4 6이 되죠 오름차순으로 정렬 되었죠?

 

Arrays.sort(배열,Collections.reverseOrder()) 을 이용해 내림차순 정렬을 할 수 있습니다.

Arrays.sort(arr6,Collections.reverseOrder())

 

List<Point> pointList = new ArrayList<Point>() 같이 Point객체를 받는 ArrayList여도 똑같이 정렬이 가능합니다.

Collections.sort(ArrayList객체명)

Collections.sort(pointList) 하지만 조금 다른 점이 있는데 Arrays를 사용 안 하고 Collections를 써야합니다.

(ArrayList때문에) 또한 Point객체를 이용하는 경우 Point클래스에 CompareTo를 구현해야합니다.

 

 

 

Comparator<Point> myComparator = new Comparator<Point>() {
            	  @Override
            	  public int compare(Point p1, Point p2) {
            		  if (p1.x > p2.x) {
            	      return 1; // x에 대해서는 오름차순
            	    }
            	    else if (p1.x == p2.x) {
            	      if (p1.y < p2.y) { // y에 대해서는 내림차순
            	        return 1;
            	      }
            	    }
            	    return -1;
            	  }
            	};

또 다른 객체 비교하는 클래스가 있는데 그게 Comparator입니다.

사용 방법Comparator<클래스명> 객체명 = new Comparator<클래스명>()

Comparator<Point> myComparator = new Comparator<Point>()

그 후 Comparable이 CompareTo를 구현한 거처럼 compare(인자값1, 인자값2)으로 오버라이드 해야합니다.

구현 방법은 위에 설명한 것과 동일합니다.

 

Collections.sort(배열명, Comparator클래스를 이용해 만든 객체명)으로

배열에 내가 정의한 compare메소드가 들어있는 객체를 적용시키는 것입니다.

Collections.sort(pointList2, myComparator)

 

그러면 Comparable과 Comparator는 무슨 차이가 있나요? 그걸 알아봅시다.
1번 Comparable을 사용하고자 한다면 compareTo 메소드를 오버라이드해야합니다.

그리고 Comparable은 인터페이스입니다. 그리고 자기 자신과 인자값 한개를 비교하죠


2번은 Comparator의 경우 클래스이며 compare 메소드를 오버라이드를 해야합니다 그리고 

두개의 매개변수를 받아서 그 두개를 비교하죠

 

결과적으로 이런 차이만 있을 뿐 객체를 비교하기 위해 있다는 건 동일합니다.

 

 

 

반응형