클래스 앞에 final
2.완전하지 않은 메소드 만들기
3.Friend 클래스를 인스턴스 생성이 되지 않는 클래스로 만들어라.
그리고 Friend 클래스의 showBasicInfo 메소드를 몸통이 없는 메소드로 선언하라.
abstract class Friend {
String name;
String phoneNum;
String addr;
public Friend(String name, String phone, String addr) {
this.name = name;
this.phoneNum = phone;
this.addr = addr;
}
public void showData() {
System.out.println("이름 : " + name);
System.out.println("전화 : " + phoneNum);
System.out.println("주소 : " + addr);
}
public void showBasicInfo();
}
인스턴스 생서잉 되지 않는 클래스 > 객체를 생성할 수 없는 클래스를 의미한다.
abstract는 추상 클래스고, 추상 클래스는 하나 이상의 추상 메서드를 가진다. 그래서 showBasicInfo(); 로 추상 메서드로 변경하고 이를 상속하는 클래스에서 구현을 해준다.
extends 이다void methoodOne() { . . . }
abstract void methodTwo();
}
class BBB extends AAA
{
void methodThree() { . . . }
}
class BBB extends AAA{
void methodThree(){}
@Override
void methodTwo(){}
}
AAA클래스에서 abstract 키워드로 선언했기 때문에, 이를 상속하는 하위 클래스 BBB는 추상메소드를 구현해야한다. 그러므로 추상 메서드인 methodTwo를 구현해야한다.
현재 추상 클래스인 AAA에서 methodTwo();가 추상 메소드이기 때문에
5.홍만군은 이번 프로젝트의 실무 담당자이다. 그리고 이번 프로젝트에서 필요한 기능 중 일부를 A사에 의뢰할 생각이다. 홍만군이 의뢰한 기능을 요약하면 다음과 같다.
package com.test.memo;
class Person {
String name, perNum;
public Person(String name, String perNum) {
this.name = name;
this.perNum = perNum;
}
public String getName() {
return name;
}
public String getPerNum() {
return perNum;
}
}
class ResidentNum {// 홍만이가 의뢰한 기능
private Person[] personalInfoArr;
private int cnt;
public ResidentNum(int size) {// 배열의 길이 받아와서 생성
personalInfoArr = new Person[size];
cnt = 0;
}
void addPersonalInfo(String name, String perNum) {// 주민등록번호, 이름 저장
if (cnt < personalInfoArr.length) {// 저장 용량이 초과되면 안되니까
personalInfoArr[cnt++] = new Person(name, perNum);// 받아온 값에 객체 생성해서 배열에 넣어주기
} else {
System.out.println("저장 공간이 부족합니다.");
}
}
String searchName(String perNUm) {// 주민등록번호를 이용한 검색
for (int i = 0; i < cnt; i++) {
if (perNUm == personalInfoArr[i].getPerNum()) {
return personalInfoArr[i].getName();
}
}
return null;// 해당 주민등록번호가 없을 경우
}
}
class Practice3 {
public static void main(String[] args) {
ResidentNum rn = new ResidentNum(10);
rn.addPersonalInfo("정현지", "011030-111111");
rn.addPersonalInfo("박홍석", "222222-222222");
rn.addPersonalInfo("현지수", "333333-333333");
String searchName = rn.searchName("333333-333333");
if (searchName != null) {
System.out.println(searchName);
} else
System.out.println("해당하는 주민번호가 존재하지 않습니다.");
}
}
주민등록번호로 이름 찾는 메소드에서 내가 == 으로 비교했는데 이는 문자의 내용을 비교하는것이 아닌, 참조하는 주소값을 비교하는것이기 때문에 equals를 쓰는게 더 좋다.
public String searchName(String perNum){
for(Person person : personalInfoArrat){
if(person != null && person.getPerNum().equals(perNum){//Person객체들을 순차적으로 접근하고 비교한다.
return person.getName();
}
}
return null;
}그래서 다시 만들어봤다.
package com.test.memo;
import java.util.Scanner;
class Person {
String name, perNum;
Person(String name, String perNum) {
this.name = name;
this.perNum = perNum;
}
String getName() {
return name;
}
String getNum() {
return perNum;
}
}
class InputPerNum {
private Person[] perArr;
private int cnt;
public InputPerNum(int size) {
perArr = new Person[size];
cnt = 0;
}
void addPersonalInfo(String name, String perNum) {
if (cnt < perArr.length) {
perArr[cnt++] = new Person(name, perNum);
} else
System.out.println("저장 공간이 부족합니다.");
}
String searchName(String perNum) {
for (Person per : perArr) {
if (per != null && per.getNum().equals(perNum)) {
return per.getName();
}
}
return "해당하는 주민번호가 존재하지 않습니다.";
}
}
class Practice3 {
public static void main(String[] args) {
InputPerNum in = new InputPerNum(5);
in.addPersonalInfo("현지", "011030-111111");
in.addPersonalInfo("박홍석", "222222-222222");
in.addPersonalInfo("현지수", "333333-333333");
String sName = in.searchName("333333-333333");
System.out.println(sName);
}
}
AbstractInterface.java 를 인터페이스를 이용하는 형태로 변경시켜라
abstract interface PersonalNumberStorage//추상 인터페이스 클래스
{
public abstract void addPersonalInfo(String perNum, String name);//추상화메소
public abstract String searchName(String perNum);
}
class PersonalNumInfo
{
String name;
String number;
PersonalNumInfo(String name, String number)
{
this.name=name;
this.number=number;
}
String getName(){return name;}
String getNumber(){return number;}
}
class PersonalNumberStorageImpl implements PersonalNumberStorage//구현시키는 클래스
{
PersonalNumInfo[] perArr;
int numOfPerInfo;
public PersonalNumberStorageImpl(int sz)
{
perArr=new PersonalNumInfo[sz];
numOfPerInfo=0;
}
public void addPersonalInfo(String name, String perNum)//추상메소드 구현
{
perArr[numOfPerInfo]=new PersonalNumInfo(name, perNum);
numOfPerInfo++;
}
public String searchName(String perNum)//추상 메소드 구현
{
for(int i=0; i<numOfPerInfo; i++)
{
if(perNum.compareTo(perArr[i].getNumber())==0)
return perArr[i].getName();
}
return null;
}
}// 상속이 아닌 , 인터페이스로 선언해주고 구현하도록 interface, implements 로 변경하면
package com.test.memo;
interface ClassOne {
void method1();
}
interface ClassTwo {
void method2();
}
class myClass implements ClassOne, ClassTwo {
public void method1() {
System.out.println("첫번째 클래스 메소드");
}
public void method2() {
System.out.println("두번째 클래스 메소드");
}
}
class Organize {
public static void main(String[] args) {
myClass mc = new myClass();
mc.method1();
mc.method2();
}
}//구현 클래스에서 public 을 반드시 붙여야한다 > 그러지않으니 에러 났다.
package com.test.memo;
interface ClassOne {
void method1();
}
interface ClassTwo {
void method2();
}
interface ClassThree extends ClassOne, ClassTwo{
void method3();
}
class myClass implements ClassThree {
public void method1() {
System.out.println("첫번째 클래스 메소드");
}
public void method2() {
System.out.println("두번째 클래스 메소드");
}
public void method3() {
System.out.println("세번째 클래스 메소드");
}
}
class Organize {
public static void main(String[] args) {
myClass mc = new myClass();
mc.method1();
mc.method2();
mc.method3();
}
}
터
새로운 인터페이스를 생성해서 두개의 인터페이스를 extends로상속(확장)받아주고, 그 상속받은 인터페이스를 클래스에서 구현해준다 > 그래도 추상메소드는 구현 클래스에서 메소드들 모두 구현해줘야한다.
public static final int Mone = 1; > class안에 모든 요일이 존재
interface ClassOne {
int MON=1;
int TUE=2;
int WED=3;
int THU=4;
int FRI=5;
int SAT=6;
int SUN=7;
}
인터페이스에서 변수를 선언하면 > 상수로 취급
public static final이라는 속성을 가진다. 그래서 굳이 붙여주지 않아도 됌.12.System.out.println 오버로딩 된 메소드 중에 public void println(Object x)가 없다고 가정하고 문제12 폴더에 있는 ClassPrinter에 있는 class에 print 메소드를 만드시오.
class ClassPrinter
{
static void print(Object obj){
System.out.println(obj.toString());
}
}
class Point
{
private int xPos, yPos;
Point(int x, int y)
{
xPos=x;
yPos=y;
}
public String toString()
{
String posInfo="[x:"+xPos + ", y:"+yPos+"]";
return posInfo;
}
}
class ImplObjectPrintln
{
public static void main(String[] args)
{
Point pos1=new Point(1, 2);
Point pos2=new Point(5, 9);
ClassPrinter.print(pos1);
ClassPrinter.print(pos2);
}
}
최상위 클래스인 Object를 이용해 받아온 값을 출력해줬다.
Object로 인자를 받는 이유는 다형성과 관련이있다 > 최상위 클래스 이기 때문에 어떤 타입의 객체라도 받을 수 있다.
다양한 타입의 객체를 인자로 전달받을 수 있어서 유연성이 높아진다.
Point num을 인자로 넣고 출력도 가능하지만 Object로 사용하면 유연성 up
interface UpperCasePrinter{
}
class ClassPrinter
{
public static void print(Object obj){
String org = obj.toString();
if(obj instanceof UpperCasePrinter){//객체가 비교하는 타입의 하위클래스인지 아닌지 비교하는 boolean형
org = org.UpperCase();
}
System.out.println(org);
}
}
class PointOne implements UpperCasePrinter
{
private int xPos, yPos;
Point(int x, int y)
{
xPos=x;
yPos=y;
}
public String toString()
{
String posInfo="[x:"+xPos + ", y:"+yPos+"]";
return posInfo;
}
}
class PointTwo
{
private int xPos, yPos;
Point(int x, int y)
{
xPos=x;
yPos=y;
}
public String toString()
{
String posInfo="[x:"+xPos + ", y:"+yPos+"]";
return posInfo;
}
}
class ImplObjectPrintln
{
public static void main(String[] args)
{
PointOne pos1=new PointOne(1, 1);
PointTwo pos2=new PointTwo(2, 2);
PointOne pos3=new PointOne(3, 3);
PointTwo pos4=new PointTwo(4, 4);
ClassPrinter.print(pos1);
ClassPrinter.print(pos2);
ClassPrinter.print(pos3);
ClassPrinter.print(pos4);
}
}
class TV
{
public void onTV()
{
System.out.println("영상 출력 중");
}
}
interface Computer
{
public void dataReceive();
}
class ComputerImpl
{
public void dataReceive()
{
System.out.println("영상 데이터 수신 중");
}
}
class IPTV extends TV implements Computer//상속이 구현보다 앞에 와야함
{
ComputerImpl comp=new ComputerImpl();//인터페이스의 내용과 연관있는 객체 생성해서 아래 추상메서드에서 해당 클래스 이용해서 구현해주기
public void dataReceive()//인터페이스 추상 메서드는 반드시 구현 클래스에서 구현해야함
{
comp.dataReceive();
}
public void powerOn()
{
dataReceive();
onTV();
}
}
class MultiInheriAlternative
{
public static void main(String[] args)
{
IPTV iptv=new IPTV();
iptv.powerOn();
TV tv=iptv;
Computer comp=iptv;
}
}
interface TV
{
public void onTV();
}
class TVImpl
{
public void onTV()
{
System.out.println("영상 출력 중");
}
}
interface Computer
{
public void dataReceive();
}
class ComputerImpl
{
public void dataReceive()
{
System.out.println("영상 데이터 수신 중");
}
}
class IPTV implements TV, Computer
{
ComputerImpl comp=new ComputerImpl();
TVImpl tv = new TVImpl();
public void dataReceive()
{
comp.dataReceive();
}
public void onTV()
{
tv.onTV();
}
public void powerOn()
{
dataReceive();
onTV();
}
}
class MultiInheriAlternative
{
public static void main(String[] args)
{
IPTV iptv=new IPTV();
iptv.powerOn();
TV tv=iptv;
Computer comp=iptv;
}
}
interface TV
{
public void onTV();
}
interface Computer
{
public void dataReceive();
}
class IPTV implements TV, Computer
{
public void dataReceive()
{
System.out.println("영상 데이터 수신 중");
}
public void onTV()
{
System.out.println("영상 출력 중");
}
public void powerOn()
{
dataReceive();//같은 클래스 안에있는 메서드 호출
onTV();
}
}
class MultiInheriAlternative
{
public static void main(String[] args)
{
IPTV iptv=new IPTV();
iptv.powerOn();
TV tv=iptv;
Computer comp=iptv;
}
}
class OuterClass
{
private String myName;
private int num;
OuterClass(String name)
{
myName=name;
num=0;
}
public void whoAreYou()
{
num++;
System.out.println(myName+ " OuterClass "+num);
}
class InnerClass
{
InnerClass()
{
whoAreYou();
}
}
}
class InnerClassTest
{
public static void main(String[] args)
{
OuterClass out1=new OuterClass("First");
OuterClass out2=new OuterClass("Second");
out1.whoAreYou();
out2.whoAreYou();
OuterClass.InnerClass inn1=out1.new InnerClass();
OuterClass.InnerClass inn2=out2.new InnerClass();
OuterClass.InnerClass inn3=out1.new InnerClass();
OuterClass.InnerClass inn4=out1.new InnerClass();
OuterClass.InnerClass inn5=out2.new InnerClass();
}
}
class OuterClassOne
{
OuterClassOne()
{
NestedClass nst=new NestedClass();//static 클래스여서 객체 생성해서 호출 가능
nst.simpleMethod();
}
static class NestedClass//얘는 Nested클래스로 static이 붙어있지만
{
public void simpleMethod()//이 메서드는 붙어있지 않아서 위에서 객체를 생성해서 호출해준
{
System.out.println("Nested Instance Method One");
}
}
}
class OuterClassTwo
{
OuterClassTwo()
{
NestedClass nst=new NestedClass();
nst.simpleMethod();
}
private static class NestedClass
{
public void simpleMethod()
{
System.out.println("Nested Instance Method Two");
}
}
}
class NestedClassTest
{
public static void main(String[] args)
{
OuterClassOne one=new OuterClassOne();//Nested Instance Method One출력
OuterClassTwo two=new OuterClassTwo();//Nested Instance Method Two 출력
OuterClassOne.NestedClass nst1=new OuterClassOne.NestedClass();
nst1.simpleMethod();//Nested Instance Method One 출력
// OuterClassTwo.Nested nst2=new OuterClassTwo.Nested();
// nst2.simpleMethod();
}
}
class OuterClass
{
...
public LocalClass createLocalClassInst()
{
class LocalClass
{
...
}return new LocalClass();
}
}
interface Readable
{
public void read();
}
class OuterClass
{
private String myName;
OuterClass(String name)
{
myName=name;
}
public Readable createLocalClassInst()
{
class LocalClass implements Readable
{
public void read()
{
System.out.println("Outer inst name: "+myName);
}
}
return new LocalClass();
}
}
class LocalClassTest
{
public static void main(String[] args)
{
OuterClass out1=new OuterClass("First");
Readable localInst1=out1.createLocalClassInst();
localInst1.read();
OuterClass out2=new OuterClass("Second");
Readable localInst2=out2.createLocalClassInst();
localInst2.read();
}
}
interface Readable
{
public void read();
}
class OuterClass
{
private String myName;
OuterClass(String name)
{
myName=name;
}
public Readable createLocalClassInst(final int instID)
{
class LocalClass implements Readable
{
public void read()
{
System.out.println("Outer inst name: "+myName);
System.out.println("Local inst ID: "+instID);
}
}
return new LocalClass();
}
}
class LocalParamClassTest
{
public static void main(String[] args)
{
OuterClass out=new OuterClass("My Outer Class");
Readable localInst1=out.createLocalClassInst(111);
localInst1.read();
Readable localInst2=out.createLocalClassInst(222);
localInst2.read();
}
}
interface Readable
{
public void read();
}
class OuterClass
{
private String myName;
OuterClass(String name)
{
myName=name;
}
public Readable createLocalClassInst(final int instID)
{
return new Readable()
{
public void read()
{
System.out.println("Outer inst name: "+myName);
System.out.println("Local inst ID: "+instID);
}
};
}
}
class LocalParamAnonymous
{
public static void main(String[] args)
{
OuterClass out=new OuterClass("My Outer Class");
Readable localInst1=out.createLocalClassInst(111);
localInst1.read();
Readable localInst2=out.createLocalClassInst(222);
localInst2.read();
}
}
interface Readable
{
public void read();
}
class OuterClass
{
private String myName;
OuterClass(String name)
{
myName=name;
}
public Readable createLocalClassInst(final int instID)
{
return new Readable()
{
public void read()
{
System.out.println("Outer inst name: "+myName);
System.out.println("Local inst ID: "+instID);
}
};
}
}
class LocalParamAnonymous
{
public static void main(String[] args)
{
OuterClass out=new OuterClass("My Outer Class");
Readable localInst1=out.createLocalClassInst(111);
localInst1.read();
Readable localInst2=out.createLocalClassInst(222);
localInst2.read();
}
}
모든 소스파일(.java)에서 import문은 package문 다음에, 그리고 클래스 선언문 이전에 위치해야 한다. import문은 package문과 달리 한 소스파일에 여러 번 선언할 수 있다.
package문
import문
클래스 선언
import 패키지명.클래스명;
import 패키지명.*; > static import 문과 함께 사용 x
static 멤버를 호출할 때 클래스 이름을 생략할 수 있어 특정 클래스의 static멤버를 자주 사용할 때 편리하다 > 코드도 간결해짐
import static java.lang.Integer.*; //Integer클래스의 모든 static메소드
import static java.lang.Math.random; //Math.random()만
import static java.lang.System.out; //System.out을 out만으로 참조 가능
import static java.lang.System.out;
import static java.lang.Math.*;
class StaticImportEx1 {
public static void main(String[] args) {
// System.out.println(Math.random());
out.println(random());
// System.out.println("Math.PI :"+Math.PI);
out.println("Math.PI :" + PI);
}
}
정적 메소드를 import static을 사용해서 import한 후에 클래스명 없이 avs();처럼 바로 사용할수 있다.
자바 프로그램을 작성할 때 자바 문법에 맞지 않게 코드를 작성하고 컴파일하려고 하면, 자바 컴파일러는 문법 오류(syntax error)를 발생시킨다.
문법에 맞게 작성되었더라도 프로그램이 실행되면서 예상하지 못한 오류가 발생할 수 있다.
이렇게 시스템이 동작하는 도중에 예상하지 못한 사태가 발생하여 실행 중인 프로그램이 영향을 받는 것을 오류(error) 와 예외(exception) 두 가지로 구분할 수 있다.
오류(error) : 시스템 레벨에서 프로그램에 심각한 문제를 야기하여 실행 중인 프로그램을 종료시킨다.
예외(exception) : 오류와 마찬가지로 실행 중인 프로그램을 비정상적으로 종료 시키지만, 발생할 수 있는 상황을 미리 예측하여 처리할 수 있다.
java에서는 에러 발생 시 자동으로 예외객체가 생성
try {
//예외를 처리하길 원하는 실행 코드;
} catch (e1) {
//e1 예외가 발생할 경우에 실행될 코드;
} catch (e2) {
//e2 예외가 발생할 경우에 실행될 코드;
}
...
finally {
// 예외 발생 여부와 상관없이 무조건 실행될 코드;
}
try 블록 : 기본적으로 제일 먼저 실행되는 코드로, 여기에서 발생한 예외는 catch블록에서 처리된다.
catch 블록 : try 블록에서 발생한 예외 코드나, 예외 객체를 인수로 전달받아 그 처리를 담당한다.
finally블록 : try블록에서 예외가 발생하건 안하건 맨 마지막에 무조건 실행된다.
catch블록과 finally블록은 선택적인 옵션이다.
다른 제어문과는 달리 예외 처리문은 중괄호를 생략할 수 없다.

try 블록에 도달한 프로그램의 제어는 try 블록 내의 코드를 실행합니다.
try 블록에서 예외가 발생하면 catch 핸들러는 다음과 같은 순서로 적절한 catch 블록을 찾게 됩니다.
2-1. 스택에서 try 블록과 가장 가까운 catch 블록부터 차례대로 검사합니다.
2-2. 만약 적절한 catch 블록을 찾지 못하면, 바로 다음 바깥쪽 try 블록 다음에 위치한 catch 블록을 차례대로 검사합니다.
2-3. 이러한 과정을 가장 바깥쪽 try 블록까지 계속 검사하게 됩니다.
2-4. 그래도 적절한 catch 블록을 찾지 못하면, 예외는 처리되지 못합니다.
만약 적절한 catch 블록을 찾게 되면, throw 문의 피연산자는 예외 객체의 형식 매개변수로 전달됩니다.
모든 예외 처리가 끝나면 프로그램의 제어는 finally 블록으로 이동합니다.
finally 블록이 모두 처리되면, 프로그램의 제어는 예외 처리문 바로 다음으로 이동합니다.
만약 1번 try블록에서 예외가 발생하지 않고, 바깥쪽 try블록에서도 예외가 발생하지 않으면, 6번 finally블록이 바로 실행된다.
하지만 1번 try 블록에서 예외가 발생하면, 2번과 3번 catch블록에서 해당 예외를 처리할 수 있는지 검사하게된다.
만약 적절한 catch 블록을 찾지 못하면, 바깥쪽 try 블록의 4번과 5번 catch블록도 차례대로 검사하게된다.
이때 해당 예외를 처리할 수 있는 catch블록을 찾게되면, catch블록을 실행한 후 6번 finally 블록을 실행한다.

컴파일러가 예외처리를 확인하지 않는 RuntimeException 클래스들은 'unchecked 예외'라고 부르고, 예외처리를 확인하는 Exception 클래스들은 'checked예외'라고 부른다.
예외의 최상위 클래스는 Throwable > Object클래스의 하위
Error 는 un-Checked예외이고, 심각한 예외여서 try~catch문으로 예외처리가 되지않는다. 아예 코드를 다시 짜야한다.
Exception는 Checked예외라고 한다. 이를 RunTimeException 과 Other Exceptions가 상속받는다.
RunTimeException 는 un-Checked예외라고 하고, 예외를 해도그만 안해도그만인 클래스들이다.
Other Exceptions 는 Checked 예외라고 하는데, 반드시 예외처리를 해야하는 클래스들이다.
예외처리를 하지 않으면 컴파일도 되지 않는다!!! > 이클립스에서 나오는 오류가 checked예외
RunTimeException 이 아닌 다른 예외들이 이에 속한다.
class ExceptionEx10 {
public static void main(String[] args) {
throw new Exception(); // Exception을 고의로 발생시킨다.
}
}
'Exception 클래스들 (Exception 클래스와 그 자손들)'이 발생할 가능성이 있는 문장들에 대해 예외처리를 해주지 않으면 컴파일조차 되지 않는다.
class ExceptionEx11 {
public static void main(String[] args) {
throw new RuntimeException(); // RuntimeException을 고의로 발생시킨다.
}
}
RunTimeException클래스와 그 자손(RuntimeException클래스들)'에 해당하는 예외는 프로그래머에 의해 실수로 발생하는 것들이기 때문에 예외처리를 강제하지 않는 것이다. 만일 RuntimeException 클래스들에 속하는 예외가 발생할 가능성이 있는 코드에도 예외처리를 필수로 해야 한다면, 아래와 같이 참조 변수와 배열이 사용되는 모든 곳에 예외처리를 해주어야 할 것이다.
try{
int[] arr = new int[10];
System.out.println(arr[0]);
} catch(ArrayIndexOutOfBoundsException ae){
...
} catch(NullPointerException ne) {
...
}특별한 경우가 아니면 try~catch문을 이용해서 예외처리를 하지 않는다.
주로 개발자의 실수에 의한 오류이므로, 런타임 시에 발생할 수 있고, 사전에 예방할 수 있다.
프로그램의 로직 오류를 나타내므로, 예외 처리보다는 미리 예방하는 것이 바람직하다.
예방을 하지 않는 경우에도 프로그램이 적절히 종료될 수 있도록 JVM에서 자동으로 예외가 발생하게 된다.
| 예외 구문 | 이유 |
|---|---|
| ArithmeticException | 정수를 0으로 나눌경우 발생 |
| ArrayIndexOutOfBoundsExcetion | 배열의 범위를 벗어난 index를 접근할 시 발생 |
| ClassCastExcetion | 변환할 수 없는 타입으로 객체를 반환 시 발생 |
| NullPointException | 존재하지 않는 객체를 참조할때 발생 |
| IllegalArgumentException | 잘못된 인자를 전달 할 때 발생 |
| IOException - other exception | 입출력 동작 실패 또는 인터럽트 시 발생 |
| OutOfMemoryException | 메모리가 부족한 경우 발생 |
| NumberFormatException | 문자열이 나타내는 숫자와 일치하지 않는 타입의 숫자로 변환시 발생 |
| InputMismatchException | Scanner가 기대한 유형의 입력이 제공되지 않았을 때 발생 |
에러를 미연에 방지할 수 있다. > 메시지를 통해서
시스템의 안전성을 확보할 수 있다.
에러발생 위치 확인이 가능하고, 적절하게 대처할 수 있다.
프로그램의 원치않는 정지를 막기위해서예외처리는 의무적으로 해야한다.
getMessage 메소드를 호출한다.
예외상황이 발생해서 전달되는 과정을 출력해준다.
프로그램을 종료한다.
에러 정보를 출력할 수 있는 메서드 > 발생한 예외를 메서드 내에서 직접 처리
e.getMessage() : e에서 발생하는에러 이벤트와 함께 들어오는 메세지를 출력해준다.(오류 사유만 표출)
e.toString() : 에러 이벤트의 toString()을 호출해서 간단한 에러 메세지를 확인시켜준다.(오류 내용과 사유 표출)
e.printStackTrace: 에러 발생 근원지를 찾아서 어디서 발생했는지, 메소드 호출의 순서, 예외의 종류 등을 자세히 보여준다.(오류 내용과 사유 표출)
이를 이용해 개발자는 어떤 부분에서 예외가 발생했는지를 파악하고 디버깅할 수 있다.
예외의 전파 경로를 보여주며, 가장 최근에 호출된 메소드부터 역순으로 출력된다.
public static boolean divider(int num1, int num2) {
try {//예외가 발생할 구문
int result = num1/num2;
System.out.println("result: " + result);
return true;
} catch (ArithmeticException e) {//인자에 발생오류 종류와 변수를 넣고 구문작성
System.out.println(e); // 오류 내용과 사유 표출
System.out.println(e.toString()); // 오류 내용과 사유 표출
System.out.println(e.getMessage()); // 오류 사유만 표출
return false;
} finally {
System.out.println("finally 영역"); // finally 영역은 오류발생여부와 상관없이 무조건 실행됨.
}
}
finally영역은 오류 발생 여부와 상관없이 무조건 실행된다!
오류가 발생하면 오류메세지가 출력되고 finally구문 실행되서 출력된다.
finally영역은 이름이 finally일 필요는 없지만 가독성으로 보통 finally가 쓰인다.
try는 예외상황이 발생할만한 영역을 감싸는 용도로 사용이 되고, catch는 발생한 예외의 처리를 위한 코드를 묶어두기 위한 용도로 사용이 된다.
try{
//에러가 발생할 수 있는 코드
throw new Exception(); //강제 에러 출력
}catch (Exception e){
//에러시 수행
e.printStackTrace(); //오류 출력(방법은 여러가지)
throw e; //최상위 클래스가 아니라면 무조건 던져주자
}finally{
//무조건 수행
}
try블록에는 예외가 발생할 수 있는 코드가 위치한다.
try 블록의 코드가 예외없이 정상 실행되면 catch블록의 코드는 실행되지 않고 finally 블록의 코드를 실행한다.
하지만 try 블록의 코드에서 예외가 발생하면 즉시 실행을 멈추고 catch 블록으로 이동하여 예외처리 코드를 실행한다.
그리고 finally 블록의 코드를 실행한다. (finally 블록은 생략 가능합니다.)
try catch 문을 주로 쓰는 구간은 주로 데이터베이스에 데이터를 주고받을 경우 많이사용한다.
데이터베이스를 거쳐올때는 변수가 많이 생기기 때문에 try catch문은 필수다.
public class NullPointerEx {
public static void main(String[] args) {
String str1 = "test";
String str2 = null;
String str2 = "test2";
try {
System.out.println(str1,toString); //정상실행
System.out.println(str2.toString); //예외발생 - catch문으로 이동
System.out.println(str2.toString); //실행안됨
//객체(인스턴스)가 없는데 인스턴스에 있는
//toString()메소드를 호출시도하여 예외 발생함
} catch (Exception e) {//Exception이 예외클래스의 최상위 객체
System.out.println(e.getMessage());//오류메세지 출력 메서드
}
}
}
class Test
{
public static void main(String[] args) throws ArithmeticException
{
hi();
}
public static void hi() throws ArithmeticException
{
bye();
}
public static void bye() throws ArithmeticException
{
System.out.println(10/0); // throw new ArithmeticException()
}
}
메인 메소드 전에는 예외를 처리해야한다 > 그렇지않으면 프로그램이 종료됌
import java.util.Scanner;
class DivideByZero
{
public static void main(String[] args)
{
System.out.print("두 개의 정수 입력: ");
Scanner keyboard=new Scanner(System.in);
int num1=keyboard.nextInt();
int num2=keyboard.nextInt();
try
{
System.out.println("나눗셈 결과의 몫: "+(num1/num2));
System.out.println("나눗셈 결과의 나머지: "+(num1%num2));
}
catch(ArithmeticException e)//Throwable e 도 가능 > 예외 클래스의 최상위 클래스니까
{
System.out.println("나눗셈 불가능");
System.out.println(e.getMessage());
}
System.out.println("프로그램을 종료합니다.");
}
}
예외처리를 이용해서 사용자가 0을 입력했을 때 예외 메시지를 보낼 수 있다.
import java.util.Scanner;
import java.util.InputMismatchException;
class ExceptionCase5 {
public static void main(String[] args) {
Scanner kb = new Scanner(System.in);
try {
System.out.print("a/b... a? ");
int n1 = kb.nextInt();
System.out.print("a/b... b? ");
int n2 = kb.nextInt();
System.out.printf("%d / %d = %d \n", n1, n2, n1/n2);
}
catch(ArithmeticException e) {
e.getMessage();
}
catch(InputMismatchException e) {
// 클래스 Scanner를 통한 값의 입력에서의 오류 상황을 의미하는 예외 클래스
e.getMessage();
}
System.out.println("Good bye~~!");
}
}
import java.util.Scanner;
import java.util.InputMismatchException;
class ExceptionCase6 {
public static void main(String[] args) {
Scanner kb = new Scanner(System.in);
try {
System.out.print("a/b... a? ");
int n1 = kb.nextInt();
System.out.print("a/b... b? ");
int n2 = kb.nextInt();
System.out.printf("%d / %d = %d \n", n1, n2, n1/n2);
}
catch(ArithmeticException | InputMismatchException e) {
e.getMessage();
}
System.out.println("Good bye~~!");
}
}
하나의 try문에서 여러 예외상황이 발생할 경우에 사용한다. > 여러 catch문을 사용해 다양한 예외를 잡을 목적
public class MultiCatchEx {
public static void main(String[] args) {
try{
int[] intArr = new int[5];
int[] intArr2 = null;
//ArrayIndexOutOfBoundsException 발생 > 배열의 범위를 벗어남
for(int i=0; i<6; i++) {
intArr[i] = i;
}
//ArithmeticException 발생 > 정수를 0으로 나눌 수 x
intArr[0] = 100/0;
//NullPointerException 발생 > null값인 객체 참
System.out.println(intArr2.toString());
} catch (ArrayIndexOutOfBoundsException arrayOBE) {
arrayOBE.getMessage();
} catch (ArithmeticException ame) {
ame.getMessage();
} catch (NullPointerException npe) {
npe.getMessage();
} catch (Exception e) {//예외 클래스의 최상위 클래래스로 제일 하단에 위치해야 위 예외처리부분이 다돈다
e.getMessage();
}
}
}
예외발생에 상관없이 항상 수행되는 영역
try영역 수행중 발생한 예외를 해결하고 난뒤 반드시 수행되어야하는 코드가 finally 영역에 기술된다.
주로 database 연결후 자원을 해제하는 코드에 많이 사용되는 코드이다.
예외를 명시적을 ㅏ발생시킬 때 사용
예외가 발생하는 코드를 호출한 곳으로 예외객체를 전달하여 처리를 부탁하는 것 > 객체를 생성하고 발생시키는 것
최상단 클래스를 제외한 나머지 클래스에서의 예외처리는 반드시 Throw를 해야한다.
throw는 예외상황이 발생되었음을 자바 가상머신에게 알리는 키워드이다.

if(조건){throw new 예외클래스("예외처리문자열);}
예외 클래스의 조건에 해당되지 않는데 예외를 만들고싶은 경우, 조건을 설정해서 명시적으로 예외를 발생시키는 방법이다.
만든 후 반드시 예외처리를 해줘야 비정상 종료를 막을 수 있다.
사용하고자 하는 예외클래스의 객체를 생성하고 throw로 예외를 발생시킨 뒤 throws로 넘겨서 예외처리해주고 프로그램을 종료한다.
package com.test.memo;
class Practice3 {
public static void a(int num) throws ArithmeticException {
b(num);
}
public static void b(int num) throws NullPointerException {
if (num == 10) {
// 명시적 강제적으로 특정 Exception 발생시키면서 보여줄 메세지 지정
throw new NullPointerException("널 포인트 익셉션 발생");
// 객체 생성하면서 에러메세지 보여주기
}
}
public static void main(String[] args) {
System.out.println("프로그램 시작");
try {
a(10);
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
}
System.out.println("프로그램 정상종료");
}
}

num이 10인 경우를 예외로 인식하는 예외클래스는 없으므로, 예외를 발생하고 싶다면 throw를 사용해 명시적으로 예외를 지정할 수 있다.
throw 키워드 뒤에 new로 객체생성 해주고 괄호 안에 예외처리 메세지를 적으면된다.
package com.test.memo;
class Practice3 {
public static void main(String[] args) {
ExPractic3 ex = new ExPractic3();
try {
ex.a(10, 0);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
class ExPractic3 {
public static int a(int num1, int num2) throws ArithmeticException {
int result = num1 / num2;
return result;
}
}
객체를 생성해서 a메소드에 인자를 넣어 호출했다. 0으로 나누니까 예외가 발생한다.
public class ExTest {
public int a(int num1, int num2) throws ArithmeticException{
int result = 0;
if(num2 == 0) {
throw new ArithmeticException("0으로 나눌 수 없습니다. 다시 입력해 주세요.");
}else{
result = 0;
result=num1/ num2;
}
return result;
}
}
class ExPractic3 {
public static int a(int num1, int num2) throws ArithmeticException {
int result = num1 / num2;
return result;
}
}
메서드 선언부에서 사용되며, 해당 메서드가 어떤 예외를 던질 수 있는지를 나타낸다.
메서드를 호출한 영역으로 예외가 전될되도록 한다. > 해당 메서드에서 예외를 처리하지않고 떠넘긴다.
throws키워드가 붙어있는 메소드는 반드시 try블록내에서 호출되어야 한다.
여러 개의 예외를 나열하여 throws를 사용할 수 있다.
throws는 예외를 처리하는 것이 아니라, 해당 메서드에서 발생할 수 있는 예외를 선언하는 역할을 한다.
class Test
{
public static void main(String[] args)
{
try
{
hi();
}
catch(ArithmeticException e)
{
System.out.println("0으로 나누면 안돼요.");
}
}
public static void hi() throws ArithmeticException//던져진것을 안받는다고 한다면 메소드에 꼭 명시
{
System.out.println(10/0); // throw new ArithmeticException()
System.out.println("Good");//위에서 던지기 때문에 영원히 출
}
}
hi메소드 호출
예외객체를 생성하고 던진다. > 만약 받지 않는다면(catch가 없음) 해당 메소드에 throws 예외 이름을 작성 = 던져짐을 명시해줘야한다.
그럼 호출한곳으로 다시 돌아간다
catch가 있기때문에= 잡기때문에 0으로 나누면안돼요 문장이 출력된다.
그러므로 good문장을 출력하는 부분은 사용되지 않는다
public class MultiCatchEx {
public static void main(String[] args) {
try {
int x = changeToInteger("test");
int y = printArrayElement(new int[] {1, 2, 3}, 5);
} catch (NumberFormatException nfe){
nfe.getMessage();
} catch (ArrayIndexOutOfBoundsException aiob) {
aiob.getMessage();
} catch (Exception e) {
e.getMessage();
}
}
static int changeToInteger(String str) throws NumberFormatException{
int number = Integer.parseInt(str);
return number;
}
static int printArrayElement(int[] intArr, int index) throws ArrayIndexOutOfBoundsException{
int number = intArr[index];
return number;
}
}
예제 코드를 보면 changeToInteger() 메서드와 printArrayElement() 메서드 수행시 예외가 발생하면 호출한 곳에서
예외를 처리하도록 역할을 양도하고 있다. main 함수에서 두 함수를 호출하고 있으므로 해당 예외를 처리하는코드를 작성했다.
메소드 선언부에 throws를 사용하여 예외를 상위 호출자에게 전파시켜야한다.
public class MultiCatchEx {
public static void main(String[] args) throws Exception {
int x = changeToInteger("test");
int y = printArrayElement(new int[] {1, 2, 3}, 5);
}
static int changeToInteger(String str) throws NumberFormatException{
int number = Integer.parseInt(str);
return number;
}
static int printArrayElement(int[] intArr, int index) throws ArrayIndexOutOfBoundsException{
int number = intArr[index];
return number;
}
}
throws를 사용한 예외객체의 양도는 예외처리와는 다르다. 예외처리할 역할을 해당 코드를 호출한 곳으로 위임하는 것이기 때문에 정상적으로 코드가 실행되기 위해서는 try ~ catch문으로 예외를 적절히 해결해야한다.
그럼에도 throws 코드가 존재하는 이유는, try~catch 문 수행시 내부에서 과도한 로직처리를 막기위해서이다.
예외처리코드가 많은 경우 이를 처리하는 과정에서 과부하가 발생할 수 있다. 이를 방지하기 위해 예외처리코드를 양도한 뒤에, 최종 호출하는 곳에서 try~catch 문으로 한번에 처리해 프로그램이 무거워지지 않도록 하기 위함이다.
public static int readAge() throws AgeInputException
{
Scanner keyboard=new Scanner(System.in);
int age=keyboard.nextInt();
if(age<0)
{
AgeInputException excpt=new AgeInputException();
throw excpt;
}
return age;
}
예외를 객체로 생성해서 보내는 부분을
throw new AgeInputException(); 이라고 한줄로 정의할 수 있다.메소드 안에서 던질때는throw / 메소드에 던져짐을 명시할 때throws
자바에서 제공되는 예외 클래스외에 프로그래머가 직접 만들어야 하는 예외가 있는 경우, 예외 클래스 중에 가장 유사한 예외 클래스를 상속받아 사용자 정의 예외 클래스를 만든다.
class UserException extends Exception {
public UserException(String mesg) {
super(mesg);
}
}
public class Ex09_8 {
public static void check(int num) throws UserException {
if (num < 100) {
throw new UserException("num 값이 100보다 작다");
}
}
public static void main(String[] args) {
System.out.println("프로그램 시작");
try {
check(70);
} catch (UserException e) {
System.out.println("예외발생: " + e.getMessage());
}
System.out.println("프로그램 정상 종료");
}
}
super 키워드는 부모 클래스의 생성자를 호출하는 데 사용된다.super(mesg)를 호출하면, 부모 클래스인 Exception 클래스의 생성자를 호출하여 예외 메시지를 설정하게 된다.public class BalanceInsufficientException extends Exception{ //Exception 상속
public BalanceInsufficientException() {}
public BalanceInsufficientException(String message) {
super(message);
}
}
public class Account {
private long balance;
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;
}
}
public class AccountMain {
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();//그냥 바로 syso해서 e.getMessage();도 가능
System.out.println(message);
System.out.println();
e.printStackTrace();
}
}
}

오버라이딩의 조건
자손 클래스에서 오버라이딩하는 메서드는 조상 클래스의 메서드와
이름이 같아야 한다.
매개변수가 같아야 한다.
반환타입이 같아야 한다.
조상 클래스의 메서드를 자손 클래스에서 오버라이딩할 때
접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
올바른 오버라이딩
class Parent{
void parentMethod() throws IOException, SQLException{
...
}
}
class Child extends Parent {
void parentMethod() throws IOException {
...
}
}
잘못된 오버라이딩
class Child extends Parent{
void parentMethod() throws Exception {
...
}
}
만일 위와같이 오버라이딩 하였다면 Exception은 모든 예외의 최고 클래스이므로(Object보다 아래) 가장 많은 개수의 예외를 던질 수 있도록 선언한 것이다.
인스턴스 메서드를 static메서드로 또는 그 반대로 변경할 수 없다.
조상 클래스에 정의된 static메서드를 자손 클래스에서 똑같은 이름의 static메서드로 정의 가능하다.
그러나 이것은 각 클래스에 별개의 static메서드를 정의한 것일 뿐 오버라이딩은 아니다.
각 메서드는 클래스 이름으로 구별될 수 있으며, 호출할 때는 '참조변수.메서드이름()'대신 '클래스이름.메서드이름()'으로 호출하는것이 맞다.
clone : Object클래스에서 상속받은 메소드로, 객체를 복사하여 새로운 객체를 생성한다. > 객체를 복사할 때 사용
Object 클래스에서 상속받은 메소드 이기 때문에 복사할 자료형으로 형변환 해줘야한다.
Cloneable 인터페이스를 구현하지 않으면 CloneNotSupportedException 이라는 예외를 발생시킨다.
컴파일 에러가 안나게 수정하시오.
public void simpleMethod(int n)
{
MyClass my = new MyClass();
my.clone();
...
}
아래와 같이 try~catch를 삽입하거나
public void simpleMethod(int n)
{
MyClass my = new MyClass();
try
{
my.clone();
}
catch(CloneNotSupportedException e) { ... }
...
}
아래와 같이 throws에 의해서 던져짐을 명시해야 컴파일이 된다.
public void simpleMethod(int n) throws CloneNotSupportedException
{
MyClass my = new MyClass();
my.clone();
........
}
package com.test.joeun;
class Person implements Cloneable {//Cloneable 인터페이스를 구현해야지만 clone메서드를 사용할 수 있다.
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println(name + " " + age);
}
@Override // alt + shift + s > v 하면 오버라이딩 간편하게 가능
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Extest1 {
public static void main(String[] args) {
Person person = new Person("홍길동", 20);
try {
Person cpyPerson = (Person) person.clone();//clone()의 자료형은 Object니까 형변환 시켜야한다. > 복제시에는 new 사용하지않는다.
person.show();
cpyPerson.show();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}

package com.test.memo;
import java.util.Scanner;
class Practice2 {
public static void main(String[] args) {
System.out.println("두 개의 정수 입력:");
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt();
int num2 = sc.nextInt();
try {
System.out.print("나눗셈의 결과: " + (num1 / num2));
System.out.print(" 나눗셈의 결과 나머지: " + (num1 % num2));
} catch (ArithmeticException e) {
System.out.println("나눗셈 불가능");
System.out.println(e.getMessage());
}
System.out.println(" 프로그램을 종료합니다.");
}
}

( )는 예외상황을 알리기 위해서 정의된(또는 앞으로 여러분이 정의할), 모든 예외 클래스들이 상속하는 ( ) 클래스에 정의되어 있는 메소드이다.모든 예외 클래스들이 ( ) 클래스를 상속.
getMessage
Throwable
Throwable
예외 상황을 알리는 클래스
package com.test.memo;
class Practice2 {
public static void main(String[] args) {
try {
int[] arr = new int[3];
arr[-1] = 20;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage());
}
try {
Object obj = new int[10];
String str = (String) obj;
} catch (ClassCastException e) {
System.out.println(e.getMessage());
}
try {
int[] arr = new int[-5];
} catch (NegativeArraySizeException e) {
System.out.println(e.getMessage());
}
try {
String str = null;
int i = str.length();
} catch (NullPointerException e) {
System.out.println(e.getMessage());
}
}
}
package com.test.memo;
import java.util.Scanner;
class Organize {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] arr = new int[100];
for (int i = 0; i < 3; i++) {
try {
System.out.print("피제수 입력: ");
int num1 = sc.nextInt();
System.out.print("제수 입력: ");
int num2 = sc.nextInt();
num2 = 0;
System.out.print("연산결과를 저장할 배열의 인덱스 입력: ");
int idx = sc.nextInt();
arr[idx] = num1 / num2;
System.out.println("나눗셈 결과는 " + arr[idx]);
System.out.println("저장된 위치의 인덱스는 " + idx);
} catch (ArithmeticException e) {
System.out.println("제수는 0이 될 수 없습니다.");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("유효하지 않은 인덱스 값입니다.");
i -= 1;
}
}
}
}
try
{
...
}
catch(Throwable e)
{
...
}
catch(ArithmeticException e)
{
...
}
try~catch는 구체적인 예외부터 처리 해야한다. Throwable은 예외클래스의 최상위 클래스인데 이를 제일 먼저 처리할 경우 ArithmeticException 의 예외처리가 실행되지 않는다.
두번째 캐치블럭에 도달할 수 없는것이다.
정상실행 되려면 Trowable 캐치 문이 마지막에 가야한다!
package com.test.memo;
import java.util.Scanner;
class Practice3 {
public static void main(String[] args) {
int uNum = 0, uNum2 = 0;
Scanner sc = new Scanner(System.in);
System.out.print("숫자를 입력하세요: ");
uNum = sc.nextInt();
System.out.print(uNum + "을 나눌 숫자를 입력하세요: ");
uNum2 = sc.nextInt();
boolean com = comparison(uNum, uNum2);
if (com) {
System.out.println("연산 성공");
} else {
System.out.println("연산 실패");
}
}
public static boolean comparison(int num1, int num2) {
try {
int result = num1 / num2;
System.out.println("나눗셈 결과는: " + result);
return true;
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
return false;
} finally {
System.out.println("finally 영역 실행");
}
}
}
import java.util.Scanner;
class AgeInputException extends Exception
{
public AgeInputException()
{
super("유효하지 않은 나이가 입력되었습니다.");
}
}
class ProgrammerDefineException
{
public static void main(String[] args)
{
System.out.print("나이를 입력하세요: ");
try
{
int age=readAge();
System.out.println("당신은 "+age+"세입니다.");
}
catch(AgeInputException e)
{
System.out.println(e.getMessage());
}
}
public static int readAge() throws AgeInputException
{
Scanner keyboard=new Scanner(System.in);
int age=keyboard.nextInt();
if(age<0)
{
AgeInputException excpt=new AgeInputException();
throw excpt;
}
return age;
}
}

package com.test.memo;
import java.util.Scanner;
class AgeInputException extends Exception {
public AgeInputException() {
super("유효하지 않은 나이가 입력되었습니다.");
}
}
public class Practice1 {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
System.out.print("나이를 입력하세요: ");
try {
int age = keyboard.nextInt();
if (age < 0) {
AgeInputException excpt = new AgeInputException();
throw excpt;//catch문 있으니까 명시적으로 메서드에 throws안넣어도
}
System.out.println("당신은 " + age + "세입니다.");
} catch (AgeInputException e) {
e.printStackTrace();
// System.out.println(e.getMessage());
}
}
}
printStackTrace()는 syso 없어도 된다.

만약 그냥 주석 처리한것처럼 System.out.println(e.getMessage()); 했다면

import java.util.Scanner;
class AgeInputException extends Exception
{
public AgeInputException()
{
super("유효하지 않은 나이가 입력되었습니다.");
}
}
class ThrowsFromMain
{
public static void main(String[] args) throws AgeInputException
{
System.out.print("나이를 입력하세요: ");
int age=readAge();
System.out.println("당신은 "+age+"세입니다.");
}
public static int readAge() throws AgeInputException
{
Scanner keyboard=new Scanner(System.in);
int age=keyboard.nextInt();
if(age<0)
{
AgeInputException excpt=new AgeInputException();
throw excpt;
}
return age;
}
}
가상머신의 예외처리 방식
getMessage 메소드를 호출한다.
예외상황이 발생해서 전달되는 과정을 출력해준다.
프로그램을 종료한다.
예외가 발생해서 전달되는 과정이 출력되는 메소드.
( ) 클래스에 정의되어 있는 ( ) 메소드가 이러한 유형의 메시지를 출력
Throwable
printStackTrace
import java.util.Scanner;
class AgeInputException extends Exception
{
public AgeInputException()
{
super("유효하지 않은 나이가 입력되었습니다.");
}
}
class NameLengthException extends Exception
{
String wrongName;
public NameLengthException(String name)
{
super("잘못된 이름이 삽입되었습니다.");
wrongName=name;
}
public void showWrongName()
{
System.out.println("잘못 입력된 이름: "+ wrongName);
}
}
class PersonalInfo
{
String name;
int age;
public PersonalInfo(String name, int age)
{
this.name=name;
this.age=age;
}
public void showPersonalInfo()
{
System.out.println("이름: "+name);
System.out.println("나이: "+age);
}
}
class PrintStackTrace
{
public static Scanner keyboard=new Scanner(System.in);
public static void main(String[] args)
{
try
{
PersonalInfo readInfo=readPersonalInfo();
readInfo.showPersonalInfo();
}
catch(AgeInputException e)
{
e.printStackTrace();
}
catch(NameLengthException e)
{
e.showWrongName();
e.printStackTrace();
}
}
public static PersonalInfo readPersonalInfo()
throws AgeInputException, NameLengthException
{
String name=readName();
int age=readAge();
PersonalInfo pInfo=new PersonalInfo(name, age);
return pInfo;
}
public static String readName() throws NameLengthException
{
System.out.print("이름 입력: ");
String name=keyboard.nextLine();
if(name.length()<2)
throw new NameLengthException(name);
return name;
}
public static int readAge() throws AgeInputException
{
System.out.print("나이 입력: ");
int age=keyboard.nextInt();
if(age<0)
throw new AgeInputException();
return age;
}
}
"자바 가상머신에 문제가 생겨서 더 이상 제대로 동작할 수 없는 상황을 알리기 위해서 정의된 클래스입니다."
(Error)를 상속하는 클래스의 오류상황이 발생하면, 그냥 프로그램이 종료되도록 놔두는 것이 상책이다(프로그램이 종료된 뒤 소스코드를 수정하는 등의 방식으로 원인을 해결해야 한다.)
(VirtualMachineError)의 하위 클래스
(Error)를 상속하는 대표적인 클래스가 (VirtualMachineError)이다. 그리고 이를 상속하는 클래스 중에서 (OutOfMemoryError)라는 클래스가 있는데, 이는 메모리 공간이 부족한 상황을 표현하는 예외 클래스이다. 따라서 이러한 오류가 발생하면, 메모리가 효율적으로(또는 적절히) 사용되도록 소스코드 자체를 변경해야 한다. 이렇듯 Error와 관련 있는 오류상황은 소스코드의 변경을 통해서 해결해야 하는 경우가 대부분이다.
Exception을 상속하는 대표적인 클래스 두가지
RuntimeException
IOException
Exception을 상속하는 클래스의 예외 상황이 임의의 메소드 내에서 발생 가능하다면, 해당 메소드는 반드시 다음 두 가지 중 한가지 방법을 선택해서 정의되어야 한다.
try~catch문을 이용해서 메소드 내에서 예외를 처리하도록 정의한다.
throws를 이용해서 메소드를 호출한 영역을 예외가 전달되도록 정의한다.
위의 메소드를 호출할 때
다음과 같이 호출하면 문제가 발생한다. 무엇이 문제인가?
public void simpleMethod(int n)
{
MyClass my = new MyClass();
my.clone();
...
}
public void simpleMethod(int n)
{
MyClass my = new MyClass();
try
{
my.clone();
}
catch(CloneNotSupportedException e) { ... }
...
}
public void simpleMethod(int n) throws CloneNotSupportedException
{
MyClass my = new MyClass();
my.clone();
........
}
throws에 의해 던져짐을 명시해야 컴파일이 된다.
특별한 경우가 아니면, 이들에 대해서는 try~catch문을 이용해서 예외처리를 하지않는다.
미리 조건을 검사하고 예외 상황을 방지하는 방법을 더 선호함 > if문들을 이용해