package miniprj.model;
import java.util.ArrayList;
public interface IBookDAO {
public int deleteBook(String name, String password);
public int insertBook(Book book);
public int updateBook(Book book);
public int getBookCount();
public Book getOne(String name, String password);
public ArrayList<Book> getAllBooks();
}
public class WriteExample{
public class void main(String[] args){
try{
OutputStream os = new FileOutputStream("test1.db");
byte a =10;
byte b =20;
byte c =30;
os.write(a);
os.write(b);
os.write(c);
os.flush();
os.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
바이트 배열 출력
public class WriteExample{
public static void main(String[] args){
try{
OutputStream os = new FileOutputStream("test2.db");
byte[] array = {'A','B','C'};
os.write(array);
os.flush();
os.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
바이트 배열 일부분 출력
public class WriteExample{
public static void main(String[] args){
try{
OutputStream os = new FileOutputStream("test3.db");
byte[] array = {'A','B','C','D','E'};
os.write(array,1,3); //B C D 출력
os.flush();
os.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
바이트 입력 스트림
InputStream은 바이트 입력 스트림의 최상위 클래스로 추상 클래스이다.
리턴 타입
메소드
설명
int
read()
1byte 읽은 후 읽은 바이트를 리턴
int
read(byte[] b)
읽은 바이트를 매개값으로 주어진 배열에 저장 후 읽은 바이트 수를 리턴
void
close()
입력 스트림을 닫고 사용 메모리 해제
1바이트 읽기
public class ReadExample{
public static void main(String[] args){
try{
InputStream is = new FileInputStream("test1.db");
whie(True){
int data = is.read();
if(data == -1) break;
System.out.println(data);
}
is.close();
}catch(FileNotFoundException e){
e.printStrackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
}
바이트 배열로 읽기
public class ReadExample{
public static void main(String[] args){
try{
InputStream is = new FileInputStream("test2.db");
byte[] data = new byte[100];
while(true){
int num = is.read(data);
if(num == -1) break;
for(int i=0; i<num; i++){
System.out.println(data[i]);
}
}
is.close();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
}
바이트 배열 읽고 바로 출력하기
public class ReadExample{
public static void main(String[] args){
try{
InputStream is = new FileInputStream("test.txt");
OutputStream os = new FileOutputStream("test2.txt");
byte[] data = new byte[100];
while(true){
int num = is.read(data);
if(num == -1) break;
os.write(data,0,num);
}
os.flush();
os.close();
is.close();
System.out.prinln("복사가 되었습니다");
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
}
문자 입출력 스트림
InputStream과 OutputSTream에 대응하는 문자 입출력 스트림으로는 Reader와 Writer가 있다.
문자 출력
리턴 타입
메소드
설명
void
write(int c)
매개값으로 주어진 한 문자를 출력
void
write(char[] cbuf)
매개값으로 주어진 배열의 모든 문자를 출력
void
write(char[] cbuf, int off, int len)
매개값으로 주어진 배열에서 cbuf[off]부터 len개까지의 문자를 출력
void
flush()
버퍼에 잔류하는 모든 문자를 출력
void
close()
출력 스트림을 닫고 사용 메모리를 해제
public class WriteExample{
public static void main(String[] args){
try{
Writer writer = new FileWriter("text.txt");
//한 문자씩 출력
char a = 'A';
writer.write(a);
char b = 'B';
writer.write(b);
//char 배열 출력
char[] arr={'C','D','E'};
writer.write(arr);
//문자열 출력
writer.write("FGH");
writer.flush();
writer.close();
}catch(IOException e){
e.printStacTrace();
}
}
}
문자 읽기
메소드
설명
int
read()
1개의 문자를 읽고 리턴
int
read(char[] cbuf)
읽은 문자들을 매개값으로 주어진 문자 배열에 저장하고 읽은 수를 리턴
void
close()
입력 스트림을 닫고, 사용 메모리 해제
public class ReadExample{
public static void main(String[] args){
try{
Reader reader = null;
//한 문자씩
reader = new FileReader("test.txt");
while(true){
int data = reader.read();
if(data == -1) break;
System.out.println((char)data);
}
reader.close();
reader = new FileReader("test.txt");
char[] data = new char[100];
while(true){
int num=reader.read(data);
if(num==-1) break;
for(int i=0; i<num; i++){
System.out.print(data[i]);
}
}
reader.close();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
}
InputStream is = new FileInputStream("text.txt");
Reader reader = new InputStreamReader(is);
OutputStream을 Writer로 변환
OutputStream os = new FileOutputStream("text.txt");
Writer writer = new OutputStreamWriter(os);
입출력 성능 향상 스트림
BufferedInputStream bis = new BufferedInputStream(바이트 입력 스트림);
BufferedOutputStream bos = new BufferedOutputStream(바이트 출력 스트림);
BufferedReader br=new BufferedReader(문자 입력 스트림);
BufferedWriter bw = new BufferedWriter(문자 출력 스트림);
기본 타입 스트림
바이트 스트림에 DataInputStream과 DataOutputStream 보조 스트림을 연결하면 기본 타입인 boolean, char, short, int, long, double 값을 입출력할 수 있다.
DataInputStream dis=new DataInputStream(바이트 입력 스트림);
DataOutputStream dos = new DataOutputStream(바이트출력 스트림);
프린트 스트림
프린트 스트림은 print(), println(), prinf() 메소드를 갖고 있는 보조 스트림이다.
PrintStream ps = new PrintStream(바이트 출력 스트림);
PrintWriter pw = new PrintWriter(문자 출력 스트림);
객체 스트림
*직렬화 : 객체를 출력하기 위해 필드값을 일렬로 늘어선 바이트로 변경
*역직렬화 : 직렬화된 바이트를 객체의 필드값으로 복원하는 것
ObjectInputStream ois = new ObjectInputStream(바이트 입력 스트림);
ObjectOutputStream oos = new ObjectOutputStream(바이트 출력 스트림);
oos.writeObject(객체);
객체타입 변수 = (객체타입)ois.readObject();
public class Product{
private int pno;
private String name;
public Product(int pno, String name){
this.pno = pno;
this.name = name;
}
@Override
public String toString(){
return new StringBuilder()
.append("{")
.append("pno : " +pno+", ")
.append("name: " + name + ", ")
.append("}")
.toString();
}
}
public class StreamExample{
public static void main(String[] args){
List<Product> list = new ArrayList<>();
for( int i =1; i<=5; i++){
list.add(new Product(i, "상품"+i);
}
Stream<Product> stream = list.stream();
stream.forEach(p->System.out.prinln(p));
}
}
public class Xxx implements Comparable {
...
}
List<Xxx> list = new ArrayList<>();
Stream<Xxx> stream = list.stream();
Stream<Xxx> orderedStream = stream.sorted();
//객체가 Comparable을 구현하고 있어야 sorted()메소드를 사용해 정렬할 수 있다.
public interface Calculable{
//추상메소드
void calculate(int x, int y);
}
//익명 구현 객체
new Calculable(){
@Override
public void calculate(int x, int y){처리 내용}
}
//람다식 표현 방법
(x,y) -> {처리 내용}
public static void main(String[] args){
action((x,y)->{
int result = x+y;
System.out.println(result);
}
}
public static void action(Calculable calculable){
int x=10;
int y=4;
calculable.calculate(x,y);
}
* 함수형 인터페이스 : 인터페이스가 단 하나의 추상 메소드를 가질 때. => 이를 보장하기 위해 @FunctionalInterface 어노테이션을 추가한다.
- ArrayList에 add로 객체 추가 시 배열에 객체가 저장되며, 일반 배열과 달리 길이 제한이 없다.
- 객체 자체가 아닌 객체의 번지를 저장한다. 동일한 객체 저장도 가능하며, 동일한 번지가 저장된다.
//생성방법
ArrayList<E> list = new ArrayList<E>(); //지정된 E타입 객체만 저장 가능
ArrayList<E> list = new ArrayList<>(); //지정된 E타입 객체만 저장 가능
ArrayList list = new ArrayList(); //모든 타입 객체 저장 가능
* 특정 index 객체를 제거하면 바로 뒤부터 끝까지 모두 앞으로 한 칸씩 당겨진다.
* 특정 index에 객체를 추가하면 해당 인덱스부터 끝까지 뒤로 한 칸씩 밀려진다.
Vector
ArrayList와 동일한 내부 구조를 가졌지만 Vector는 동기화된 메소드로 구성되어 있어 멀티 스레드가 동시에 Vector() 메소드를 실행할 수 없다.
=> 멀티 스레드 환경에서 안전하게 객체 추가/삭제가 가능하다.
//생성 방법
List<E> list = new Vector<E>(); //E타입 객체만 저장
List<E> list = new Vector<>(); //E타입 객체만 저장
List<> list = new Vector<>(); //모든 타입 객체 저장
=>코드에 여러 스레드가 있어 thread1.start(); thread2.start();해도 한 번에 하나의 스레드만 실행시킨다.
LinkedList
LinkedList는 ArrayList와 사용 방법은 동일하지만 내부 구조는 완전히 다르다. ArrayList는 배열에 객체를 저장하지만, LinkedList는 인접 객체를 체인처럼 연결해서 관리한다.
- 특정 위치에서 객체를 삽입/삭제하면 바로 앞 뒤 링크만 변경되므로 빈번한 삽입/삭제에서는 ArrayList보다 좋다.
//생성 방법
List<E> list = new LinkedList<E>(); //E타입 객체만 저장
List<E> list = new LinkedList<>(); //E타입 객체만 저장
List<> list = new LinkedList<>(); //모든 객체 저장
Set 컬렉션
List와 달리 Set은 저장 순서가 유지되지 않는다. 또한 객체를 중복해서 저장할 수 없고, 하나의 null만 저장할 수 있다.
기능
메소드
설명
객체 추가
boolean add(E e)
주어진 객체를 성공적으로 저장하면 true를 리턴하고 중복 객체면 false를 리턴
객체 검색
boolean contains(Object o)
주어진 객체가 저장되어 있는지 여부
isEmpty()
컬렉션이 비어 있는지 조사
Iterator<E> iterator()
저장된 객체를 한 번씩 가져오는 반복자 리턴
int size()
저장된 객체 수 리턴
객체 삭제
void clear()
저장된 모든 객체를 삭제
boolean remove(Object o)
주어진 객체를 삭제
HashSet
- Set컬렉션 중 가장 많이 사용되는 것
//생성 방법
Set<E> set = new HashSet<E>(); //E타입 객체만 저장
Set<E> set = new HashSet<>(); //E타입 객체만 저장
Set<> set = new HashSet<>(); //모든 타입 객체 저장
=>HashSet은 hashCode()의 리턴값이 같고 equals()메소드가 true를 리턴하면 동등한 객체로 보고 중복 저장하지 않는다.
* Set은 index가 없어 객체를 검색해서 가져오는 방법이 없다. 그래서 2가지 방법을 이용한다.
//Set에서 객체를 가져오는 방법
//1.for문 이용
Set<E> set = new HashSet<>();
for (E e:set){
...
}
//2.Iterator이용
Set<E> set = new HashSet<>();
Iterator<E> iterator = set.iterator();
리턴타입
iterator 메소드명
설명
boolean
hasNext()
가져올 객체가 있으면 true, 없으면 false
E
next()
컬렉션에서 하나의 객체를 반환
void
remove()
next()로 가져온 객체를 Set컬렉션에서 제거한다.
//사용 방법
while(iterator.hasNext()){
E e = iterator.next();
}
Map 컬렉션
Map 컬렉션은 키(key)와 값(value)으로 구성된 엔트리 객체를 저장한다. 여기서 키와 값은 모두 객체이다.
키 - 중복저장 불가능
값 - 중복저장 가능
기능
메소드
설명
객체 추가
V put(K key, V value)
주어진 키와 값을 추가, 저장되면 값을 리턴
객체 검색
boolean containsKey(Object key)
주어진 키가 있는지 여부
boolean containsValue(Object Value)
주어진 값이 있는지 여부
Set<Map.Entry<K,V>> entrySet()
키,값 쌍으로 구성된 모든 Map.Entry 객체를 Set에 담아서 리턴
V get(Object key)
주어진 키의 값을 리턴
boolean isEmpty()
컬렉션이 비어있는지 여부
Set<K> keySet()
모든 키를 Set객체에 담아 리턴
int size()
저장된 키의 총 수를 리턴
Collection<V> values()
저장된 모든 값 Collection에 담아서 리턴
객체 삭제
void clear()
모든 Map.Entry(키와 값)을 삭제
V remove(Object key)
주어진 키와 일치하는 Map.Entry 삭제. 삭제되면 값을 리턴
HashMap
키로 사용할 객체가 hashCode() 메소드의 리턴값이 같고 equals() 메소드가 true를 리턴할 경우, 동일 키로 보고 중복 저장을 허용하지 않는다.
//생성 방법
Map<K,V> map = new HashMap<K,V>();
Map<K,V> map = new HashMap<>();
Hashtable
Hashtable은 HashMap과 동일한 내부 구조를 갖고 있다. 차이점으로는 Hashtable은 동기화된 메소드로 구성되어 있어 멀티 스레드가 동시에 Hashtable의 메소드들을 실행할 수 없다.
따라서 멀티 스레드 환경에서도 안전하게 객체를 추가, 삭제할 수 있다.
Map<String, Integer> map = new Hashtable<String, Integer>();
Map<String, Integer> map = new Hahtable<>();
Properties
Hashtable의 자식 클래스이기 때문에 Hahtable의 특징을 그대로 갖고 있다. Properties는 키와 값을 String으로 제한한 컬렉션이다.
스레드는 다른 스레드와 독립적으로 실행하지만 다른 스레드가 종료될 때까지 기다렸다가 실행해야 하는 경우에 join()메소드를 사용한다.
//<Thread A>
threadB.start(); //threadB 시작
threadB.join(); //threadA 일시 정지. =>B가 끝날 때까지 A는 실행하지 않음.
//<Thread B>
run(){
}
스레드 동기화
멀티 스레드는 하나의 객체를 공유해서 사용할 수도 있다. 한 객체를 여러 스레드가 접근해서 데이터를 변경하거나 가져올 때 원하지 않는 결과가 발생할 수도 있다.
메소드에 synchrosized키워드를 추가해 한 스레드가 끝날 때까지 flag를 가져가지 못하도록 할 수 있다.
스레드 안전 종료
스레드는 자신의 run()메소드가 모두 실행되면 자동적으로 종료되지만, 안전하게 사용하던 리소스들을 정리하고 run()메소드를 빨리 종료하는 방법은 조건 이용 방법과 interrupt()메소드 이용 방법이 있다.
조건 이용
public class XXXThread extends Thread{
private boolean stop;
public void run(){
while(!stop){
//스레드가 반복 실행하는 코드;
}
//스레드가 사용한 리소스 정리
}
}
interrupt()메소드 이용
interrupt() 메소드는 스레드가 일시 정지 상태에 있을 때 InterruptedException 예외를 발생시켜 run()메소드를 정상 종료시킬 수 있다.
XThread thead = new XThread();
thread.start; //---1
...
thread.interrupt(); //---2
public void run(){ //---1로 인해 진행
try{
while(true){
...
Thread.sleep(1); //---2로 인해 일시정지
}
}catch(InterruptedException e){ //---일시정지로 인해 예외 발생
}
//스레드가 사용한 리소스 정리
}
데몬 스레드
데몬 스레드는 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드이다. 주 스레드가 종료되면 데몬 스레드도 따라서 자동 종료된다.
스레드를 데몬으로 만들기 위해 주 스레드가 데몬이 될 스레드의 setDaemon(true)를 호출한다.
public static void main(String[] args){
AutoSaveThread thread = new AutoSaveThread();
thread.setDaemon(true);
thread.start();
}
=>AutoSaveThread는 데몬 스레드가 된다.
스레드풀
병렬 작업 처리가 많아지면 스레드 개수가 폭증하여 CPU가 바빠지고 메모리 사용량이 늘어난다. 따라서 어플리케이션 성능이 저하되기 때문에 스레드 폭증을 막기 위한 스레드풀을 사용하는 것이 좋다.
스레드의 개수를 제한하여 큐에 들어오는 작업들을 스레드가 하나씩 맡아 처리하는 방식이다.
스레드풀 생성
메도드명(매개변수)
초기 수
코어 수
최대 수
newCachedThreadPool()
0
0
Integer.MAX_VALUE
newFixedThreadPool(int nThreads)
0
생성된 수
nThreads
ExecutorService executorService = Executors.newCachedThreadPool();
// 초기 수와 코어 수는 0개이고, 작업수가 많아지면 새 스레드를 생성시켜 작업을 처리한다.
ExecutorService executorService = Executors.newFixedThreadPool(5);
// 초기 수는 0개이고, 작업 수가 많아지면 최대 5개까지 스레드를 생성시켜 작업을 처리한다.
ExecutorService threadPool = new ThreadPoolExecutor(
3, //코어 스레드 개수
100, //최대 스레드 개수
120L, //놀고 있는 시간
TimeUnit.SECONDS, //놀고 있는 시간의 단위
new SynchronousQueue<Runnable>() //작업 큐
);
스레드풀 종료
스레드풀의 스레드는 데몬 스렏가 아니기 때문에 main스레드가 종료되더라도 계속 실행 상태로 남아있다. 두 가지 중 하나의 메소드를 실행해야한다.
리턴 타입
메소드명(매개변수)
설명
void
shutdown()
현재 처리 중인 작업뿐만 아니라 작업 큐에 대기하고 있는 모든 작업을 처리한 뒤에 스레드풀을 종료시킨다.
List<Runnable>
shutdownNow()
현재 작업 처리 중인 스레드를 interrupt해서 작업을 중지시키고 스레드풀을 종료시킨다. 리턴값은 작업 큐에 있는 미처리된 작업(Runnable)의 목록이다.
public class DateExample {
public static void main(String[] args) {
Date now= new Date();
String strNow1= now.toString();
System.out.println(strNow1);//Fri Apr 21 11:00:43 KST 2023
SimpleDateFormat sdf=new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
String strNow2=sdf.format(now);
System.out.println(strNow2);//2023.04.21 11:00:43
Date date = new Date();
System.out.println(date);
System.out.println(date.getTime());//1682042443861밀리초
java.sql.Date date2 = new java.sql.Date(date.getTime());
System.out.println(date2); //2023-04-21
System.out.println(System.currentTimeMillis()); //밀리초
System.out.println(new java.sql.Date(System.currentTimeMillis())); //2023-04-21
}
}
Calendar 클래스
Calendar now = Calendar.getInstance();
int year = now.get(Calendar.YEAR);
int month = now.get(Calendar.MONTH) + 1; //월은 0부터 시작
int day = now.get(Calendar.DAY_OF_MONTH);
int week = now.get(Calendar.DAY_OF_WEEK);
int amPm = now.get(Calendar.AM_PM);
int hour = now.get(Calendar.HOUR);
int minute = now.get(Calendar.MINUTE);
int second = now.get(Calendar.SECOND);
TimeZone 클래스를 이용해 알고 싶은 다른 시간대의 Calendar을 얻을 수 있다.
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
Calendar now = Calendar.getInstance(timeZone);
날짜와 시간 조작
LocalDateTime now = LocalDateTime.now();
public class DateTimeOperationExample {
public static void main(String[] args) {
LocalDateTime now= LocalDateTime.now();
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy.MM.dd. a HH:mm:ss");
System.out.println("현재 시간: "+now.format(dtf));
LocalDateTime result1=now.plusYears(1);
System.out.println("1년 덧셈: "+result1.format(dtf));
LocalDateTime result2 = now.minusMonths(2);
System.out.println("2달 뺄셈: "+result2.format(dtf));
LocalDateTime result3 = now.plusDays(7);
System.out.println("7일 덧셈: "+result3.format(dtf));
}
}
/*
결과
현재 시간: 2023.04.21. 오전 11:10:22
1년 덧셈: 2024.04.21. 오전 11:10:22
2달 뺄셈: 2023.02.21. 오전 11:10:22
7일 덧셈: 2023.04.28. 오전 11:10:22
*/
형식 클래스
Format 클래스
설명
DecimalFormat
숫자를 형식화된 문자열로 변환
SimpleDateFormat
날짜를 형식화된 문자열로 변환
정규 표현식 클래스
//이메일 형식
String str="\\w+@\\w+\\.\\W+(\\.\\W+)?";
//전화번호 형식
String phone="(02|010)-\\d{3,4}-\\d{4}";
어노테이션
어노테이션
- 코드에서 @으로 작성되는 요소
- 클래스 또는 인터페이스를 컴파일하거나 실행할 때 어떻게 처리해야 할 것인지를 알려주는 설정 정보
용도
1) 컴파일 시 사용하는 정보 전달
2) 빌드 툴이 코드를 자동으로 생성할 때 사용하는 정보 전달
3) 실행 시 특정 기능을 처리할 때 사용하는 정보 전달
어노테이션 타입 정의와 적용
- @interface 뒤에 사용할 어노테이션 이름 작성
public @interface AnnotationName{
}
@AnnotationName
어노테이션 적용 대상(어디에)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface AnnotationName{
}
어노테이션 유지 정책(언제)
RententionPolicy 열거 상수
어노테이션 적용 시점
어노테이션 제거 시점
SOURCE
컴파일 할 때 적용
컴파일된 후에 제거됨
CLASS
메모리로 로딩할 때 적용
메모리로 로딩된 후에 제거됨
RUNTIME
실행할 때 적용
계속 유지됨
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationName{
}