반응형
반응형
package runnable_jar;

public class PrintThread extends Thread {
	@Override
	public void run() {
		while (true) {
		}
	}
}
package runnable_jar;

import java.util.Map;
import java.util.Set;

public class InterruptExample {

	public static void main(String[] args) {

		PrintThread printThread = new PrintThread();
		printThread.setName("Print Thread");
		printThread.setDaemon(true);
		printThread.start();
		
		Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
		Set<Thread> threads = map.keySet();
		for(Thread thread : threads) {
			System.out.println("Name : " + thread.getName() + ((thread.isDaemon() ? " 데몬" : "주")));
			System.out.println("\t" + "소속그룹 : " + thread.getThreadGroup().getName());
			System.out.println();
		}
	}
	/** 기본 스레드 그룹 **/
	// system : JVM 운영에 필요한 스레드를 포함
	// main : 메인 스레드를 포함 (Print Thread는 Main Thread의 데몬 스레드이기 때문에 main 소속)
	
//	Name : Notification Thread 데몬
//	소속그룹 : system
//
//	Name : main주
//		소속그룹 : main
//	
//	Name : Signal Dispatcher 데몬
//		소속그룹 : system
//	
//	Name : Common-Cleaner 데몬
//		소속그룹 : InnocuousThreadGroup
//	
//	Name : Finalizer 데몬
//		소속그룹 : system
//	
//	Name : Print Thread 데몬
//		소속그룹 : main
//	
//	Name : Reference Handler 데몬
//		소속그룹 : system
//	
//	Name : Attach Listener 데몬
//		소속그룹 : system


}

 

 

 

 

package runnable_jar;

public class PrintThread extends Thread {

	// 스레드 그룹 정해주는 생성자
	public PrintThread(ThreadGroup threadGroup, String threadName) {
		super(threadGroup, threadName);
	}
	
	@Override
	public void run() {
		while (true) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				System.out.println(getName() + " interrupted");
				break;
			}
		}
		System.out.println(getName() + "종료됨");
	}
	

}
package runnable_jar;

public class ThreadGroupExample {

	public static void main(String[] args) {

		ThreadGroup myGroup = new ThreadGroup("myGroup"); // main - myGroup (계층도)
		PrintThread printThreadA = new PrintThread(myGroup, "printThreadA"); // main - myGroup - printThreadA
		PrintThread printThreadB = new PrintThread(myGroup, "printThreadB"); // main - myGroup - printThreadB
		
		printThreadA.start();
		printThreadB.start();
		
		System.out.println("[main 스레드 그룹 list() 메소드 출력 내용]");
		ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
		mainGroup.list();
		System.out.println();
		

		
//		[main 스레드 그룹 list() 메소드 출력 내용]
//				java.lang.ThreadGroup[name=main,maxpri=10]
//				    Thread[main,5,main]
//				    java.lang.ThreadGroup[name=myGroup,maxpri=10]
//				        Thread[printThreadA,5,myGroup]
//				        Thread[printThreadB,5,myGroup]

		myGroup.interrupt(); // 상위 스레드 그룹에서 interrupt 발생시 하위 스레드도 전부 interupt 발생
		
//		printThreadA interrupted
//		printThreadA종료됨
//		printThreadB interrupted
//		printThreadB종료됨
	}

}
반응형
반응형

1. Runnable
Runnable은 이름부터 인터페이스의 느낌이 강하다.
implements Runnable 을 통해서 Runnable 인터페이스를 구현할 수 있다.

Runnable 인터페이스를 구현하게되면 재사용성이 높고, 코드의 일관성을 유지할 수 있어서 Thread보다 더 효율적인 방법이라 할 수 있다.

2. Thread
상속을 받아 사용해야 하기 때문에 다른 클래스를 상속받아 사용할 수 없다는 단점이 있다.
따라서 일반적으로는 Runnable 인터페이스를 구현해서 스레드를 사용한다.

반응형
반응형
function uuidv4() {
  return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  );
}
반응형
반응형
//이미지 미리보기 
function imagePreview() {
	 var filedata = document.getElementById("license_org_file");
	 var file;
	 var formdata = new FormData();
	 
	 file = filedata.files[0];
	 
	 var img = URL.createObjectURL(file); 
     // blob:http://localhost:8080/b9a326dd-8438-4e17-a0de-99c7e0158bbd
	 
     /** 파일 정보를 읽어 사진이 로컬에 있는 것처럼 보이게 한다. **/
     $("#imageView").attr("src", img); 
      
     return true;
     	 
}
<input style="display: inline-block; width:230px;" id=license_org_file class="form-control" type="file" placeholder="">
<img id=imageView  style="max-width: 100%; height: 50%;">
반응형
반응형

- 제네릭

/** Generic 사용 안 할 시 **/
//public class Box {
//	
//	private Object t;
//	public Object get() {return t;}
//	public void set(Object t) {this.t = t;}
//	
//}

/** Generic 사용 할 시 **/
public class Box<T> {
	
	private T t;
	public T get() {return t;}
	public void set(T t) {this.t = t;}
	
}

// 1. 실행시 타입 에러가 나는 것보다는 컴파일시에 미리 타입을 강하게 체크해 에러를 사전에 방지할 수 있다.
// 2. 타입 변환을 제거할 수 있다.
// → 이와 같은 방법으로 컬렉션프레임워크가 탄생하게 되었다.

Box.java

public class GenericBox {

	public static void main(String[] args) {

		/** Generic 사용 안 할 시 **/
//		Box box = new Box();
//		box.set("Apple");
//		String boxContent = (String) box.get();
//		
//		Box boxInteger = new Box();
//		boxInteger.set(10);
//		int boxContentInteger = (int) boxInteger.get();
		
		
		
		/** Generic 사용 할 시 **/
		Box<String> box = new Box();
		box.set("Apple");
		String boxContent = box.get();

		Box<Integer> boxInteger = new Box();
		boxInteger.set(10);
		int boxContentInteger = boxInteger.get();
		
		
	}

}

GenericBox.java

 

- 제네릭<멀티타입>

public class Product<T, M> {

	private T kind;
	private M model;
	
	public void setModel(M model) {
		this.model = model;
	}

	public void setKind(T kind) {
		this.kind = kind;
	}
	
	public T getKind() {
		return kind;
	}
	
	public M getModel() {
		return model;
	}
	
}

// Product<Tv, String> product = new Product<>(); 이와 같이 사용

Product.java 이렇게 멀티타입도 가능하다.

 

 

- 제네릭 메소드, 제네릭 <멀티타입> 메소드

public class Util {
	// 기본 구조 : <T> 리턴타입 메소드명
	// return type : box<T> 제너릭으로 선언된 Box Class
	// 동작 : box 객체 선언 후 T 타입의 값을 box에 넣는다.
	public <T> Box<T> boxing(T t){ 
		
		Box<T> box = new Box<T>();
		box.set(t);
		return box;
	}
	
	// 멀티타입 제너릭 메소드 (두 객체의 키와 값을 비교하기)
	public <Key,Value> boolean compare(Pair<Key,Value> p1, Pair<Key,Value> p2) {
		
		boolean isSameKey = p1.getKey().equals(p2.getKey());
		boolean isSameValue = p1.getValue().equals(p2.getValue());
		
		boolean isSame = (isSameKey && isSameValue) ? true : false; 
		System.out.println("isSame ? : " + isSame);
		
		return isSame;
	}
	
}

Util.java

/** Generic 사용 할 시 **/
public class Box<T> {
	
	private T t;
	public T get() {return t;}
	public void set(T t) {this.t = t;}
	
}

Box.java

 

import java.util.HashMap;

public class GenericMethod {

	public static void main(String[] args) {

		/**  제너릭 메소드  **/
		Util util = new Util();
		Box<Integer> box = util.<Integer>boxing(100);
		int intValue = box.get();
		System.out.println(intValue);
		
		Box<String> box1 = util.<String>boxing("홍길동");
		String intValue1 = box1.get();
		System.out.println(intValue1);
		
		
		/**  멀티타입 제너릭 메소드  **/
		// 어디서 많이 본듯한 형태 → 컬렉션프레임워크 hashMap
		Pair<Integer,Integer> pair = new Pair<>(100,200);  
		Pair<Integer,Integer> pair1 = new Pair<>(100,200); 
		
		System.out.println(util.compare(pair, pair1));
		
		HashMap<String, String> at = new HashMap<>();
	}

}

GenericMethod.java

 

 

 

- 제네릭 상속

public class Util {
	// Number로 구현된 클래스만 사용 가능 int, double 등...
	// Number에서 상속받은 메소드 사용 가능 
	// return type : int
	public static <T extends Number> int compare(T t1, T t2) {

		
		double v1 = t1.doubleValue();
		double v2 = t2.doubleValue();
		
		return (int) (v1 + v2);
	}
	
}

Util.java

 

 

 

 

- 와일드카드

public class WileCard {

	public static void registerCourse(Course<?> course) {

	}

	public static void registerCourseStudent(Course<? extends Student> course) {

	}

	public static void registerCourseWorker(Course<? super Student> course) {
		
	}
	public static void main(String[] args) {

		/** 모든 클래스 사용 가능 **/
		registerCourse(new Course<Person>("일반인 과정", 5));
		registerCourse(new Course<Student>("학생", 5));
		registerCourse(new Course<Worker>("근로자", 5));
		registerCourse(new Course<HighStudent>("고등학생 과정", 5));

		/** 하위 클래스만 사용 가능 **/
		registerCourseStudent(new Course<Person>("일반인 과정", 5)); // Student 클래스 상속 안 받은 Person 클래스 이기 때문에 사용 불가
		registerCourseStudent(new Course<Student>("학생", 5));
		registerCourseStudent(new Course<Worker>("근로자", 5)); // Student 클래스 상속 안 받은 Worker 클래스 이기 때문에 사용 불가
		registerCourseStudent(new Course<HighStudent>("고등학생 과정", 5));

		/** 상위 클래스만 사용 가능 **/
		registerCourseWorker(new Course<Person>("일반인 과정", 5));
		registerCourseWorker(new Course<Student>("학생", 5));
		registerCourseWorker(new Course<Worker>("근로자", 5)); // Student의 상위 클래스가 아니라 사용 불가
		registerCourseWorker(new Course<HighStudent>("고등학생 과정", 5)); // Student의 상위 클래스가 아니라 사용 불가
	}

}

WildCard.java

 

public class Course<T> {
	
	private String name;
	private T[] students;
	public Course(String name, int capacity) {
		
		this.name = name;
		students = (T[]) (new Object[capacity]); 
		// T가 정해지지 않았는데 바로 사용 불가능 최상위 클래스 Object로 구현 한 다음 타입 변환 필요
	}
	
	public String getName() {
		return name;
	}
	
	public T[] getStudents() {
		return students;
	}
	
	
}


Course.java

 

public class Person {

	private String name;

	public Person(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

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

}

Person.java

public class Worker extends Person{
	public Worker(String name) {
		super(name);
	}
}

Worker.java

public class Student extends Person{
	public Student(String name) {
		super(name);
	}
}

Student.java

public class HighStudent extends Student{
	public HighStudent(String name) {
		super(name);
	}
}

HightStudent.java

 

 

-  제네릭 상속

public class Product<T,M> {

	private T kind;
	private M model;
	
	public T getKind() {
		return kind;
	}
	public void setKind(T kind) {
		this.kind = kind;
	}
	public M getModel() {
		return model;
	}
	public void setModel(M model) {
		this.model = model;
	}	
}

Product.java

 

// 자식 클래스는 무조건 부모 클래스의 제너릭 타입 이상을 가져야한다. (K, V 반드시 포함)
public class ChildProduct<K,V,C> extends Product<K, V> {

	
}

ChildProduct.java

 

public class ExtendsGeneric {

public static void main(String[] args) {

		ChildProduct<String, String, Integer> childProduct = new ChildProduct<>();
		
	}

}

ExtendsGeneric.java

반응형
반응형
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <script src="valina.js"></script>
    <!-- js 파일 용량이 크거나 용량이 큰 경우 화면이 나오는 데 까지 속도가 느리다.-->
    <!-- parsing HTML →  block(fetching js | executing js) → parsing HTML  -->

    <script async src="valina.js"></script>
    <!-- 비동기 처리로 js 다운 받는데 시간 절약을 할 수 있지만 아직 파싱중인데 중간에 멈춰버리거나
         해당 DOM 요소가 만들어지지 않았는데 그걸 가지고 조작하는 함수가 있는 경우 치명적이다. -->
    <!-- parsing HTML →→→→→→→→→ block (executing js)  → parsing HTML  -->
    <!--       |  fecthing js  |  -->

    <script defer src="valina.js"></script>
    <!-- 비동기 처리로 js 다운 받고 HTML 다 그려진 후에 js를 실행 시키기 때문에 비동기적으로 다운 시간 절약과
         async의 문제도 해결할 수 있다. (가장 추천) -->
    <!-- parsing HTML →→→→→→→→→→→→→→→→  block (executing js) -->
    <!--         |      fecthing js     |     -->

    
</head>
<body>
  
    
<script src="valina.js"></script>

<!-- 화면을 빨리 볼 수 있는 장점은 있지만 js로 구현한 이벤트 핸들러는 다운 받을 때까지 사용 불가 -->
<!-- parsing HTML →  NonBlock(fetching js | executing js) -->
</body>
</html>

출처 : 드림코딩

 

반응형
반응형

 

function setDatePicker(){
	
	$("input.start_date").datepicker({
		 dateFormat: 'yy-mm-dd' //달력 날짜 형태
		,showOtherMonths: true //빈 공간에 현재월의 앞뒤월의 날짜를 표시
		,showMonthAfterYear:true // 월- 년 순서가아닌 년도 - 월 순서
		,changeYear: true //option값 년 선택 가능
		,changeMonth: true //option값  월 선택 가능                
		,showOn: "both" //button:버튼을 표시하고,버튼을 눌러야만 달력 표시 ^ both:버튼을 표시하고,버튼을 누르거나 input을 클릭하면 달력 표시  
		,buttonImage: "http://jqueryui.com/resources/demos/datepicker/images/calendar.gif" //버튼 이미지 경로
		,buttonImageOnly: true //버튼 이미지만 깔끔하게 보이게함
		,buttonText: "선택" //버튼 호버 텍스트              
		,yearSuffix: "년" //달력의 년도 부분 뒤 텍스트
		,monthNamesShort: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'] //달력의 월 부분 텍스트
		,monthNames: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'] //달력의 월 부분 Tooltip
		,dayNamesMin: ['일','월','화','수','목','금','토'] //달력의 요일 텍스트
		,dayNames: ['일요일','월요일','화요일','수요일','목요일','금요일','토요일'] //달력의 요일 Tooltip
		,minDate: "-5Y" //최소 선택일자(-1D:하루전, -1M:한달전, -1Y:일년전)
		,maxDate: "+5y" //최대 선택일자(+1D:하루후, -1M:한달후, -1Y:일년후)  


	});
	$("input.end_date").datepicker({
		 dateFormat: 'yy-mm-dd' //달력 날짜 형태
		,showOtherMonths: true //빈 공간에 현재월의 앞뒤월의 날짜를 표시
		,showMonthAfterYear:true // 월- 년 순서가아닌 년도 - 월 순서
		,changeYear: true //option값 년 선택 가능
		,changeMonth: true //option값  월 선택 가능                
		,showOn: "both" //button:버튼을 표시하고,버튼을 눌러야만 달력 표시 ^ both:버튼을 표시하고,버튼을 누르거나 input을 클릭하면 달력 표시  
		,buttonImage: "http://jqueryui.com/resources/demos/datepicker/images/calendar.gif" //버튼 이미지 경로
		,buttonImageOnly: true //버튼 이미지만 깔끔하게 보이게함
		,buttonText: "선택" //버튼 호버 텍스트              
		,yearSuffix: "년" //달력의 년도 부분 뒤 텍스트
		,monthNamesShort: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'] //달력의 월 부분 텍스트
		,monthNames: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'] //달력의 월 부분 Tooltip
		,dayNamesMin: ['일','월','화','수','목','금','토'] //달력의 요일 텍스트
		,dayNames: ['일요일','월요일','화요일','수요일','목요일','금요일','토요일'] //달력의 요일 Tooltip
		,minDate: "-5Y" //최소 선택일자(-1D:하루전, -1M:한달전, -1Y:일년전)
		,maxDate: "+5y" //최대 선택일자(+1D:하루후, -1M:한달후, -1Y:일년후)  

	});

	$('.start_date').datepicker("option", "maxDate", new Date());
	$('.end_date').datepicker("option", "minDate", $(".start_date").val());
	$('.end_date').datepicker("option", "maxDate", new Date());

	$("#end_date").on("change", function() { // sel02 정렬순서
		$('.start_date').datepicker("option", "maxDate", $(".end_date").val());
		$('.end_date').datepicker("option", "minDate", $(".start_date").val());
		$('.end_date').datepicker("option", "maxDate", new Date());
	});

	$("#start_date").on("change", function() { // sel02 정렬순서
		$('.start_date').datepicker("option", "maxDate", $(".end_date").val());
		$('.end_date').datepicker("option", "minDate", $(".start_date").val());
		$('.end_date').datepicker("option", "maxDate", new Date());
	});

	// $('#start_date').datepicker('setDate', 'today'); //(-1D:하루전, -1M:한달전, -1Y:일년전), (+1D:하루후, -1M:한달후, -1Y:일년후)
	// $('#end_date').datepicker('setDate', 'today'); //(-1D:하루전, -1M:한달전, -1Y:일년전), (+1D:하루후, -1M:한달후, -1Y:일년후)       
	
}

$(document).ready(function() {
	setDatePicker();
})

date.js

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

    <script type="text/javascript" src="./date.js"></script>

</head>
<body>
    <div class="start">
        <div class="date_picker">
            <input class="start_date" type="text" id="start_date"
                name="start_date" />
        </div>
    </div>
    <div class="end">
        <div class="date_picker">
            <input class="end_date" type="text" id="end_date" name="end_date" />
        </div>
    </div>
</body>
</html>

datepicker.html

반응형
반응형

 

- 입력스트림

데이터가 들어올 때 (입력)

- 출력스트림

데이터가 나갈 때 (출력)

 

스트림은 2가지로 나뉘게 된다.

1. 바이트 기반 스트립 : 그림 멀티미디어 문자 등 모든 종류의 데이터를 받고 보낼 수 있다.

2. 문자 기반 스트림 : 문자만 받고 보낼 수 있게 특화되어 있다.

 

- 바이트 기반 스트림

InputStream (최상위 입력 스트림 클래스)

XXX InputStream (하위 클래스 스트림) ex) FileInputStream

OutputStream (최상위 출력 스트림 클래스)

XXX OuputStream (하위 클래스 스트림) ex) FileOutputStream

 

- 문자 기반 스트림

Reader (최상위 입력 스트림 클래스)

XXXReader (하위 입력 스트림) ex) FileReader

Writer (최상위 출력 스트림)

XXXWriter (하위 출력 스트림) ex) FileWriter

 

파일에 글을 읽고 싶을 때 (파일이 입력될 때) → 입력 스트림

파일을 저장하고 싶을 때 (파일이 저장되어서 출력 될 때) → 출력 스트림

 

- InputStream

리턴 메소드 설명
int  read()  1바이트씩 읽고 읽은 바이트(UTF-8)를 리턴한다.
int read(byte[] b) 읽은 바이트들을 b(바이트 배열[UTF-8 값들)에 저장하고 실제 읽은 바이트 수를 리턴한다.
int read(byte[] b, int off, int len) off의 인덱스 번호부터 len의 크기만큼 읽어 b(바이트배열에 저장후에 출력한다.
void  close()  사용 후에 스트림을 가비지 컬렉터가 수집할 수 있게 닫아야 한다.

 

 

 

 

- OutputStream

리턴 메소드 설명
void write(int b) 1 바이트를 저장 또는 화면 따위에 보낸다
void write(byte[] b) 바이트 배열 전체를 저장 또는 화면 따위에 보낸다.
void write(byte[] b, int off, int len)  off의 인덱스 번호부터 len의 크기만큼 b(바이트배열)을 보낸다
void flush() 버퍼에 잔류하는 모든 바이트를 출력한다. (이 행위를 하지 않으면 바이트는 할당량[메모리버퍼]만큼 찰 때까지 출력하지 않는다.)
void close() 사용 후에 스트림을 가비지 컬렉터가 수집할 수 있게 닫아야 한다.

 

 

- Reader

리턴 메소드 설명
int reade() 한 개의 문자를 읽고 리턴한다.
int read(char[] cbuf) 읽은 문자들을 배열에 저장하고 읽은 문자 수를 리턴한다.
int read(char[] cbuf, int off, int len) off의 인덱스 번호부터 len의 크기만큼 문자를 리턴한다
void close() 사용 후에 스트림을 가비지 컬렉터가 수집할 수 있게 닫아야한다.

 

 

 

- Writer

리턴 메소드 설명
void write(int c) 한 문자를 파일이나 화면 따위에 보낸다
void write(char[] cubf) 읽은 문자의 배열을 파일이나 화면 따위에 보낸다
void write(char[] cbuf, int off, int len) off의 인덱스 번호부터 len의 크기만큼 문자의 배열을 파일이나 화면 따위에 보낸다.
void write(String str) 문자열을 파일이나 화면 따위에 보낸다
void write(String str, int off, int len) off의 인덱스 번호부터 len의 크기만큼 문자열을 파일이나 화면 따위에 보낸다.
void flush() 버퍼에 잔류하는 모든 바이트를 출력한다. (이 행위를 하지 않으면 바이트는 할당량[메모리버퍼]만큼 찰 때까지 출력하지 않는다.)
void close() 사용 후에 스트림을 가비지 컬렉터가 수집할 수 있게 닫아야한다.

 

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class Stream {

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

		/** -- inputStream -- **/
		// 1. is.read() 1 byte 씩 읽기
//		InputStream is = new FileInputStream("C:/test.txt"); // 'abcd' 내용이 저장 됨
//		int readByte;
//		while((readByte=is.read()) != -1) {
//			System.out.println(readByte); // 97 98 99 100
//		}
//		is.close();

		// 2. is.read(byte[] b) 내가 설정한 byte의 크기 읽기
//		InputStream is = new FileInputStream("C:/test.txt"); // '안녕하세요' 내용이 저장 됨
//		int readByte;
//		byte[] readBytes = new byte[3];
//		while( (readByte = is.read(readBytes)) != -1) {
//			System.out.println(new String(readBytes,0 , readByte)); // 안 녕 하 세 요 (한글은 UTF-8에서 주로 3byte이기 때문에 잘 읽어온다.)
//		}
//		is.close();

		
		/** -- outputStream -- **/
		// 1. os.write() 1 바이트씩 출력
//		OutputStream os = new FileOutputStream("C:test2.txt");
//		byte[] data = "안녕하세요".getBytes(); // '안녕하세요'의 바이트를 가져온다. (UTF-8 코드)
//		for (int i = 0; i < data.length; i ++) {
//			os.write(data[i]); // '안녕하세요'가 test2.txt에 저장된다.
//		}
//		os.flush();
//		os.close();
		
		
		// 2. os.write(byte[] b) → os 1번에서 for문 여러번 사용하는 것보다 효율적
//		OutputStream os = new FileOutputStream("C:test2.txt");
//		byte[] data = "안녕하세요".getBytes(); // '안녕하세요'의 바이트를 가져온다. (UTF-8 코드)
//		
//		os.write(data); // '안녕하세요'가 test2.txt에 저장된다.
//		os.flush();
//		os.close();
		
		
		/** -- reader -- **/
		// 1. reader.read() 한 개의 문자씩 읽기
//		Reader reader = new FileReader("C:/test.txt"); // '안녕하세요' 내용이 저장 됨
//		int readData;
//		while ( (readData = reader.read()) != -1 ) {
//			System.out.println((char) readData); // 안 녕 하 세 요 출력
//		}
//		reader.close();
		
		// 2. reader.read(char[] cbuf) 여러개의 문자열로 읽기
//		Reader reader = new FileReader("C:/test.txt"); // '안녕하세요' 내용이 저장 됨
//		int readData;
//		char[] cbuf = new char[2];
//		while ( (readData = reader.read(cbuf)) != -1 ) {
//			System.out.println(new String(cbuf, 0, readData)); // 안녕 하세 요 출력
//		}
//		reader.close();

		
		/** -- writer -- **/
		// 1. writer.write() 한 개의 문자씩 출력
//		Writer writer = new FileWriter("C:/test3.txt");
//		char[] data = "홍길동".toCharArray();
//		for(int i = 0; i < data.length; i++) {
//			writer.write(data[i]);
//		}
//		writer.flush();
//		writer.close();
		
		
		// 2. writer.write(char[] cbuf) 여러개의 문자열 출력
//		Writer writer = new FileWriter("C:/test3.txt");
//		char[] data = "홍길동".toCharArray();
//		writer.write(data);
//		writer.flush();
//		writer.close();
		
		// 3. writer(String)
		Writer writer = new FileWriter("C:/test3.txt");
		String data = "스프레이";
		writer.write(data);
		writer.flush();
		writer.close();

		
	}

}

 

 

출처 : https://www.youtube.com/watch?v=ISO3iy4aOh8&t=503s

반응형
반응형

📝검색엔진

DB에 일반 검색에 문제점들을 해결하기 위해 만들어졌으며 현재에는 검색뿐만 아니라 다양하게 이용되고 있습니다 대표적인 특징들은 아래와 같습니다

 

💗장점

  • 전문 검색
    • 데이터베이스로 처리하기 어려운 대량의 비정형 데이터 검색이 가능하다
    • 예를 들면 "다이슨선풍기" 라는 키워드로는 "다이슨 DP-03 퓨어쿨 선풍기" 를 조회할 수 없습니다 하지만 "다이슨 / DP-03 / 퓨어 / 쿨 / 선풍기" 라고 검색엔진이 형태소 분해를 했을 때는 조회가 가능합니다
  • 동의어 검색
    • 예를 들면 검정 구두라고 했을 때 블랙 구두도 나오게 하고 싶을 때 사용하기 좋습니다.
  • 복잡한 정렬 가능
    • 일반적으로 관련성이 높은 레코드를 상위에 노출하는게 중요합니다
    • 색인된 데이터들로 적합도 점수를 매겨서 빠르게 정렬 및 다양한 정렬을 할 수 있게 해줍니다

 

엘라스틱에서는 BM25라는 알고리즘을 사용합니다.

TF문서내 검색 키워드의 단어 빈도수가 높을 경우 점수가 높아진다

("치킨" 이라는 키워드가 본문에 50개가 나왔다 등)

 

DF는 단어 빈도수가 많을 수록

IDF의 경우 전체 문서에서 검색 키워드의 빈도수가 높을수록 검색 점수는 낮아진다.

(필요 없는 단어라는 취급 예를 들면 "조사", "숫자" 등)

 

TF와 IDF의 적절한 조합으로 인해 만들어진게 BM25라는 엘라스틱 자체 적합도 알고리즘

 

⚠️단점

  • 색인 처리를 한 후에 검색을 할 수 있기 때문에 실시간 처리는 불가능하다.
  • 트랜잭션(Transaction) 롤백(Rollback) 등의 기능을 제공하지 않는다
  • 분산 시스템 구성의 특징 때문에, 시스템적으로 비용 소모가 큰 롤백, 트랜잭션을 지원하지 않습니다 그래서 데이터 관리에 유의해야 합니다.


엘라스틱서치에는 물론 업데이트 명령이 있습니다만, 실제로는 데이터를 삭제했다가 다시 만드는 과정으로 업데이트됩니다 이러한 특성은 나중에 불변성(Immutable)이라는 이점을 제공하기도 합니다.

 


📝DB vs 검색엔진

 

DB로도 충분한데 왜 검색엔진을 쓰냐라고 하시는데 검색엔진은 검색에 특화되어있는 솔루션으로 검색에서 위에 설명한 거 같은 장점이있습니다.

 

📝동작 방식 (역인덱싱)

검색엔진은 색인이라는 역인덱싱과정을 채택하는데 색인과정을 거칠시 형태소가 분해되어 각 형태소가 몇번째에 레코드와 관련있는지에 대해서 표시를 해줍니다. 그래서 짜장면을 검색할시 형태소에서 찾아 얘는 관련되어 있는 레코드는 1번이네? 이러면서 찾아갑니다

 

물론 미리 색인작업을 거쳐야하기 때문에(빨리 찾아갈 수 있게끔) 실시간이 상황에 따라 어렵다는 단점이 있습니다.

 


📝Solar vs Elastic

 

오픈소스 검색엔진이 두개가 있습니다. (Solar와 Ealstic Search)

어떤 글에서는 Solar보다 Elastic이 더 빠르다 아니다 이런 글들이 많은데 솔직히 핵심기능 측면에서는 큰 차이는 없어보입니다.

 

  • Solar
    • 자유도가 높습니다 개발자 중심의 API를 가지고 있습니다.
    • 대시보드를 제공하지 않지만, 외부 시각화 도구와 연동할 수 있습니다.
    • Solr은 일괄 처리 방식을 사용하여 변경 사항이 검색 결과에 반영되기까지 시간이 걸릴 수 있습니다 이는 Solr이 변경 사항이 발생할 때마다 색인을 업데이트하는 것이 아니라 변경 사항이 축적된 후 일괄 처리를 수행하기 때문입니다.

 

  • Elastic
    • 자유도는 높지 않지만 다양한 API를 제공하기 때문에 필요한 건 웬만해서 구현이 다 가능합니다
    • 대시보드를 따로 제공해주고 있습니다 (Kibana)
    • Elasticsearch는 변경 사항이 발생할 때마다 실시간으로 검색 색인을 업데이트하므로, 변경 사항이 바로 검색 결과에 반영됩니다 Elasticsearch는 분산 아키텍처와 실시간 검색 성능에 대한 요구 사항이 높은 대규모 애플리케이션에서 사용하기 좋습니다

 

기술적인 장단점에 차이는 없는 것 같고 커뮤니티 활성도등을 따지는게 좋을 거 같습니다 저 같은 경우는 엘라스틱을 선택해 사용중입니다.

반응형