[서론]
Collection (java.util)
객체를 담아주는 저장 창고
ArrayList에 int는 못 담음, integer은 담을 수 있다.
객체 타입에 상관없이 저장 가능(전부 Object로 잡고있다.) -> 항상 형변환 해줘야함.
(컵은 Object - 커피, 물, 주스 다 담을 수 있다.)
부모 = 자식 (부모는 모든 자식 클래스를 참조할 수 있따.)
String a = "apple"
String b = a;
a → "apple" 주소값 담고있다. 클@100
b 클@100 담고있다.
Object로 잡으면 자바의 모든 데이터 다 받을 수 있다.
ob = a; 있다. - 다형성, 부모는 모든 자식의 값 받아도된다.
자식 = 부모 (자식이 부모클래스를 받겠다 X)
자식 = (자식)부모 - 형변환해줘야한다.
부모에 있는 형을 자식의 형태로 변환해주는데 - 강제형변환(cast연산)
매번 형변환하기 귀찮다.
한가지 타입으로 고정시키자 - Generic
크기 조절 가능 - 넣다 뺐다 가능하다. - Collectoin의 가장 큰 특징
배열의 경우 Object니까 어떤게 와도 상관없다. -> Collection도
Object[] ob = {25, 43.8, "apple"}
배열은 한 번 잡은 크기는 바꿀 수 없으므로 Collection 추천
public void sub(int a){} 정수형 데이터를 받고 리턴되는 것 없음.
public int sub(Stirng a. int b){} 매개변수 있고 정수형으로 리턴
public void sub(Object a){} 어떤거 들어와도 상관없다.
하지만 그 때 그 때 형변환해주기는 귀찮다.
Generic은 안정성있다.
T E K V 4개의 문자로 표현해준다.
ArrayList <E> → ArrayList라는 창고에 어떤 타입을 담을건가
T는 쓸 일 별로 없음 → 아 이게 있구나하고만 넘어가면 되고
나머지 E K V만 보면 됨
Package : collection
Class : GenericMain.java
하나의 컵을 가지고 이 때는 이 용도로 나중에는 다른용도로 사용가능
wrapper class → 포장시켜주는 것 - 주소값들어감.
기본형 → 데이터가 들어감.
int a = 10; 직접 데이터가 들어간다.
GenericMain.java
package collection;
public class GenericMain<T> {
private T a;
public void setA(T a) { //자료형 설정 x
this.a = a;
}
public T getA() {
return a;
}
public static void main(String[] args) {
//실행할 때 자료형 잡힘. (데이터를 한 가지 자료형으로만)
GenericMain<String> aa = new GenericMain<>(); //뒤에는 <String>생략가능
aa.setA("홍길동");
System.out.println("이름 = " + aa.getA());
//aa.setA(25); - error(현재 클래스는 generic으로 문자열로 설정해놨기 때문에)
GenericMain<Integer> bb = new GenericMain<>(); //객체타입만 들어가므로 int는 안됨.
bb.setA(25);
System.out.println("나이 = " + bb.getA());
}
}
이름 = 홍길동
나이 = 25
GenericMain<Integer> bb = new GenericMain<>();
객체타입만 들어가므로 wrapper class에 있는 것처럼 int가 아닌 Integer가 들어가야한다.
GenericMain2.java
package collection;
public class GenericMain2<T> {
private T a;
public GenericMain2(T a) { // 생성자 생성해줘야함.
this.a = a;
}
public void setA(T a) { //자료형 설정 x
this.a = a;
}
public T getA() {
return a;
}
public static void main(String[] args) {
GenericMain2<?> aa = new GenericMain2<String>("홍길동");
//String name = aa.getA();
String name = (String)aa.getA(); //형변환해줘야함.
System.out.println("이름 : " + name);
GenericMain.java
GenericMain<String> aa = new GenericMain<>();
aa.setA("홍길동");
System.out.println("이름 = " + aa.getA());
GenericMain<String> aa = new GenericMain<>();
GenericMain2<?> aa = new GenericMain2<String>("홍길동");
두 코드의 차이점을 알아야한다.
하나의 컵을 커피를 컵으로 하기로 했지만 물잔이 없으면 걍 물잔으로 먹는 것처럼 generic을 깨주는방식이라고 보면 된다.
GenericMain2<?> aa = new GenericMain2<String>("홍길동");
String으로 설정했지만 안에서는 돌 때는 Object화 된다.
[안 되는 경우]
※ GenericMain2<?> aa = new GenericMain2<String>();
※ aa.setA("홍길동");
→ 반드시 데이터는 setter가 아니라 생성자를 통해서 넣어야 한다.
※ String name = aa.getA();
"홍길동" 이렇게 String 값으로 받았다고 해서 위의 코드처럼 하면 안된다.
String타입으로 받았어도 Object화가 되므로 반드시 형변환해줘야한다.
String name = (String)aa.getA();
GenericMain2<?> bb = new GenericMain2<Integer>(25); //똑같은 클래스인데 이번에는 정수형으로
int age = (Integer) bb.getA(); // unAutoBoxing
System.out.println("나이 : " + age);
}
}
위에서 언급했듯이 wrapper class는 주소가 들어간다. 하지만 int와 Integer가 같은 계열인 것처럼,
같은계열이면면 스스로 바꿔라하면서 나온게 AutoBoxing이다.
즉, 자동으로 박스처리하겠다.(자동으로 클래스형으로 가겠다.)
반대로 가는 것은 unAutoBoxing이라고 부르며. AutounBoxing이라고도 한다.
int age = (Integer) bb.getA():
Integer로 값을 받아서 int로 변환시켜주는 것이기 때문에 - unAutoBoxing
이름 : 홍길동
나이 : 25
*interface
1. implements
모든 추상메소드 Override (너무 많으며 힘들어진다.)
2. 모든 추상메소드를 Override 해주는 클래스를 찾아라.
Collection coll = new ArrayList(); 대신해주는 클래스 ArrayList
Interface Connection
부모가 2개 - but, 대신해주는 애가 없음
3. 메소드(메소드를 통해서 인터페이스가 만들어짐) (DB들어가면 많이 씀)
Connection에는 메소드 4개가 있다.
4. 익명 inner class (안드로이드 모바일에서는 많이 쓰지만 우리는 별로 안씀)
나쁜 점 모든 추상메소드 Override 해줘야함.
1번은 일회용이고 / 4번은 계속 그 클래스를 써먹을 수 있다.
2번 방식 - Interface Collection<E>
ArrayList를 우리가 썼다. - 배열처럼 저장됨. 중간에 빼고 낄 수는 있다.
인덱스로 관리하므로 검색속도 빠름
사이에 새로운 값 들어가면 인덱스 번호 재배열해야함.
LinkedList 데이터 들어가고 주소가 따라다님 → 데이터+주소 → 데이터
주소를 가지고 따라가므로 검색속도 느림
대신 넣다뺐다가 쉬움. (주소가지고 값 바꾸고 하면 됨)
Stack은 컵처럼 생김 마지막에 들어온게 첫 번째로 나간다.(LIFO)
함수 저장하려할 때 Stack 쓰는게 좋다.
main() -> menu() -> menu 닫히고 나서 main 닫아야함.
CPU가 명령어 실행할 때는 Queue 사용
+ - * / 큐 속에 명령어 저장 / 먼저 들어간게 먼저 처리됨(FIFO)
→ 자바에서는 이런 것들을 Collection이라고 함.
Collection coll = new ArrayList();
ArrayList가 Collection에 있는거 전부 다 Override → 상속받은 것처럼 보인다.
ArrayList에는 get(int index)가 있다. Collection은 안 가지고 있다.
그러므로 Iterator 사용해야함.
Package : collection
Class : SetMain.java
CollectionMain2랑 비교
Set<E> - interface다.
얘도 오버라이드 해주는 애들있음 - HashSet / TreeSet ...
set은 중복허용 안 하고 순서가 없다는 것
ArrayList는 중복허용하고 순서가 있다는 것
SetMain.java
package collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetMain {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("호랑이");
set.add("사자");
set.add("호랑이"); //중복허용 X, 순서X
set.add("기린");
set.add("코끼리");
//인터페이스의 메소드를 통해서 생성한 방법
Iterator<String> it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
호랑이
코끼리
기린
사자
CollectionMain2.java
package collection;
import java.util.ArrayList;
public class CollectionMain2 {
//둘의 차이점 확인
public static void main(String[] args) {
//안에 뭐가 들었는지 알려주는거 <String>
ArrayList<String> list = new ArrayList<String>();
list.add("호랑이");
list.add("사자");
list.add("호랑이"); //중복허용, 순서
//list.add(25);
//list.add(43.8);
list.add("기린");
list.add("코끼리");
for(int i=0; i<list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("------------");
for(String data : list) {
System.out.println(data);
}
}
}
호랑이
사자
호랑이
기린
코끼리
------------
호랑이
사자
호랑이
기린
코끼리
Interface Map<K, V>
key - 모델명 value - 값
indexOf() 값이 없으면 -1 가져옴
MapMain.java
package collection;
import java.util.HashMap;
import java.util.Map;
public class MapMain {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("book101", "백설공주");
map.put("book201", "인어공주");
map.put("book102", "백설공주");//Value 중복허옹
map.put("book301", "쟈스민");
map.put("book101", "엄지공주"); //Key 중복허용
map.put("book401", "덕혜옹주");
System.out.println(map.get("book101")); //키에 해당하는 값 꺼내줌.
System.out.println(map.get("book301"));
System.out.println(map.get("book501")); //null
System.out.println();
Map<String, String> map = new HashMap<>();
키와 값이 모두 String 타입인 HashMap 객체를 생성한다.
map.put() → put 메서드를 사용하여 맵에 데이터를 삽입한다.
- book101 키는 처음에는 "백설공주" 값을 가지지만, 이후 "엄지공주"로 덮어씌워진다. 이는 Map이 동일한 키를 허용하지 않기 때문이다.
- 값은 중복될 수 있다. 예를 들어, "백설공주" 값은 두 번 삽입된다.
map.get() → get 메서드를 사용하여 키에 해당하는 값을 검색한다.
존재하지 않는 키 (book501)를 검색하면 null을 반환한다.
//set형식으로 바꿔서 하나씩 넘겨준다.
for(Map.Entry<String, String> data : map.entrySet()) {
String key = data.getKey();
String value = data.getValue();
System.out.println("key : " + key + "\tvalue : " + value);
}
}
}
for(Map.Entry<String, String> data : map.entrySet()) {
- entrySet 메서드를 사용하여 Map의 모든 키-값 쌍을 Set 형식으로 가져온다.
- for-each 루프를 사용하여 각 Map.Entry 객체를 순회한다.
- 각 키와 값을 출력한다.
엄지공주
쟈스민
null
key : book201 value : 인어공주
key : book102 value : 백설공주
key : book301 value : 쟈스민
key : book101 value : 엄지공주
key : book401 value : 덕혜옹주
Stack구조는 컵처럼 되어있음.
ArrayList - add / Map - put / Stack -push
StackMain.java
package collection;
import java.util.Stack;
import static java.lang.System.out;
public class StackMain {
public static void main(String[] args) {
String[] groupA = {"우즈베키스탄", "쿠웨이트", "사우디", "대한민국"};
Stack<String> stack = new Stack<String>();
for(int i=0; i<groupA.length; i++)
stack.push(groupA[i]);
while(!stack.isEmpty())
out.println(stack.pop());
}
}
대한민국
사우디
쿠웨이트
우즈베키스탄
push통해서 0번째 방부터 넣음. 우즈베키스탄, 쿠웨이트, 사우디, 대한민국 순으로 들어감.
→ 대한민국
사우디
쿠웨이트
우즈베키스탄
:대한민국 (비어있는지 물어보고 안 비어있으면 pop통해서 꺼내옴)
→ 사우디
쿠웨이트
우즈베키스탄
:사우디
끝나면 나옴.
out.println(stack.pop());
이 경우는 위에 import static java.lang.System.out; 이거 꼭 해줘야함.
LinkedList
검색속도가 느림
LinkedListMain.java
package collection;
import java.util.LinkedList;
import static java.lang.System.out;
public class LinkedListMain {
public static void main(String[] args) {
String[] item = {"소나타", "렉스톤", "제규어"};
LinkedList<String> q = new LinkedList<String>();
for(String n : item)
q.offer(n);//요소 추가
out.println("q의 크기:" + q.size() + "\n");
String data ="";
while( (data = q.poll()) != null) {
out.println(data + "삭제!");
out.println("q의 크기:" + q.size() + "\n");
}
}
}
넣을 때 offer / 꺼낼 때 poll
item에 있는 값을 꺼내서 String 타입의 n에 집어넣는다.
소나타 → 렉스톤 → 제규어
큐의 사이즈는 몇개입니까? 3개
q.poll 통해서 꺼내서 data에 집어넣음 소나타는 null이 아닙니까? 아니니까 삭제하고 size 출력
렉스톤 삭제 큐 1개
꺼낼 값 없으면 null 빠져나오면 된다.
String data ="";
초기화를 시켜주는데 만약에 오류가 안 뜨면 초기화 안 해도된다.
String data = null과 같은 의미라는거!
q의 크기:3
소나타삭제!
q의 크기:2
렉스톤삭제!
q의 크기:1
제규어삭제!
q의 크기:0
배열처럼 잡히는 데 하나의 책꽂이로 생각하면 됨.
VectorMain.java
package collection;
import java.util.Iterator;
import java.util.Vector;
public class VectorMain {
public static void main(String[] args) {
Vector<String> v = new Vector<String>();
System.out.println("벡터 크기 = " + v.size()); //0
System.out.println("벡터 용량 = " + v.capacity());//기본용량 10, 항목이 들어갈 공간이 없으면 10개씩 자동으로 증가
System.out.println();
System.out.println("항목 추가");
for(int i=1; i<=10; i++) {
v.add(i + ""); //+ "" 벡터 안에 String 들어가게 했으므로 -> String으로 바뀌면서 값이 들어감.
System.out.print(v.get(i-1) + " ");//index는 0부터 시작하므로 -1 시켜줘야함.
}//for
v.add(i + "");
i + ""는 i를 문자열로 변환하는 방법이다.
이는 문자열 연결 연산자 +를 사용하여 i와 빈 문자열 ""을 연결하면 i가 문자열로 변환된다.
System.out.println();
System.out.println("벡터 크기 = " + v.size()); //0
System.out.println("벡터 용량 = " + v.capacity());//10 꽉참
System.out.println();
v.addElement(5 + "");// 중복 허용
System.out.println("벡터 크기 = " + v.size()); //11
System.out.println("벡터 용량 = " + v.capacity());//20
System.out.println();
항목이 들어갈 공간이 없으면 10씩 증가해주므로 값 하나가 추가됐지만 용량은 20으로 된다.
for(int i=0; i<v.size(); i++) {
System.out.print(v.get(i) + " ");
}
System.out.println();
System.out.println("항목 5를 삭제");
v.remove(5); //index 5번 항목 6 삭제
v.remove(5 + ""); //중복된 5 중에 앞에꺼가 지워짐 - 처음만난거 지워짐. 뒤에있는거 지우고 싶으면 인덱스 이용해야함.
System.out.println(v); //[1, 2, 3, 4, 5, 7, 8, 9, 10, 5] -> 주소값 찍는 것 -> toString으로 Override 된 상태(성적부분이랑 똑같)
System.out.println();
//Iterator 사용
Iterator<String> it = v.iterator();
while(it.hasNext()) {
System.out.print(it.next() + " ");
}
System.out.println();
}
}
벡터 크기 = 0
벡터 용량 = 10
항목 추가
1 2 3 4 5 6 7 8 9 10
벡터 크기 = 10
벡터 용량 = 10
벡터 크기 = 11
벡터 용량 = 20
1 2 3 4 5 6 7 8 9 10 5
항목 5를 삭제
[1, 2, 3, 4, 7, 8, 9, 10, 5]
1 2 3 4 7 8 9 10 5
예외처리 - 생각지도 못하게 예외가 발생하는 거 해결하려는 것
중간에 멈추는걸 최대한 복구하거나 하는것
1. 예외처리의 최상위 클래스는 Exception
부모 Throwable 바로 밑에 Exception
- 컴파일할 때 - 예방차원(보험처리)
try-catch(보험 직접드는거) / throws(보험설계사에게 맡기는거 - JVM)
- 실행할 때 - NullPointerException
비즈니스 로직으로 처리한다.
컴파일할 때는 예외처리가 안나옴. 실행할 때 나는 문제는 프로그램을 잘 못 짰을 때
try {
error가 발생할 가능성이 있는 영역 A
} catch( ){
error가 발생하면 처리되는 부분 B
}
C
error X : A → C
error O : A → B → C
try {
}catch( ){
}catch( ){
}
try{
}catch( ){
}finallt {
error가 있건 없건 무조건 실행하는 부분
}
Package : exceptio
Class : ExceptionMain.java
ArrayIndexOutOfBoundsException
개발자 실수 → 데이터만 잘 넣어주면 됨
아니면 비즈니스 로직으로 막아주면 error 안 뜬다.
NumberFormatException
args[0] "호랑이"는 숫자 형식이 아니므로 바꿀 수 없다.
일반사용자에게 이렇게 하면 모른다.
error 메시지를 예쁘게 바꿔줄 수 있다. - try-catch이용
ArithmeticException
수학 연산에 맞지않는다 0으로 나눌 수 없다.
Run Configurations 방식으로 데이터 값 넣어줌.
ExceptionMain.java
package exception;
import java.util.Scanner;
public class ExceptionMain {
public static void main(String[] args) {
if(args.length != 0) System.out.println("args[0] = " + args[0]);
System.out.println();
try {
int num1 = Integer.parseInt(args[0]);//error 일어나면 밑에꺼 수행 안하고 바로 catch로 간다.
Scanner scan = new Scanner(System.in);
System.out.print("숫자 입력 : ");
int num2 = scan.nextInt();
System.out.println(num1 + " / " + num2 + " = " + (num1/num2));
}catch(NumberFormatException e) {
System.out.println("숫자 형식으로 넣으세요.");
e.printStackTrace();
}catch(ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다.");
e.printStackTrace();
}finally {
System.out.println("error가 있건 없건 무조건 실행!!");
}
}
}
args[0] = 호랑이
숫자 형식으로 넣으세요.
java.lang.NumberFormatException: For input string: "호랑이"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at exception.ExceptionMain.main(ExceptionMain.java:12)
error가 있건 없건 무조건 실행!!
args[0] = 25
숫자 입력 : 0
0으로 나눌 수 없습니다.
java.lang.ArithmeticException: / by zero
at exception.ExceptionMain.main(ExceptionMain.java:18)
error가 있건 없건 무조건 실행!!
args[0] = 25
숫자 입력 : 12
25 / 12 = 2
error가 있건 없건 무조건 실행!!
ExceptionMain2.java
IO(Input Output) - 입력 / 출력
Application ← 데이터 들어온다
→ 데이터 나간다.
길을 만들어주는게 Stream
키보드를 통해서 데이터가 들어오고 모니터 화면을 통해서 데이터를 출력한다.
system.in / system.out
파일을 통한 입출력 - 컴퓨터 껐다 켜도 살아있다.
순서대로 들어갔다가 순서대로 나온다.
파일은 보관용으로 많이 쓴다.
DB는 정형화된 데이터 / if pw name 크기가 정해져서 들어감. → Oracle, MySQL
AI는 비정형 데이터
데이터가 들어갈 수 있는 길을 잡는 것 - IO Stream
입력 출력 다른길
ExceptionMain2.java ←(BufferesReader) buffer ← ( InputStreamReader )키보드
파이프 설치 - <버퍼리더통해서 읽음> ← <클래스로 키보드에서 발생한 데이터 - 버퍼로 이동>
x
y
ExceptionMain2.java
package exception;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class ExceptionMain2 {
private int x, y;
private int mul=1;
public void input() throws IOException{ //구현부
//데이터가 흘러갈 수 있는 길을 만들어준거
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("x값 입력 : ");
x = Integer.parseInt(br.readLine()); //readLine - String으로만 받을 수 있기 때문에
System.out.print("y값 입력 : ");
y = Integer.parseInt(br.readLine());
}
public void output() {
for(int i=0; i<y; i++) {
mul *=x;
}
System.out.println(x + "의 " + y + "승은 " + mul);
}
public static void main(String[] args) throws IOException{ //호출부도 같이 걸어줘야함.
ExceptionMain2 em = new ExceptionMain2();
em.input(); //호출부
em.output();
}
}
x값 입력 : 2
y값 입력 : 5
-----------------------
2의 5승은 32
throw 메소드 구현부에 걸면 호출부에도 걸어야되는 번거로움이 있다.
class Test{
public void sub() throws IOException{}
}
class Sample extends Test{
public void sub() throws IOException{ }
}
throws IOException 부모한테도 걸어줘야한다.
→ 편하지않음. 상속관계로 있으면 다 가서 걸어줘야한다.
그럴 때는 try-catch가 훨씬 편하다.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
이 코드의 말을 이해하기 위해 차례차례 설명을 해보면
1. System.in
- System.in은 Java에서 표준 입력 스트림을 나타내며, 일반적으로 콘솔로부터 입력을 받는 데 사용된다.
- System.in은 바이트 스트림(InputStream)으로, 바이트 단위의 데이터를 읽는는다. 이 때문에 문자 데이터(텍스트)를 읽기에는 적합하지 않다.
2. InputStreamReader
- InputStreamReader는 바이트 스트림을 문자 스트림으로 변환하는 브릿지 역할을 한다.
- System.in을 인자로 받아 InputStreamReader 객체를 생성한다.
- 이 객체는 바이트 데이터를 문자 데이터로 변환하여 읽을 수 있게 해준다.
3. BufferedReader
- BufferedReader는 문자 입력 스트림을 버퍼링하여 효율적으로 읽을 수 있게 한한다.
- InputStreamReader 객체를 인자로 받아 BufferedReader 객체를 생성한다.
- BufferedReader는 버퍼링을 통해 한 번에 여러 문자를 읽고, 읽기 작업을 효율적으로 처리한다.
- 주로 readLine() 메서드를 사용하여 한 줄씩 읽을 때 사용된다.
[요약]
- System.in : 표준 입력 스트림(콘솔 입력).
- new InputStreamReader(System.in) : 바이트 입력 스트림을 문자 입력 스트림으로 변환.
- new BufferedReader(new InputStreamReader(System.in))
: 문자 입력 스트림을 버퍼링하여 효율적으로 읽음.
throws는 에러를 잡아주는 백신
throw는 바이러스
throw new Exception("y는 0보다 크거나 같아야 한다.");//강제로 Exception 발생
package exception;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class ExceptionMain2 {
private int x, y;
private int mul=1;
public void input() throws IOException{ //구현부
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //데이터가 흘러갈 수 있는 길을 만들어준거
System.out.print("x값 입력 : ");
x = Integer.parseInt(br.readLine()); //readLine - String으로만 받을 수 있기 때문에
System.out.print("y값 입력 : ");
y = Integer.parseInt(br.readLine());
}
public void output() {
if(y>=0) {
for(int i=0; i<y; i++) {
mul *=x;
}
System.out.println(x + "의 " + y + "승은 " + mul);
}else {
//System.out.println("y는 0보다 크거나 같아야 한다.");
try {
throw new Exception("y는 0보다 크거나 같아야 한다.");//강제로 Exception 발생
}catch(Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException{ //호출부도 같이 걸어줘야함.
ExceptionMain2 em = new ExceptionMain2();
em.input(); //호출부
em.output();
}
}
x값 입력 : 2
y값 입력 : -1
java.lang.Exception: y는 0보다 크거나 같아야 한다.
at exception.ExceptionMain2.output(ExceptionMain2.java:34)
at exception.ExceptionMain2.main(ExceptionMain2.java:45)
public class MakeException extends Exception
Exception을 상속했으므로 이제 예외처리는 MakeException에서 작성한 것으로 해준다.
즉, 사용자가 만든 예외처리 클래스라고 생각하면 된다.
MakeException.java
package exception;
public class MakeException extends Exception { //사용자가 만든 예외처리 클래스
private String errorMsg;
public MakeException() {}
public MakeException(String errorMsg) {
super();
this.errorMsg = errorMsg;
}
@Override
public String toString() {
return super.toString();
}
}
ExceptionMain2.java
package exception;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class ExceptionMain2 {
private int x, y;
private int mul=1;
public void input() throws IOException{ //구현부
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //데이터가 흘러갈 수 있는 길을 만들어준거
System.out.print("x값 입력 : ");
x = Integer.parseInt(br.readLine()); //readLine - String으로만 받을 수 있기 때문에
System.out.print("y값 입력 : ");
y = Integer.parseInt(br.readLine());
}
public void output() {
if(y>=0) {
for(int i=0; i<y; i++) {
mul *=x;
}
System.out.println(x + "의 " + y + "승은 " + mul);
}else {
//System.out.println("y는 0보다 크거나 같아야 한다.");
try {
//throw new Exception("y는 0보다 크거나 같아야 한다.");//강제로 Exception 발생
throw new MakeException("y는 0보다 크거나 같아야 한다.");//강제로 Exception 발생
}catch(Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException{ //호출부도 같이 걸어줘야함.
ExceptionMain2 em = new ExceptionMain2();
em.input(); //호출부
em.output();
}
}
/*
x값 입력 : 2
y값 입력 : 5 input()
-----------------------
2의 5승은 xx output()
*/
x값 입력 : 2
y값 입력 : -1
exception.MakeException
at exception.ExceptionMain2.output(ExceptionMain2.java:35)
at exception.ExceptionMain2.main(ExceptionMain2.java:47)
- 예외 상황을 명확하게 구분하고, 예외 메시지를 통해 문제의 원인을 쉽게 파악할 수 있게 한다.
- 코드의 가독성을 높이고 유지보수를 쉽게 만든다.
이와 같이 사용자 정의 예외를 사용하면 예외 처리를 더 명확하고 구체적으로 할 수 있다.
Java Project : 10_io
Package : io
Class : DataStream.java
IO Stream
입출력 처리
1. byte 단위 처리(숫자, 영문자 처리할 때 좋음)
InputStream
OutputStream
2. 문자(2byte) 단위 처리 - 속도 더 느려짐 한글 안 깨짐
Reader
Writer
BufferedInputStream - byte 한글 깨짐
BufferedReader - 문자 단위 한글 안 깨짐
FileInputStream - 파일을 byte 단위로 가져오겠다.
FileReader - 파일은 문자단위로 읽어오겠다.
InputStream - byte단위로 처리
추상클래스 → new InputStream( ) X
자식들이 많음 어떤 매체를 통해 읽어올지 ex) FileInputStream
OutputStream - 추상클래스 - 직접적인 생성을 못 함.
[OutputStream의 자식들]
- BufferedOutputStream
String "apple" → byte[] a | p | p | l | e 다 쪼개 보내야함.
write 메소드 2개뿐
- DataOutputStream (오늘 실습)
write 메소드 많음 - 각종의 자료형 다 찍을 수 있음
정수형, 실수형일 때마다 자료형을 다 다르게 찍어야함.
- PrintStream ← 자바는 얘를 제일 좋아함. 이유-오버로드 되어있음.
print 메소드 다 똑같음.
System.out.print(
print 하나만 외우면 자료형 상관없이 다 찍어낼 수 있음.
DataStream.java → 버퍼(임시 기억저장소)로 데이터 들어감. → 파일 안에 저장
홍길동 DateOutputStream FileOutputStream result.txt
25
185.3
갖고있는 데이터를 파일 속에 저장하고싶은것
데이터가 흘러가세요 스트림을 통해서 저장하는
출력할 때 파일이 없으면 파일 자동으로 생성해줌.
현재 입력시 파일이 없으면 error 발생시
11_io에 두고 F5키를 누르면 result.txt 파일 나옴.
한글이 깨져서 들어온다. byte 단위(OutputStream)로 처리하면 깨질 수밖에 없다.
읽어줘야된다.
DataStream.java
1. 파일에 데이터 쓰기
package io;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStream {
public static void main(String[] args) throws IOException { //FileNotFoundException는 자식 IOException 하나만 있어도 됨.
//DataOutputStream dos = new DataOutputStream(new FileOutputStream("result.txt")); //괄호 안쪽부터 수행됨.
FileOutputStream fos = new FileOutputStream("result.txt");
DataOutputStream dos = new DataOutputStream(fos);
dos.writeUTF("홍길동");
dos.writeInt(25);
dos.writeDouble(185.3);
dos.close();
- DataOutputStream: 기본 데이터 타입을 파일에 바이트 형태로 쓸 수 있도록 도와준다.
- DataInputStream: 바이트 형태로 저장된 기본 데이터 타입을 읽어들일 수 있도록 도와준다.
- FileOutputStream: 파일에 바이트 스트림을 작성할 수 있도록 한다.
- FileInputStream: 파일로부터 바이트 스트림을 읽어올 수 있도록 한다.
- FileOutputStream fos = new FileOutputStream("result.txt");
"result.txt"라는 파일에 바이트 스트림을 작성하기 위한 FileOutputStream 객체를 생성합니다. 파일이 존재하지 않으면 새로 생성한다.
- DataOutputStream dos = new DataOutputStream(fos);
FileOutputStream 객체를 이용해 DataOutputStream 객체를 생성한다. DataOutputStream은 다양한 기본 데이터 타입을 손쉽게 파일에 쓸 수 있도록 한다.
2. 파일에서 데이터 읽기
//파일에 들어간 순서대로 나온다.
DataInputStream dis = new DataInputStream(new FileInputStream("result.txt")); //읽을 때 파일 없으면 error 떨어짐 파일 정확하게 써줘야한다.
String name = dis.readUTF();
int age = dis.readInt();
double height = dis.readDouble(); //자료형 똑같이 꺼내와야한다.
System.out.println("이름 = " + name);
System.out.println("나이 = " + age);
System.out.println("키 = " + height);
dis.close();
}
}
- DataInputStream dis = new DataInputStream(new FileInputStream("result.txt"));
"result.txt" 파일로부터 바이트 스트림을 읽어오기 위한 FileInputStream 객체를 생성하고, 이를 이용해 DataInputStream 객체를 생성한다.
이름 = 홍길동
나이 = 25
키 = 185.3
[요약]
이 코드는 DataOutputStream을 사용하여 데이터를 파일에 순차적으로 작성하고, DataInputStream을 사용하여 해당 데이터를 순차적으로 읽어오는 과정이다.
데이터를 작성할 때 사용한 순서와 동일한 순서로 데이터를 읽어와야 제대로 된 값을 얻을 수 있다. 입출력 스트림을 닫는 것은 매우 중요하다.
이를 통해 데이터가 파일에 올바르게 저장되고 시스템 자원이 해제된다.
Project 명에서 data.txt
사진 설명을 입력하세요.
BufferedInputStream
read( ) 메소드 - 한글자 한글자 읽어서 int형으로 꺼내온다.
읽을 값 없으면 -1을 출력함.
656667681310495051521310434542471310
A B C D 1 2 3 4 + - * /
1310
엔터 → 커서 맨 앞으로 \r
→ 다음 줄로 이동 \n
ByteStream.java
package io;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStream {
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("data.txt"));
int data; //read로 읽으면 정수형으로 가져오므로 int
//파일에서 1글자씩 읽기
while( (data=bis.read()) != -1 ) { //한글자 한글자 읽어온다.
System.out.print((char)data); //문자로 보여주세요.
}
System.out.println();
bis.close();
}
}
- BufferedInputStream: 입력 스트림을 버퍼링하여 입출력 성능을 향상시킨다.
- FileInputStream: 파일로부터 바이트 스트림을 읽어올 수 있도록 한다.
- read(): 입력 스트림에서 한 바이트를 읽어옵니다. 더 이상 읽을 데이터가 없으면 -1을 반환한다.
- FileInputStream 객체를 생성하여 "data.txt" 파일을 읽을 준비를 한다.
- BufferedInputStream 객체를 생성하여 FileInputStream 객체를 감싼다.
버퍼를 사용하여 입력 효율을 높인다.
버퍼링을 통해 파일 읽기 성능을 향상시킬 수 있다.
- while ((data = bis.read()) != -1) { ... }
bis.read() 메소드는 파일로부터 한 바이트를 읽어온다. 더 이상 읽을 데이터가 없으면 -1을 반환한다.
while 루프는 파일의 끝에 도달할 때까지(-1이 반환될 때까지) 데이터를 읽는다.
- System.out.print((char)data);
읽어온 정수형 데이터를 문자로 변환하여 출력한다. 바이트 데이터를 문자로 변환할 때는 (char) 캐스팅을 사용한다.
ABCD
1234
+-*/
아까는 한 글자 한 글자 읽었다가 없으면 -1
이번엔 한 번에 읽는 방법
사진 설명을 입력하세요.
ByteStream2.java
이 코드는 BufferedInputStream을 사용하여 파일의 모든 내용을 한 번에 읽고,
읽어온 바이트 배열을 문자열로 변환하여 출력하는 예제이다.
package io;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStream2 {
public static void main(String[] args) throws IOException {
File file = new File("data.txt"); //파일 직접적으로 생성
"data.txt" 파일을 나타내는 File 객체를 생성한다. 이 객체는 파일의 경로, 크기, 존재 여부 등의 속성을 확인할 수 있다.
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));// "data.txt" 파일명만 제시
- FileInputStream 객체를 생성하여 file 객체가 가리키는 파일로부터 바이트 스트림을 읽어올 준비를 한다.
- BufferedInputStream 객체를 생성하여 FileInputStream 객체를 감싼다. 버퍼를 사용하여 읽기 성능을 향상시킨다.
int size = (int)file.length(); //파일 크기 long이므로 형변환해줘야함.
//파일의 크기만큼 byte[] 생성
byte[] b = new byte[size];
//파일 안에 내용을 한 번에 읽기
bis.read(b, 0, size); //b 0번째 방만큼 size만큼
System.out.println(new String(b)); // byte[] => String 변환
bis.close();
}
}
bis.read(b, 0, size) 메소드를 사용하여 파일의 내용을 한 번에 바이트 배열 b에 읽어온다.
- b: 데이터를 저장할 바이트 배열
- 0: 데이터를 저장할 배열의 시작 인덱스
- size: 읽을 데이터의 길이 (파일 크기)
ABCD
1234
+-*/
[요약]
이 코드는 BufferedInputStream을 사용하여 파일 "data.txt"의 모든 내용을 한 번에 읽고, 이를 문자열로 변환하여 출력한다.
파일의 크기만큼의 바이트 배열을 생성하여 파일의 내용을 읽어오고, 이를 문자열로 변환하여 출력한다. 마지막으로 스트림을 닫아 리소스를 해제한다.
'JAVA' 카테고리의 다른 글
DAY 11 - interface / iterator (2024.07.17) (0) | 2024.08.12 |
---|---|
DAY 12 - 접근제한자 / 중첩클래스 (2024.07.18) (0) | 2024.08.12 |
DAY 14 - 입출력처리 / 객체 직렬화 / 프로세스 / Thread (1) | 2024.08.12 |
DAY 15 - Thread / Synchronized (2024.07.23) (0) | 2024.08.09 |
DAY 16 - LOMBOK / 시퀀스 객체 / JDBC / DB 연결 (2024.07.24) (0) | 2024.08.09 |