[Java] 객체를 제거하는 방법

객체를 제거하는 방법


1. 레퍼런스가 영원히 영역을 벗어남


void A()    {

School s = new School();

}

메소드가 종료되면 's' 라는 레퍼런스도 죽어버립니다.

 

2. 레퍼런스에 다른 객체를 대입


School s = new School();

s = new School();

레퍼런스 's' 에 새로운 객체를 대입하면 첫번째 객체는 버려집니다.

 

3. 레퍼런스를 직접 'null' 로 설정

 

School s = new School();

s = null;

's' 를 '해제' 하면 첫번째 객체는 버려집니다.

즉 레퍼런스 's' 가 아무 객체도 참조하지 않는 것입니다.

 

레퍼런스가 참조하지 않는 객체는 가비지 컬렉션의 대상이 되어 자동으로 정리됩니다.

'Programing > Java' 카테고리의 다른 글

[Java] 객체를 제거하는 방법  (0) 2015.05.19
[Java] Wrapper 클래스  (0) 2015.04.13
[Java] 예외 던지기  (0) 2014.12.25
[Java] 예외 만들기  (0) 2014.12.25
[Java] 예외 처리 기본  (0) 2014.12.25
[Java] enum  (0) 2014.12.25

[Java] Wrapper 클래스

Wrapper 클래스


Wrapper 클래스라는 것은 그 이름이 의미하듯이 'wrap(포장)'하는 기능의 클래스를 의미한다.

이것은 주로 JDK1.5 이전에 많이 쓰였던 기능들인데 설명하자만 기본자료형을 객체자료형으로 변환하기 위해서 사용하는 클래스라고 생각하면 된다.


1. 문제제기

Object 타입의 변수는 모든 객체형 자룔를 표현할 수 있지만, int나 byte와 같은 기본형 자료는 선언할 수 없다.

Object a = 123; //컴파일오류


2. 문제를 일으키는 경우

- 변수의 최초 선언

- 메소드의 파라미터, 리턴타입

- 배열과 같은 자료구조


3. 기본형 자료를 객체형 자료로 처리하기 위한 클래스

기본자료형 

Wapper 클래스 

byte

Byte 클래스

short 

Short 클래스

int 

Integer 클래스 

long 

Long 클래스

double 

Double 클래스

float 

Float 클래스 

boolean 

Boolean 클래스 

char 

Character 클래스 


4. 사용법

Integer data = new Integer(3);

int intValue = data.intValue();

double doubleValue = data.doubleValue();

String StringValue = data.toString();


예제)

Integer aa = new Integer(10);

Integer bb = aa;

aa = aa + new Integer(1);

System.out.println("aa:  "+aa);

System.out.println("bb:  "+bb);

실행결과

aa:   11

bb:   10


5. 문자열 --> 기본자료형 / 숫자 --> 문자열

문자를 기본 자료형으로 바꿀 때

기본 자료형을 문자형으로 바꿀 때 

byte b = Byte.parseByte(문자열);

Byte.toString(byte 값);

short s = Short.parseshort(문자열);

Short.toString(short 값); 

int i = Integer.parseInt(문자열); 

Integer.toString(int 값);

double d = Double.parseDouble(문자열);

Double.toString(double 값); 

long l = Long.parseLong(문자열); 

Long.toString(long 값); 

float f = Float.parseFloat(문자열); 

Float.toString(float 값); 

boolean b = new Boolean(문자열); 

Boolean.toString(boolean 값); 

char c = String.클래스의 메소드 이용 

Character.toString(char 값); 


6. Autoboxing / Unboxing

Autoboxing / Unboxing는 JDK1.5에서 지원하는 자동 변환이다. 이 방식 때문에 기본 자료형이나 객체 자료형을 간단히 변환할 수 있게 되었다.

(1) Autoboxing

Autoboxing은 기본 자료형의 데이터를 자동으로 객체 자료형으로 변환하는 것을 의미한다.

int i = 10;

Integer J = 1;


(2) Unboxing

Unboxing은 Wrapper 자료형을 기본 자료형으로 자동 변환한다.

Integer i = new Integer(10);

int j = 1;


'Programing > Java' 카테고리의 다른 글

[Java] 객체를 제거하는 방법  (0) 2015.05.19
[Java] Wrapper 클래스  (0) 2015.04.13
[Java] 예외 던지기  (0) 2014.12.25
[Java] 예외 만들기  (0) 2014.12.25
[Java] 예외 처리 기본  (0) 2014.12.25
[Java] enum  (0) 2014.12.25

[Java] 예외 던지기

예외 던지기


1. 예외 되던지기


한 메서드에서 발생할 수 있는 예외가 여럿인 경우, 몇 개는 try-catch문을 통해서 메서드 내에서 자체적으로 처리하고, 그 나머지는 선언부에 지정하여 호출한  메서드에서 처리하도록 함으로써, 양쪽에서 나눠서 처리되도록 할 수 있다. 그리고 심지어는 단 하나의 예외에 대해서도 예외가 발생한 메서드와 호출한 메서드, 양쪽에서 처리하도록 할 수 있다.

이것은 예외를 처리한 후에 인위적으로 다시 발생시키는 방법을 통해서 가능한데, 이것을 '예외 던지기'이라고 한다.

먼저 예외가 발생한 가능성이 있는 메서드에서 try-catch문을 사용해서 예외를 처리해주고 catch문에서 필요한 작업으로 행한 후에 throw문을 사용해서 예외를 다시 발생시킨다.

다시 발생한 예외는 이 메서드를 호출한 메서드에게 전달되고 호출한 메서드의 try-catch문에서 예외를 또다시 처리한다.

이 방법은 하나의 예외에 대해서 예외가 발생한 메서드와 이를 호출한 메서드 양쪽 모두에서 처리해줘야 할 작업이 있을 때 사용된다.

이 때 주의할 점은 예외가 발생할 메서드에서는 try-catch문을 사용해서 예외처리를 해줌과 동시에 메서드의 선언부에 발생할 예외를 throws에 지정해줘야 한다는 것이다.


class ExceptionEx23 {

public static void main(String[] args) {

try  {

method1();

} catch (Exception e) {

System.out.println("main메서드에서 예외가 처리되었습니다.");

}

} // main메서드의 끝


static void method1() throws Exception {

try {

throw new Exception();

} catch (Exception e) {

System.out.println("method1메서드에서 예외가 처리되었습니다.");

throw e; // 다시 예외를 발생시킨다.

}

} // method1메서드의 끝

}

실행결과)

method1메서드에서 예외가 처리되었습니다.

main메서드에서 예외가 처리되었습니다.

결과에서 알 수 있듯이 method1()과 main메서드 양쪽이 catch블럭이 모두 수행되었음을 알 수 있다. method1()의 catch블럭에서 예외를 처리하고도 throw문을 통해 다시 예외를 발생시켰다.

그리고 이 예외를 main 메서드 한 번 더 처리 하였다.


2. 메서드에 예외 선언


메서드에 예외를 선언하려면, 메서드의 선언부에 키워드 throws를 사용해서 메소드 내에서 발생할 수 있는 예외를 적어주기만 하면 된다. 그리고, 예외가 여러 개일 경우에는 쉼표(,)로 구분한다.

void method( ) throws Exception1, Exception2....ExceptionN{

.... 메서드의 내용

}

--> 이 메서드는 Exception1, Exception2....ExceptionN와 같은 Exception이 발생할 수 있으니, 이 메서드를 호출하고자 하는 메서드에서는  Exception1, Exception2....ExceptionN을 처리 해주어야 한다는 뜻이다. 자신을 호출한 메서드에 예외를 전가시키는 것. 예외를 발생시키는 키워드 throw와 예를 메서드에 선언할 때 쓰이는 throws를 잘 구별하자


이렇게 메서드의 선언부에 예외를 선언함으로써 메서드를 사용하려는 사람이 메서드의 선언부를 보았을 때, 이 메서드를 사용하기 위해서는 어떠한 예외들이 처리되어져야 하는 쉽게 알 수 있다.

자바에서는 메서드를 작성할 때 메서드 내에서 발생할 가능성이 있는 예외를 메서드의 선언부에 명시하여 이 메서드를 사용하는 쪽에서는 이에 대한 처리를 하도록 강요하기 때문에, 프로그래머들의 짐을 덜어 주는 것은 물론이고 보다 견고한 프로그램 코드를 작성할 수 있도록 도와 준다.


메서드에 예외를 선언할 때 일반적으로 RuntimeException클래스들은 적지 않는다. 이 들은 메서드 선언부의 throws에 선언한다고 해서 문제가 되지는 않지만, 보통 반드시 처리해주어야 하는 예외들만 선언한다. 이처럼 Java API 문서를 통해 사용하고자 하는 메서드의 선언부와 'Throws:'를 보고, 이 메서드에서는 어떤 예외가 발생할 수 있으며 반드시 처리해주어야 하는 예외는 어떤 것들이 있는지 확인하는 것이 좋다. 반드시 처리해주어야 하는 예외는 Exception 클래스들(RuntimeException 클래스들 이외의 예외 클래스들)이다.

사실 예외를 메서드의 throws에 명시하는 것은 예외를 처리하는 것이 아니라. 자신(예외가 발생할 가능성이 있는 메서드)을 호출한 메서드에게 예외를 전달하여 예외처리를 떠맡기는 것이다.

예외를 전달받은 메서드가 또다시 자신을 호출한 메서드에게 전달할 수 있으며, 이런 식으로 계속 호출스택에 있는 메서드들을 따라 전달되다가 제일 마지막에 있는 main 메서드에서도 예외가 처리되지 않으면, main 메서드 마저 종료되어 프로그램이 전체가 종료된다.


class ExceptionEx18 {

public static void main(String[] args) throws Exception {

method1(); // 같은 클래스내의 static멤버이므로 객체생성없이 직접 호출가능.

  } // main메서드의 끝


static void method1() throws Exception {

method2();

} // method1의 끝


static void method2() throws Exception {

throw new Exception();

} // method2의 끝

}

실행결과)

Exception in thread "main" java.lang.Exception

at example.ExceptionEx18.method2(ExceptionEx18.java:13)

at example.ExceptionEx18.method1(ExceptionEx18.java:9)

at example.ExceptionEx18.main(ExceptionEx18.java:5)

위의 실행 결과를 프로그램의 실행도중에 java.lang.Exception이 발생하여 비정상적으로 종료했다는 것과 예외가 발생했을 때 호출스택(Call Stack)의 내용을 알 수 있다.


위의 결과로 부터 다음과 같은 사실을 알 수 있다.

1 예외가 발생했을 때, 모두 3개의 메서드(main, method1, method2)가 호출 스택에 있었다

2 예외가 발생한 곳은 제일 윗줄에 있는 method2()이다.

3 main 메서드가 method1()를 , 그리고 method1()은 method2()를 호출했다는 것을 알 수 있다.


위의 예제를 보면, method2()에서 'throw new Exception();' 문장에 의해 예외가 강제적으로 발생했으나 try-catch문으로 예외처리를 해주지 않았으므로, method2()는 종료되면서 예외를 자신을 호출한 method1()에게 넘겨준다. method1()에서도 역시 예외처리를 해주지 않았으므로 종료되면서 main메서드에게 예외를 넘겨준다.

그러나 main메서드에서 조차 예외처리를 해주지 않았으므로 main 메서드가 종료되어 프로그램이 예외로 인해 비정상적으로 종료되는 것이다.

이처럼 예외가 발생한 메서드에서 예외처리를 하지 않고 자신을 호출한 메서드에게 예외를 넘겨줄 수는 있지만, 이것으로 예외가 처리된 것은 아니고 예외를 단순히 전달만 하는 것이다.


결국 이는 한 곳에서는 반드시 try-catch문으로 예외처리를 해주어야 한다.

class ExceptionEx19 {

public static void main(String[] args) {

method1(); // 같은 클래스내의 static멤버이므로 객체생성없이 직접 호출가능.

  // main메서드의 끝


static void method1() {

try {

throw new Exception();

} catch (Exception e) {

System.out.println("method1메서드에서 예외가 처리되었습니다.");

e.printStackTrace();

}

// method1의 끝

}

printStackTrace()를 통해 예외에 대한 정보를 화면에 출력하였다. 예외가 method1()에서 발생했으며, main 메서드가 method1()을 호출했음을 알 수 있다.


class ExceptionEx20 {

public static void main(String[] args) {

try  {

method1();

} catch (Exception e) {

System.out.println("main메서드에서 예외가 처리되었습니다.");

e.printStackTrace();

}

// main메서드의 끝


static void method1() throws Exception {

throw new Exception();

// method1()의 끝

} // class의 끝

ExceptionEx19는 method1()에서 예외처리를 했고, ExceptionEx20은 method1()에서 예외를 선언하여 자신을 호출하는 메서드(main 메서드)에 예외를 전달했으며, 호출한 메서드(main 메서드)에서는 try-catch문으로 예외처리를 했다.

ExceptionEx19 처럼 예외가 발생한 메서드(method1) 내에서 처리되어지면, 호출한 메서드(main 메서드)에서는 예외가 발생했다는 사실조차 모르게 된다.

ExceptionEx20처럼 예외가 발생한 메서드에서 예외를 처리하지 않고 호출한 메서드로 넘겨주면, 호출한 메서드에서는 method1()을 호출한 라인에서 예외가 발생한 것으로 간주되어 이에 대한 처리를 하게 된다. 이처럼 예외가 발생한 메서드 'method1()'에서 예외를 처리할 수도 있고, 예외가 발생한 메서드를 호출한 메서드 'main 메서드' 에서 처리할 수도 있다. 또는 두 메서드가 예외 처리를 분담할 수 있다.



'Programing > Java' 카테고리의 다른 글

[Java] 객체를 제거하는 방법  (0) 2015.05.19
[Java] Wrapper 클래스  (0) 2015.04.13
[Java] 예외 던지기  (0) 2014.12.25
[Java] 예외 만들기  (0) 2014.12.25
[Java] 예외 처리 기본  (0) 2014.12.25
[Java] enum  (0) 2014.12.25

[Java] 예외 만들기


예외 만들기


1. 예외 발생시키기

키워드 throw를 사용해서 프로그래머가 고의로 예외를 발생시킬 수 있다.

1) 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든 다음

  Exception e = new Exception("고의로 발생시켰음");


2) 키워드 throw를 이용해서 예외를 발생시킨다.

  throw  e;


class ExceptionEx

{

public static void main(String args[]) 

{

try {

Exception e = new Exception("고의로 발생시켰음.");

throw e; // 예외를 발생시킴

//  throw new Exception("고의로 발생시켰음.");  // 위의 두 줄을 한 줄로 줄여 쓸 수 있다.

} catch (Exception e) {

System.out.println("에러 메시지 : " + e.getMessage());

e.printStackTrace();

}

System.out.println("프로그램이 정상 종료되었음.");

}

}

실행결과)

에러 메시지 : 고의로 발생시켰음.

프로그램이 정상 종료되었음.

java.lang.Exception: 고의로 발생시켰음.

at example.demo.main(demo.java:8)


2. 사용자 정의 예외 만들기

기존의 정의된 예외 클래스 외에 필요에 따라 프로그래머가 새로운 예외 클래스를 정의하여 사용할 수 있다. 보통 Exception클래스로부터 상속받는 클래스를 만들지만, 필요에 따라서 알맞은 예외 클래스를 선택할 수 있다.

class MyException extends Exception{

MyException(String msg){// 문자열을 매개변수로 받는 생성자

super(msg);// 조상인 Exception 클래스의 생성자를 호출한다.

}

}


Exception 클래스로부터 상속받아서 MyException클래스를 만들었다. 필요하다면, 멤버변수나 메서드를 추가할 수 있다. Exception 클래스는  생성 시에 String값을 받아서 메시지로 저장할 수 있다. 사용자 정의 예외 클래스도 메시지를 저장할 수 있으려면, 위에서 보는 것과 같이 String을 매개변수로 받는 생성자를 추가해주어야 한다.

class MyException extends Exception{// 에러 코드 값을 저장하기 위한 필드를 추가 했다.

private final int ERR_CODE;// 생성자를 통해 초기화 한다.

MyException(String msg, int errcode){ //생성자

super(msg);

ERR_CODE=errCode;

}

MyException(String msg){// 생성자

this(msg, 100)l// ERR_CODE를 100(기본값)으로 초기화한다.

}

public int getErrCode(){// 에러 코드를 얻을 수 있는 메서드도 추가한다.

return ERR_CODE;// 이 메서드는 주로 getMessage()와 함께 사용될 것이다.

}

}

이전의 코드를 좀더 개선하여 메시지뿐만 아니라 에러코드 값도 저장할 수 있도록 ERR_CODE와 getErrCode()를 MyException클래스의 멤버로 추가했다.

이렇게 함으로써 MyException이 발생했을 때, catch블럭에서 getMessage()와 getErrCode()를 사용해서 에러코드와 메시지를 모두 얻을 수 있을 것이다.


class NewExceptionTest {

public static void main(String args[]) {

try {

startInstall(); // 프로그램 설치에 필요한 준비를 한다.

copyFiles(); // 파일들을 복사한다. 

} catch (SpaceException e) {

System.out.println("에러 메시지 : " + e.getMessage());

e.printStackTrace();

System.out.println("공간을 확보한 후에 다시 설치하시기 바랍니다.");

} catch (MemoryException me) {

System.out.println("에러 메시지 : " + me.getMessage());

me.printStackTrace();

System.gc(); //  Garbage Collection을 수행하여 메모리를 늘려준다.

System.out.println("다시 설치를 시도하세요.");

} finally {

deleteTempFiles(); // 프로그램 설치에 사용된 임시파일들을 삭제한다.

} // try의 끝

} // main의 끝


   static void startInstall() throws SpaceException, MemoryException { 

if(!enoughSpace()) // 충분한 설치 공간이 없으면...

throw new SpaceException("설치할 공간이 부족합니다.");

if (!enoughMemory()) // 충분한 메모리가 없으면...

throw new MemoryException("메모리가 부족합니다.");

   } // startInstall메서드의 끝


   static void copyFiles() { /* 파일들을 복사하는 코드를 적는다. */ }

   static void deleteTempFiles() { /* 임시파일들을 삭제하는 코드를 적는다.*/}

   

   static boolean enoughSpace()   {

// 설치하는데 필요한 공간이 있는지 확인하는 코드를 적는다.

return false;

   }

   static boolean enoughMemory() {

// 설치하는데 필요한 메모리공간이 있는지 확인하는 코드를 적는다.

return true;

   }

} // ExceptionTest클래스의 끝


class SpaceException extends Exception {

SpaceException(String msg) {

  super(msg);

   }


class MemoryException extends Exception {

MemoryException(String msg) {

  super(msg);

   }

}

실행결과)

에러 메시지 : 설치할 공간이 부족합니다.

example.SpaceException: 설치할 공간이 부족합니다.

at example.ExceptionEx18.startInstall(ExceptionEx18.java:24)

at example.ExceptionEx18.main(ExceptionEx18.java:6)

공간을 확보한 후에 다시 설치하시기 바랍니다.

MemoryException과 SpaceException, 이 두개의 사용자정의 예외 클래스를 새로 만들어서 사용했다

Space Exception은 프로그램을 설치하려는 곳에 충분한 공간이 없을 경우에 발생하도록 했으며, MemoryException은 설치작업을 수행하는데 메모리가 충분히 확보되지 않았을 경우에 발생하도록 하였다. 이 두 개의 예외는 startInstall()을 수행하는 동안에 발생할 수 있으며, enoughSpace()와 enoughMemory()의 실행 결과에 따라서 발생하는 예외의 종류가 달라지도록 했다.


'Programing > Java' 카테고리의 다른 글

[Java] Wrapper 클래스  (0) 2015.04.13
[Java] 예외 던지기  (0) 2014.12.25
[Java] 예외 만들기  (0) 2014.12.25
[Java] 예외 처리 기본  (0) 2014.12.25
[Java] enum  (0) 2014.12.25
[Java] for-each문  (0) 2014.12.23

[Java] 예외 처리 기본


예외 처리 기본


컴파일 에러: 컴파일 할때 발생하는 에러이다.

런타임 에러: 프로그램의 실행도중에 발생하는 에러이다.


소스코드를 컴파일 하면 컴파일러가 소스코드(.java)에 대해 오타나 잘못된 구문, 자료형 체크 등의 기본적인 검사를 수행하여 오류가 있는지 알려준다. 컴파일러가 알려 준 에러들은 모두 수정해서 컴파일을 성공적으로 마치고 나면, 클래스 파일(.class)이 생성되고, 생성된 클래스 파일을 실행할 수 있게 되는 것이다.

컴파일러가 소스코드의 기본적인 사항은 컴파일시에 모두 걸러줄 수 있지만, 실행 도중에 발생할 수 있는 잠재적인 오류까지 검사할 수 없기 때문에 컴파일은 잘되었어도 실행 중에 에러에 의해서 잘못된 결과를 얻거나 프로그램이 비정상적으로 종료될 수 있다.


자바에서는 실행 시(runtime) 발생할 수 있는 프로그램 오류를 '에러'와 '예외' 두 가지로 구분하였다.

에러는 메모리 부족이나 스택오버플로우와 같이 일단 발생하면 복구할 수 없는 심각한 오류이고, 예외는 발생하더라도 수습될 수 있는 비교적 덜 심각한 것이다.

-> 에러와 예외는 모두 실행 시(runtime) 발생하는 오류이다.


1. 예외 클래스


RuntimeException 클래스들은 주로 프로그래머의 실수에 의해서 발생할 수 있는 예외들로서 자바의 프로그래밍 요소와 관계가 깊다.

--> 프로그래머의 실수로 발생하는 예외

Exception 클래스들은 주로 외부의 영향으로 발생할 수 있는 것들로서, 프로그램의 사용자들의 동작에 의해서 발생하는 경우가 많다.

--> 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외

RuntimeException 클래스들과 Exception 클래스들의 중요한 차이점은 컴파일시의 예외처리 체크여부이다. RuntimeException 클래스들 그룹에 속하는 예외가 발생할 가능성이 있는 코드에는 예외 처리를 해주지 않아도 컴파일 시에 문제가 되지 않지만, Exception 클래스들 그룹에 속하는 예외가 발생할 가능성이 있는 예외는 반드시 처리를 해주어야 하며, 그렇지 않으면 컴파일 시에 에러가 발생한다.


class ExceptionEx7 

{

public static void main(String[] args) 

{

throw new Exception(); // Exception을 강제로 발생시킨다.

}

}

이 예제를 작성한 후에 컴파일 하면 컴파일이 완료되지 않는다. 예외처리가 되어야 할 부분에 예외처리가 되어 있지 않다는 에러이다. 위의 결과에서 알 수 있는 것처럼, 위에서 분류한 '그 외의 Exception클래스들'이 발생할 가능성이 있는 문자들에 대해 예외처리를 해주지 않으면 컴파일 조차 되지 않는다.


따라서 위의 예제를 아래와 같이 try-catch 문으로 처리해 주어랴 컴파일이 성공적으로 이루어 질 것이다.

class ExceptionEx8 {

public static void main(String[] args) 

{

try {

throw new Exception();

} catch (Exception e) {

System.out.println("Exception이 발생했습니다.");

}

} // main메서드의 끝

}


※ 주의 할점

class ExceptionEx9 

{

public static void main(String[] args) {

throw new RuntimeException(); // RuntimeException을 강제로 발생시킨다.

}

}

위의 예제를 컴파일 하면, 예외를 처리하지 않았음에도 불구하고 이전의 예제와는 달리 성공적으로 컴파일이 될 것이다. 그러나 실행하면, RumtimeException이 발생하여 비정상적으로 종료될 것이다.

이 예제가 명백히 RuntimeException을 발생시키는 코드를 가지고 있고, 이에 대한 예외처리를 하지 않았음에도 불구하고 성공적으로 컴파일 되었다.

이와 같이 RuntimeException클래스들은 예외처리를 해주지 않아도 컴파일러가 문제삼지 않는 것을 알아야 한다.


2. 예외 처리의 정의와 목적

프로그램의 실행 도중에 발생하는 에러는 어쩔 수 없지만, 예외는 프로그래머가 이에 대한 처리를 미리 해주어야 한다.

예외처리란, 프로그램 실행 시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드를 작성하는 것이며 예외처리의 목적은 예외의 발생으로 인한 실행 중인 프로그램의 갑작스런 비정상 종료를 막고, 정상적인 실행 상태를 유지할 수 있도록 하는 것이다.


정의:  프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것.

목적: 프로그램의 비정상 종료를 막고, 정상적인 실행 상태를 유지하는 것.


3. try...catch...finally

try...catch는 예외에서 핵심적인 역할을 담당하는 문법적인 요소다. 형식을 살펴보자.

class Calculator{

    int left, right;

    public void setOprands(int left, int right){

        this.left = left;

        this.right = right;

    }

    public void divide(){

        try {

            System.out.print("계산결과는 ");

            System.out.print(this.left/this.right);

            System.out.print(" 입니다.");

        } catch(Exception e){

            System.out.println("\n\ne.getMessage()\n"+e.getMessage());

            System.out.println("\n\ne.toString()\n"+e.toString());

            System.out.println("\n\ne.printStackTrace()");

            e.printStackTrace();

        }

    }

public class CalculatorDemo {

    public static void main(String[] args) {

        Calculator c1 = new Calculator();

        c1.setOprands(10, 0);

        c1.divide();

    }

}

실행결과)
e.getMessage()
/ by zero
 
e.toString()
java.lang.ArithmeticException: / by zero
 
e.printStackTrace()
java.lang.ArithmeticException: / by zero
    at org.opentutorials.javatutorials.exception.Calculator.divide(CalculatorDemo.java:11)
    at org.opentutorials.javatutorials.exception.CalculatorDemo.main(CalculatorDemo.java:25)
1) e.getMessage();
오류에 대한 기본적인 내용을 출력해준다. 상세하지 않다.
2) e.toString()
e.toString()을 호출한 결과는 java.lang.ArithmeticException: / by zero 이다. e.toString()은 e.getMessage()보다 더 자세한 예외 정보를 제공한다. java.lang.ArithmeticException은 발생한 예외가 어떤 예외에 해당하는지에 대한 정보라고 지금을 생각하자. ArithmeticException 수학적인 계산의 과정에서 발생하는 예외상황을 의미한다. (우리는 어떤 숫자를 0으로 나누려고 하고 있다는 것을 상기하자)
3) e.printStackTrace()
메소드 getMessage, toString과는 다르게 printStackTrace는 리턴값이 없다. 이 메소드를 호출하면 메소드가 내부적으로 예외 결과를 화면에 출력한다. printStackTrace는 가장 자세한 예외 정보를 제공한다.


(1) try


try 안에는 예외 상황이 발생할 것으로 예상되는 로직을 위치시킨다. 예를 들어, 사용자가 setOprands의 두 번째 인자로 숫자 0을 입력했을 때 문제가 발생할 수 있음을 예측할 수 있다. 그래서 이 로직을 try 구문으로 감싼 것이다.


(2) catch


catch 안에는 예외가 발생했을 때 뒷수습을 하기 위한 로직이 위치한다. 


(3) finally

class A{

    private int[] arr = new int[3];

    A(){

        arr[0]=0;

        arr[1]=10;

        arr[2]=20;

    }

    public void z(int first, int second){

        try {

            System.out.println(arr[first] / arr[second]);

        } catch(ArrayIndexOutOfBoundsException e){

            System.out.println("ArrayIndexOutOfBoundsException");

        } catch(ArithmeticException e){

            System.out.println("ArithmeticException");

        } catch(Exception e){

            System.out.println("Exception");

        } finally {

            System.out.println("finally");

        }

    }

}

 

public class ExceptionDemo1 {

    public static void main(String[] args) {

        A a = new A();

        a.z(10, 0);

        a.z(1, 0);

        a.z(2, 1);

    }

}

실행결과)

ArrayIndexOutOfBoundsException

finally

ArithmeticException

finally

2

finally


'Programing > Java' 카테고리의 다른 글

[Java] 예외 던지기  (0) 2014.12.25
[Java] 예외 만들기  (0) 2014.12.25
[Java] 예외 처리 기본  (0) 2014.12.25
[Java] enum  (0) 2014.12.25
[Java] for-each문  (0) 2014.12.23
[Java] 오토박싱  (0) 2014.12.23

[Java] enum


enum


1. enum

enum은 열거형(enumerated type)이라고 부른다. 열거형은 서로 연관된 상수들의 집합(String과 같은 데이터 타입의 일종)이라고 할 수 있다.(배열은 서로 연관된 값들의 집합) 위의 예제에서는 Fruit와 Company가 말하자면 열거인 셈이다. 이러한 패턴을 자바 1.5부터 문법적으로 지원하기 시작했는데 그것이 열거형이다. 이전 코드를 enum으로 바꿔보자.


enum Fruit{

    APPLE, PEACH, BANANA;

}

//class Fruit{

//    public static final Fruit APPLE  = new Fruit();

//    public static final Fruit PEACH  = new Fruit();

//    public static final Fruit BANANA = new Fruit();

//}--> 위의 코드와 같은 의미


enum Company{

    GOOGLE, APPLE, ORACLE;

}

 

public class ConstantDemo {

     

    public static void main(String[] args) {

        /*

        if(Fruit.APPLE == Company.APPLE){

            System.out.println("과일 애플과 회사 애플이 같다.");

        }

        */

        Fruit type = Fruit.APPLE;

        switch(type){

            case APPLE://Fruit.APPLE로 명시할 시 에러(상수만 적도록 약속)

                System.out.println(57+" kcal");

                break;

            case PEACH:

                System.out.println(34+" kcal");

                break;

            case BANANA:

                System.out.println(93+" kcal");

                break;

        }

    }

}


실행결과)

57 kcal

위의 코드를 하나씩 살펴보자.

enum Fruit{

    APPLE, PEACH, BANANA;

}

enum은 class, interface와 동급의 형식을 가지는 단위다. 하지만 enum은 사실상 class이다. 편의를 위해서 enum만을 위한 문법적 형식을 가지고 있기 때문에 구분하기 위해서 enum이라는 키워드를 사용하는 것이다. 


위의 코드는 아래 코드와 사실상 같다.

class Fruit{

    public static final Fruit APPLE  = new Fruit();

    public static final Fruit PEACH  = new Fruit();

    public static final Fruit BANANA = new Fruit();

    private Fruit(){}

}

생성자의 접근 제어자가 private이다. 그것이 클래스 Fruit를 인스턴스로 만들 수 없다는 것을 의미한다. 다른 용도로 사용하는 것을 금지하고 있는 것이다. 이에 대해서는 뒤에서 다시 설명하겠다. enum은 많은 곳에서 사용하던 디자인 패턴을 언어가 채택해서 문법적인 요소로 단순화시킨 것이라고 할 수 있다.


아래 코드는 컴파일 에러가 발생한다.

/*

if(Fruit.APPLE == Company.APPLE){

    System.out.println("과일 애플과 회사 애플이 같다.");

}

*/

enum이 서로 다른 상수 그룹에 대한 비교를 컴파일 시점에서 차단할 수 있다는 것을 의미한다. 상수 그룹 별로 클래스를 만든 것의 효과를 enum도 갖는다는 것을 알 수 있다.


enum을 사용하는 이유를 정리하면 아래와 같다.

- 코드가 단순해진다.

- 인스턴스 생성과 상속을 방지한다.

- 키워드 enum을 사용하기 때문에 구현의 의도가 열거임을 분명하게 나타낼 수 있다.


2. enum과 생성자

enum은 사실 클래스다. 그렇기 때문에 생성자를 가질 수 있다. 아래와 같이 코드를 수정해보자.


enum Fruit{

    APPLE, PEACH, BANANA;

    Fruit(){

        System.out.println("Call Constructor "+this);//생성자에 대한 정보 출력

    }

}

 

enum Company{

    GOOGLE, APPLE, ORACLE;

}

 

public class ConstantDemo {

     

    public static void main(String[] args) {

        Fruit type = Fruit.APPLE;

        switch(type){

            case APPLE:

                System.out.println(57+" kcal");

                break;

            case PEACH:

                System.out.println(34+" kcal");

                break;

            case BANANA:

                System.out.println(93+" kcal");

                break;

        }

    }

}

실행결과)

Call Constructor APPLE

Call Constructor PEACH

Call Constructor BANANA

57 kcal

Call Constructor가 출력된 것은 생성자 Fruit가 호출되었음을 의미한다. 이것이 3번 호출되었다는 것은 필드의 숫자만큼 호출되었다는 뜻이다. 즉 enum은 생성자를 가질 수 있다.


하지만 코드를 아래와 같이 바꾸면 컴파일 에러가 발생한다.

enum Fruit{

    APPLE, PEACH, BANANA;

    public Fruit(){

        System.out.println("Call Constructor "+this);

    }

}

이것은 enum의 생성자가 접근 제어자 private만을 허용하기 때문이다. 덕분에 Fruit를 직접 생성할 수 없다. 그렇다면 이 생성자의 매개변수를 통해서 필드(APPLE..)의 인스턴스 변수 값을 부여 할 수 있다는 말일까? 있다.


enum Fruit{

    APPLE("red"), PEACH("pink"), BANANA("yellow");

    public String color;

    Fruit(String color){

        System.out.println("Call Constructor "+this);

        this.color = color;

    }

}

 

enum Company{

    GOOGLE, APPLE, ORACLE;

}

 

public class ConstantDemo {

     

    public static void main(String[] args) {

 

        Fruit type = Fruit.APPLE;

        switch(type){

            case APPLE:

                System.out.println(57+" kcal, "+Fruit.APPLE.color);

                break;

            case PEACH:

                System.out.println(34+" kcal"+Fruit.PEACH.color);

                break;

            case BANANA:

                System.out.println(93+" kcal"+Fruit.BANANA.color);

                break;

        }

    }

}

실행결과)

Call Constructor APPLE

Call Constructor PEACH

Call Constructor BANANA

57 kcal, red


아래 코드는 Fruit의 상수를 선언하면서 동시에 생성자를 호출하고 있다.

APPLE("red"), PEACH("pink"), BANANA("yellow");


아래 코드는 생성자다. 생성자의 매개변수로 전달된 값은 this.color를 통해서 5행의 인스턴스 변수의 값으로 할당된다.

Fruit(String color){

    System.out.println("Call Constructor "+this);

    this.color = color;

}


아래처럼 호출하면 APPLE에 할당된 Fruit 인스턴스의 color 필드를 반환하게 된다.

System.out.println(57+" kcal, "+Fruit.APPLE.color);


열거형은 메소드를 가질수도 있다. 아래 코드는 이전 예제와 동일한 결과를 출력한다.

enum Fruit{

    APPLE("red"), PEACH("pink"), BANANA("yellow");

    private String color;

    Fruit(String color){

        System.out.println("Call Constructor "+this);

        this.color = color;

    }

    String getColor(){

        return this.color;

    }

}

 

enum Company{

    GOOGLE, APPLE, ORACLE;

}

 

public class ConstantDemo {

     

    public static void main(String[] args) {

        Fruit type = Fruit.APPLE;

        switch(type){

            case APPLE:

                System.out.println(57+" kcal, "+Fruit.APPLE.getColor());

                break;

            case PEACH:

                System.out.println(34+" kcal"+Fruit.PEACH.getColor());

                break;

            case BANANA:

                System.out.println(93+" kcal"+Fruit.BANANA.getColor());

                break;

        }

    }

}


enum은 맴버 전체를 열거 할 수 있는 기능도 제공한다.

enum Fruit{

    APPLE("red"), PEACH("pink"), BANANA("yellow");

    private String color;

    Fruit(String color){

        System.out.println("Call Constructor "+this);

        this.color = color;

    }

    String getColor(){

        return this.color;

    }

}

 

enum Company{

    GOOGLE, APPLE, ORACLE;

}

 

public class ConstantDemo {

     

    public static void main(String[] args) {

        for(Fruit f : Fruit.values()){

            System.out.println(f+", "+f.getColor());

        }

    }

}

열거형의 특성을 정리해보자. 열거형은 연관된 값들을 저장한다. 또 그 값들이 변경되지 않도록 보장한다. 뿐만 아니라 열거형 자체가 클래스이기 때문에 열거형 내부에 생성자, 필드, 메소드를 가질 수 있어서 단순히 상수가 아니라 더 많은 역할을 할 수 있다.


'Programing > Java' 카테고리의 다른 글

[Java] 예외 만들기  (0) 2014.12.25
[Java] 예외 처리 기본  (0) 2014.12.25
[Java] enum  (0) 2014.12.25
[Java] for-each문  (0) 2014.12.23
[Java] 오토박싱  (0) 2014.12.23
[Java] 익명클래스  (0) 2014.12.23

[Java] for-each문


for-each문


배열과 컬렉션에 저장된 요소에 접근하기 할 때 기존보다 편리한 방법으로 처리할 수 있도록 for문의 새로운 문법이 추가되었다.


1. 배열

for(배열의 타입 변수명 : 배열){

// 반복할 문장

}


2. 컬렉션

for(컬렉션에 저장된 요소의 타입 변수명 : 컬렉션){

// 반복할 문장

}


3. 배열 예제

아래의 두 for문은 서로 동일하다.

int [] arr = {10, 20, 30, 40 50};


for(int i = 0; i<arr.length; i++;){

System.out.println(arr[i]);

}


for(int i : arr){// arr[i]가 아닌 i라는 것에 유의

System.out.println(i);

}

코드 해석: 반복문이 한 번 반복될 때마다 변수 e에 컬렉션 arr의 인덱스가 하나씩 저장되며, e에 저장된 원소와 한 칸의 공백을 출력한다. 반복은 배열의 인덱스 0부터 n-1까지 이루어진다. (배열 자체는 참조만 되기 때문에 변경되지 않음)



4. 컬렉션 예제

이제 ArrayList에 저장된 요소들에 접근하기 위해 for문을 사용한다면 다음과 같을 것이다.

ArrayList<Integer> list = new ArrayList<Integer>();

list.add(new Integer(10));

list.add(new Integer(20));

list.add(new Integer(30));

list.add(new Integer(40));

Iterator it = list.iterator();


for(it.Iterator();){

System.out.println(it.next());

}


for(Integer i : list){

System.out.println(i);

}


'Programing > Java' 카테고리의 다른 글

[Java] 예외 처리 기본  (0) 2014.12.25
[Java] enum  (0) 2014.12.25
[Java] for-each문  (0) 2014.12.23
[Java] 오토박싱  (0) 2014.12.23
[Java] 익명클래스  (0) 2014.12.23
[Java] public static void main(String [] args)  (0) 2014.12.23

[Java] 오토박싱


오토박싱


컬렉션에는 객체로 저장해야하기 때문에 기본형 값을 저장하기 위해서는 Integer나 Long과 같은 Wrapper클래스를 사용해야 했다.

그러나 이제부터는 기본형 값을 직접 컬렉션에 저장할 수 있다. 컴파일러에 의해서 자동적으로 Wrapper클래스로 변환되어 저장되는데 이것을 오토박싱이라고 한다.

뿐만 아니라 저장된 값을 꺼낼 때도 변환과정을 거치지 않고도 기본형 형태의 값을 바로 얻을 수 있는데 이것을 언박싱이라고 한다.


ArrayList list = new ArrayList();

list.add(new Integer(10));

list.add(new Integer(20));

list.add(new Integer(30));

Integer i =(Integer)list.get(0);

int value = i.intValue();


이전에는 위와 같은 코드를 사용했지만 이제는 아래와 같이 코드를 간략히 할 수 있다.

ArrayList<Integer> list = new ArrayList<Integer>();

list.add(10);// 오토박싱

list.add(20);// 오토박싱

list.add(30);// 오토박싱

int value = list.get(0);// 언박싱


'Programing > Java' 카테고리의 다른 글

[Java] enum  (0) 2014.12.25
[Java] for-each문  (0) 2014.12.23
[Java] 오토박싱  (0) 2014.12.23
[Java] 익명클래스  (0) 2014.12.23
[Java] public static void main(String [] args)  (0) 2014.12.23
[Java] 인터페이스  (0) 2014.12.23

[Java] 익명클래스


익명 클래스


익명 클래스는 특이하게도 다른 내부 클래스들과 달리 이름이 없다. 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다. 이름이 없기 때문에 생성자도 가질수 없으며, 조상클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 사용해서 정의하기 때문에 하나의 클래스로 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없다. 오로지 단 하나의 클래스를 상속받거나 단 하나의 인터페이스만을 구현할 수 있다.


class InnerEx6 {

Object iv = new Object(){ void method(){} }; // 익명클래스

static Object cv = new Object(){ void method(){} }; // 익명클래스


void myMethod() {

Object lv = new Object(){ void method(){} }; // 익명클래스

}

}

실행결과)

InnerEX6.class

InnerEX6$1.class(익명 클래스)

InnerEX6$2.class(익명 클래스)

InnerEX6$3.class(익명 클래스)

익명클래스는 이름이 없기 때문에 '외부클래스명$숫자1.class' 형식으로 클래스파일명이 결정된다.


import java.awt.*;

import java.awt.event.*;


class InnerEx7

{

public static void main(String[] args) 

{

Button b = new Button("Start");

b.addActionListener(new EventHandler());

}

}


class EventHandler implements ActionListener

{

public void actionPerformed(ActionEvent e) {

System.out.println("ActionEvent occurred!!!");

}

}


import java.awt.*;

import java.awt.event.*;


class InnerEx8

{

public static void main(String[] args) 

{

Button b = new Button("Start");

b.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

System.out.println("ActionEvent occurred!!!");

}

} // 익명 클래스의 끝

);

} // main메서드의 끝

} // InnerEx8클래스의 끝

앞의 예제에서 익명클래스를 이용해서 변경한 것이 바로 밑의 예제이다. 먼저 두 개의 독립된 클래스를 작성항 다음에, 다시 익명 클래스를 이용하여 변경하면 보다 쉽게 코드를 작성할 수 있다.


'Programing > Java' 카테고리의 다른 글

[Java] for-each문  (0) 2014.12.23
[Java] 오토박싱  (0) 2014.12.23
[Java] 익명클래스  (0) 2014.12.23
[Java] public static void main(String [] args)  (0) 2014.12.23
[Java] 인터페이스  (0) 2014.12.23
[Java] 인터페이스와 다형성  (1) 2014.12.21

[Java] public static void main(String [] args)


public static void main(String[] args)


- 메인 메서드는 진입점(Entry Point)을 뜻한다. 그러므로 메인 메서드의 접근자는 항상 public 이어야 한다. --> public


- 메인 메서드는 항상 정적이어야 한다. 클래스는 메모리에 로딩된 다음에 사용이 가능하다. static이 붙은 클래스나 메서드, 변수는 컴파일시 자동으로 로딩된다. 메인 메서드는 클래스 로딩 없이 호출할 수 있어야 한다. 그렇기 때문에 static을 사용한다. --> static


- void는 리턴타입이 없다는 뜻이다. 메인 메서드는 Entry Point이면서 프로그램의 끝이기도 하다. 메인으로 시작해서 메인이 끝나면 그 프로그램도 끝이다. 그러므로 리턴하는 값 자체가 불필요하다. 프로그램이 끝났는데 마지막에 어떤 값을 리턴해봤자 아무 의미가 없기 때문이다. --> void

 

- String[] args 는 프로그램 실행시 매개변수를 보내서 실행할 수 있다는 것을 뜻한다. 1개를 사용할수도 있고 여러개를 사용할 수도 있기 때문에 배열을 사용한다.


cf.) public과 static은 순서가 바뀌어도 상관없다. 하지만 void는 리턴타입이므로 반드시 메서드 명 앞에 와야 한다.

 public static void main(String[] args){}

 static public void main(String args[]){}


'Programing > Java' 카테고리의 다른 글

[Java] 오토박싱  (0) 2014.12.23
[Java] 익명클래스  (0) 2014.12.23
[Java] public static void main(String [] args)  (0) 2014.12.23
[Java] 인터페이스  (0) 2014.12.23
[Java] 인터페이스와 다형성  (1) 2014.12.21
[Java] 다형성  (0) 2014.12.21