하루에 4개씩 기초 지식!
1. 데이터베이스의 특징?
- 실시간 접근성(Real-Time Accessibility) : 비정형적인 질의(조회)에 대하여 실시간 처리에 의한 응답이 가능해야 하며,
- 지속적인 변화(Continuous Evloution) : 데이터베이스의 상태는 동적입니다. 즉 새로운 데이터의 삽입(Insert), 삭제(Delete), 갱신(Update)으로 항상 최신의 데이터를 유지해야 합니다.
- 동시 공용(Concurrent Sharing) : 데이터베이스는 서로 다른 목적을 가진 여러 응용자들을 위한 것이므로 다수의 사용자가 동시에 같은 내용의 데이터를 이용할 수 있어야 합니다.
- 내용에 의한 참조(Content Reference) : 데이터베이스에 있는 데이터를 참조할 때 데이터 레코드의 주소나 위치에 의해서가 아니라 사용자가 요구하는 데이터 내용으로 찾습니다.
2. 데이터베이스 언어(DDL,MDL,DCL)란 무엇일까
- DDL(정의어 : Data Definition Language) : 데이터베이스 구조를 정의, 수정, 삭제하는 언어( alter, create, drop)
- DML (조작어 : Data Manipulation Language) : 데이터베이스내의 자료 검색, 삽입, 갱신, 삭제를 위한 언어 ( select, insert, update, delete )
- DCL (제어어 : Data Control Language) : 데이터에 대해 무결성 유지, 병행 수행 제어, 보호와 관리를 위한 언어 ( commit, rollback, grant, revoke )
3. SELECT 쿼리의 수행 순서를 알려주세요.
FROM, ON, JOIN > WHERE, GROUP BY, HAVING > SELECT > DISTINCT > ORDER BY > LIMIT
1. FROM
- 각 테이블을 확인한다.
2. ON
- JOIN 조건을 확인한다.
3. JOIN
- JOIN이 실행되어 데이터가 SET으로 모아지게 된다. 서브쿼리도 함께 포함되어 임시 테이블을 만들 수 있게 도와준다.
4. WHERE
- 데이터셋을 형성하게 되면 WHERE의 조건이 개별 행에 적용된다. WHERE절의 제약 조건은 FROM절로 가져온 테이블에 적용될 수 있다.
5. GROUP BY
- WHERE의 조건 적용 후 나머지 행은 GROUP BY절에 지정된 열의 공통 값을 기준으로 그룹화된다. 쿼리에 집계 기능이 있는 경우에만 이 기능을 사용해야 한다.
6. HAVING
- GROUP BY절이 쿼리에 있을 경우 HAVING 절의 제약조건이 그룹화된 행에 적용된다.
7. SELECT
- SELECT에 표현된 식이 마지막으로 적용된다.
8. DISTINCT
- 표현된 행에서 중복된 행은 삭제
9. ORDER BY
- 지정된 데이터를 기준으로 오름차순, 내림차순 지정
10. LIMIT
- LIMIT에서 벗어나는 행들은 제외되어 출력된다.
출처: https://dev-coco.tistory.com/158 [슬기로운 개발생활:티스토리]
4. 트리거(Trigger)에 대해 설명해주세요.
- 트리거는 특정 테이블에 대한 이벤트에 반응해 INSERT, DELETE, UPDATE 같은 DML 문이 수행되었을 때, 데이터베이스에서 자동으로 동작하도록 작성된 프로그램입니다.
- 사용자가 직접 호출하는 것이 아닌, 데이터베이스에서 자동적으로 호출한다는 것이 가장 큰 특징입니다.
Optional..?
Optional이란 뭐지..
- Optional은 값의 존재 여부를 추상홯하여 표현한 객체이다!
- 값이 존재할 수도 있고 존재하지 않을 수도 있는 상황을 명확하게 표현하기 위해 사용된다. 주로 'null' 체크를 깔끔하게 처리하기 위해 사용된다.
Optional의 특징
- Optional은 래퍼 클래스: Optional은 값이 null일 수도 있는 상황을 안전하게 처리하기 위해 만들어진 래퍼 클래스다. 객체의 값이 존재할 수도 있고 존재하지 않을 수도 있는 상황에서 직접 null을 다루지 않고 Optional로 감싸서 처리할 수 있다.
- 함수형 스타일로 값 처리 가능: Optional을 사용하면 함수형 스타일로 값을 처리할 수 있다. 이는 코드의 가독성과 유지보수성을 높여준다.
Optional의 장점
- NullPointerException 방지
- Optional을 사용하면 null 값을 직접 다루지 않아도 되어, NullPointerException을 방지할 수 있다.
- Optional 내부에서 null을 안전하게 처리하므로, 개발자가 null 체크를 잊어버리는 상황을 줄일 수 있다.
- Optional을 사용하면 null 값을 직접 다루지 않아도 되어, NullPointerException을 방지할 수 있다.
- 코드 가독성 향상
- Optional을 사용하면 메서드의 반환값이 명확해져, 다른 개발자들이 코드를 읽을 때 값이 존재할 수도 있고 없을 수도 있다는 것을 쉽게 이해할 수 있다.
- 명시적인 Optional 사용은 코드의 의도를 명확하게 드러내어, 협업 시에도 큰 도움이 된다.
- Optional을 사용하면 메서드의 반환값이 명확해져, 다른 개발자들이 코드를 읽을 때 값이 존재할 수도 있고 없을 수도 있다는 것을 쉽게 이해할 수 있다.
- 함수형 스타일의 유연한 처리
- Optional은 ifPresent, orElse, orElseGet 등의 메서드를 제공해, 값이 존재할 때와 존재하지 않을 때의 처리를 유연하게 할 수 있다.
- 람다식을 활용하여 더욱 간결하고 명확한 코드를 작성할 수 있다
- Optional은 ifPresent, orElse, orElseGet 등의 메서드를 제공해, 값이 존재할 때와 존재하지 않을 때의 처리를 유연하게 할 수 있다.
Optional의 단점
- 성능 오버헤드
- Optional 객체를 생성하고 사용하는 데 추가적인 오버헤드가 발생한다. 특히 성능이 중요한 코드에서는 이를 고려해야 한다.
- 자주 호출되는 메서드나 성능이 중요한 코드에서는 Optional 사용이 오히려 성능 저하를 유발할 수 있다.
- Optional 객체를 생성하고 사용하는 데 추가적인 오버헤드가 발생한다. 특히 성능이 중요한 코드에서는 이를 고려해야 한다.
- 남용의 위험
- 모든 곳에 Optional을 사용하려고 하면 코드가 복잡해질 수 있다. 특히, 단순한 상황에서는 오히려 코드가 장황해지고 읽기 어려워질 수 있다.
- 필드 변수로 Optional을 사용하는 것은 권장되지 않는다. 필드에는 null을 허용하지 않는 구조가 더 적합하다.
- 모든 곳에 Optional을 사용하려고 하면 코드가 복잡해질 수 있다. 특히, 단순한 상황에서는 오히려 코드가 장황해지고 읽기 어려워질 수 있다.
- 호환성 문제
- 레거시 코드와의 호환성 문제가 발생할 수 있다. 기존 코드와 함께 사용하려면, Optional을 사용한 메서드와 그렇지 않은 메서드 사이의 변환 로직이 필요할 수 있다.
Optional의 사용 예시
1. Optional 생성
- 값을 감싸서 'Optional' 객체를 생성할 수 있다
String name = "Hyeonlog";
Optional<String> optionalName = Optional.of(name); // name이 null이면 NPE 발생
Optional<String> optionalNullableName = Optional.ofNullable(name); // name이 null일 수 있음
Optional<String> emptyOptional = Optional.empty(); // 비어 있는 Optional 생성
2. 값이 존재할 때의 처리
- 값이 존재할 때만 특정 동작을 수행할 수 있다.
optionalName.ifPresent(name -> System.out.println("Name is: " + name));
3. 값이 없을 때 기본값 제공
- 값이 없을 때 기본값을 제공하거나, 기본값을 생성할 수 있다
String defaultName = optionalName.orElse("Default Name");
String generatedName = optionalName.orElseGet(() -> "Generated Name");
4. 값이 없을 때 예외 던지기
- 값이 없을 때 예외를 던질 수도 있다.
String nameOrException = optionalName.orElseThrow(() -> new IllegalArgumentException("Name not found"));
근데..orElse는 뭐고,,ifpresent는 뭐지,,,?
Optional의 주요 메서드에 대해서 알아보자
1. 'orElse()'
- 기능 : 'Optional' 객체에 값이 존재하면 그 값을 반환하고, 값이 존재하지 않으면 미리 지정한 기본값을 반환한다.
- 특징 : 기본값을 미리 계산해두기 때문에, 값이 존재하든 존재하지 않든 기본값이 항상 계산된다
- 예시
Optional<String> optionalName = Optional.ofNullable(null);
String name = optionalName.orElse("Default Name");
System.out.println(name); // 출력: "Default Name"
2. 'orElseGet()'
- 기능 : 'Optional' 객체에 값이 존재하면 그 값을 반환하고, 값이 존재하지 않으면 람다식이나 메서드를 통해 기본값을 계산하여 반환한다.
- 특징 : 기본값이 필요할 때만 계산된다. 즉, 값이 존재할 때는 기본값이 계산되지 않으므로 성능 측면에서 이점이 있다.
- 예시
- 사용 시기 : 기본값을 계산하는 데 비용이 크거나, 복잡한 로직이 필요할 때 사용하면 효율적
Optional<String> optionalName = Optional.ofNullable(null);
String name = optionalName.orElseGet(() -> "Generated Name");
System.out.println(name); // 출력: "Generated Name"
3. 'ifPresent()'
- 기능 : 'Optional' 객체에 값이 존재할 때, 지정한 동작(람다식)을 실행한다.
- 특징 : 값이 없을 때는 아무런 동작도 실행되지 않으므로, 값이 있을때만 특정 작업을 수행하고 싶을 때 유용하다.
- 예시
- 값이 존재할 때만 특정 작업을 수행하고, 값이 없을 때는 아무 동작도 필요하지 않은 경우에 유용하다.
Optional<String> optionalName = Optional.of("Winter");
optionalName.ifPresent(name -> System.out.println("Name is: " + name));
// 출력: "Name is: Winter"
Optional은 메서드의 반환값으로 주로 사용되며, 필드 변수로는 적합하지 않다는 점을 다시 한 번 깨달았다. 또한, 코드의 흐름에 따라 orElse, orElseGet, ifPresent를 적절히 사용함으로써, 더 깔끔하고 효율적인 코드를 작성할 수 있었다.
3. Java로 도서관 관리 프로그램을 만들어보자!
- 주요 클래스
- Book 클래스
- 책의 제목, 저자, 데여 가능 여부 등의 정보를 저장하고 관리한다
- 책의 대여 상태를 설정하고, 책의 상세 정보를 출력하는 기능도 제공한다.
- Book 클래스
import java.util.Scanner;
public class Book {
private String title;
private String author;
private boolean isAvailable;
public Book() {
}
public Book(String title, String author, boolean isAvailable) {
this.title = title;
this.author = author;
this.isAvailable = isAvailable;
}
// 책 상세 정보 출력
public String bookInfo() {
String available = isAvailable() ? "대여 가능" : "대여 중";
return "[제목] : " + getTitle() + " [저자] : " + getAuthor() + " [대여 여부] : " + available;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public boolean isAvailable() {
return isAvailable;
}
public void setAvailable(boolean available) {
isAvailable = available;
}
}
- Library 클래스
- Library 클래스는 책을 등록하고 도서관에 추가하는 기능, 도서관에서 책을 찾고 대여/반납하는 기능을 제공
- 책의 목록을 관리하는 bookList와 도서관에 실제로 등록된 책의 목록을 관리하는 libraryList로 구분하여 처리
import java.util.ArrayList;
import java.util.Scanner;
public class Library {
Scanner scanner = new Scanner(System.in);
private ArrayList<Book> bookList = new ArrayList<>();
private ArrayList<Book> libraryList = new ArrayList<>();
public String createBook() {
System.out.print("[등록할 책의 제목을 입력해주세요 : ]");
String title = scanner.nextLine();
System.out.print("[등록할 책의 저자를 입력해주세요 : ]");
String author = scanner.nextLine();
System.out.println("[책을 등록하는 중...]");
for (Book book : bookList) {
if (book.getTitle().equalsIgnoreCase(title)) {
System.out.println("[같은 제목의 책이 이미 등록되어 있습니다. 책 등록을 취소합니다.]");
return "[등록 실패: 중복된 책입니다]";
}
}
Book book = new Book(title, author, true);
bookList.add(book);
System.out.println("책이 성공적으로 등록되었습니다.");
return book.toString();
}
// 도서관에 책 추가
public void addBookLibrary() {
System.out.println("[도서관에 추가할 수 있는 책 목록]");
for (int i = 0; i < bookList.size(); i++) {
System.out.println((i + 1) + ". " + bookList.get(i).getTitle());
}
System.out.println("[어떤 책을 도서관에 추가하시겠습니까?]");
String bookName = scanner.nextLine();
boolean find = false;
boolean alreadyBook = false;
for (Book book : bookList) {
if (book.getTitle().equals(bookName)) {
find = true;
for (Book libraryBook : libraryList) {
if (libraryBook.getTitle().equals(bookName)) {
alreadyBook = true;
break;
}
}
if(!alreadyBook) {
libraryList.add(book);
System.out.println(book.getTitle() + " 제목의 책이 도서관에 추가되었습니다.");
} else {
System.out.println(book.getTitle() + " 제목의 책은 이미 도서관에 등록되어 있습니다.");
}
break;
}
}
if (!find) {
System.out.println(bookName + " 제목의 책을 찾을 수 없습니다");
}
}
// 책 이름으로 찾기
public void findbyName() {
System.out.println("[찾으실 책 제목을 입력해주세요.]");
String bookName = scanner.nextLine();
if (!libraryList.isEmpty()) {
for (Book book : bookList) {
if (book.getTitle().equals(bookName)) {
System.out.println(book.bookInfo());
} else {
System.out.println("[책 제목이 일치하지 않습니다.]");
}
}
} else {
System.out.println("[도서관에 등록된 책이 없습니다.]");
}
}
// 모든 책 조회
public void findAllBook() {
System.out.println("[도서관에 등록되어 있는 책 목록을 전부 찾으시겠습니까?(y/n)]");
String str = scanner.nextLine();
if (str.equals("y")) {
if (!libraryList.isEmpty()) {
System.out.println("[도서관에 등록되어 있는 책 목록입니다.]");
for (Book book : libraryList) {
System.out.println("[" + book.bookInfo() + "]");
}
} else {
System.out.println("[도서관에 등록되어 있는 책이 없습니다.]");
}
} else if (str.equals("n")) {
System.out.println("[메인 화면으로 돌아갑니다.]");
} else {
System.out.println("[입력 값이 올바르지 않습니다.]");
System.out.println("[메인 화면으로 돌아갑니다.]");
}
}
// 책 삭제
public void deleteBookLibrary() {
System.out.println("[도서관에 등록되어 있는 책을 삭제하시겠습니까?(y/n)]");
String str = scanner.nextLine();
if (str.equals("y")) {
if (!libraryList.isEmpty()) {
System.out.println("[도서관에 등록되어 있는 책 목록입니다.]");
for (Book book : libraryList) {
System.out.println("[제목 : " + book.getTitle() + "]");
}
System.out.println("[삭제할 책 제목을 입력해주세요]");
String bookName = scanner.nextLine();
boolean remove = false;
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
if (bookName.equals(book.getTitle())) {
libraryList.remove(i);
System.out.println("[책이 삭제되었습니다.]");
remove = true;
break;
}
}
if (!remove) {
System.out.println("[책 제목이 일치하지 않습니다.]");
}
} else {
System.out.println("[도서관에 등록되어 있는 책이 없습니다.]");
}
} else if (str.equals("n")) {
System.out.println("[삭제를 취소합니다.]");
System.out.println("[메인 화면으로 이동합니다.]");
} else {
System.out.println("[입력 값이 올바르지 않습니다.]");
System.out.println("[메인 화면으로 이동합니다.]");
}
}
// 책 대여
public void rentBook() {
boolean borrowListEmpty = false;
System.out.println("[대여 가능한 책 목록입니다.]");
for (Book book : libraryList) {
if (book.isAvailable() == true) {
System.out.println("[ 제목 : " + book.getTitle() + "]");
borrowListEmpty = true;
}
}
if(!borrowListEmpty){
System.out.println("[대여 가능한 책이 없습니다.]");
return;
}
System.out.println("[대여하시겠습니까?(y/n)]");
String str = scanner.nextLine();
if (str.equals("y")) {
System.out.println("[대여하실 책 제목을 입력해주세요]");
String bookName = scanner.nextLine();
boolean find = false;
for (Book book : libraryList) {
if (bookName.equals(book.getTitle())) {
find = true;
if (book.isAvailable()) {
book.setAvailable(false);
System.out.println("[" + bookName + " 제목의 책이 대여되었습니다.]");
} else {
System.out.println("[" + bookName + " 제목의 책은 이미 대여 중입니다.]");
}
break;
}
}
if (!find) {
System.out.println("[책 제목이 일치하지 않습니다.]");
}
} else {
System.out.println("[대여를 취소합니다.]");
}
}
// 책 반납
public void returnBook() {
boolean borrowListEmpty = false;
System.out.println("[반납 가능한 책 목록입니다.]");
for (Book book : libraryList) {
if (!book.isAvailable()) {
System.out.println("[ 제목 : " + book.getTitle() + "]");
borrowListEmpty = true;
}
}
if(!borrowListEmpty){
System.out.println("[반납 가능한 책이 없습니다.]");
return;
}
System.out.println("[대여하신 책을 반납하겠습니까?(y/n)]");
String str = scanner.nextLine();
if (str.equals("y")) {
System.out.println("[반납하실 책 제목을 입력해주세요]");
String bookName = scanner.nextLine();
boolean find = false;
for (Book book : libraryList) {
if (bookName.equals(book.getTitle())) {
find = true;
if (!book.isAvailable()) {
book.setAvailable(true);
System.out.println("[" + bookName + " 제목의 책이 반납되었습니다.]");
} else {
System.out.println("[" + bookName + " 제목의 책은 이미 반납되었습니다.]");
}
break;
}
}
if (!find) {
System.out.println("[책 제목이 일치하지 않습니다.]");
}
} else {
System.out.println("[반납를 취소합니다.]");
}
}
}
- LibraryManagementApplicaton 클래스
- 애플리케이션 실행 및 메인메뉴 관리
- LibraryManagementApplication 클래스는 애플리케이션의 진입점으로, 도서관 관리 시스템의 전반저깅ㄴ 흐름을 제어
- 사용자는 이클래스를 통해 책 관리, 대여, 반납, 책 찾기 등 다양한 기능에 접근할 수 있다.
import java.util.Scanner;
public class LibraryManagementApplication {
private final LibraryContext context;
Library library = new Library();
Scanner scanner = new Scanner(System.in);
public LibraryManagementApplication(LibraryContext context) {
this.context = context;
}
public void run() {
mainView();
}
public void mainView() {
boolean flag = true;
while (flag) {
System.out.println("=[SPARTA-CODING-CLUB 도서관 시스템입니다]=");
System.out.println("=[1. 책 관리 시스템]=");
System.out.println("=[2. 책 찾기 시스템]=");
System.out.println("=[3. 책 대여/반납 시스템]=");
System.out.println("=[4. 프로그램 종료]=");
int input = scanner.nextInt();
switch (input) {
case 1 -> manageBookView();
case 2 -> findBookView();
case 3 -> borrowedBookView();
case 4 -> flag = false;
default -> System.out.println("[입력 값이 올바르지 않습니다]. \n [되돌아갑니다.]");
}
}
}
// 책 관리 시스템 메뉴
public void manageBookView() {
boolean flag = true;
while (flag) {
System.out.println("=[1. 책 등록]=");
System.out.println("=[2. 도서관에 등록]=");
System.out.println("=[3. 책 삭제]=");
System.out.println("=[4. 메인 화면 돌아가기]=");
System.out.println("=[원하는 항목의 번호를 입력해주세요]=");
int input = scanner.nextInt();
switch (input) {
case 1 -> library.createBook();
case 2 -> library.addBookLibrary();
case 3 -> library.deleteBookLibrary();
case 4 -> flag = false;
default -> System.out.println("[입력 값이 올바르지 않습니다.] \n [되돌아갑니다.]");
}
}
}
// 책 찾기 시스템 메뉴
public void findBookView(){
boolean flag = true;
while (flag) {
System.out.println("=[1. 책 제목으로 찾기]=");
System.out.println("=[2. 모든 책 찾기]=");
System.out.println("=[3. 메인 화면 돌아가기]=");
int input = scanner.nextInt();
switch (input){
case 1 -> library.findbyName();
case 2 -> library.findAllBook();
case 3 -> flag = false;
default -> System.out.println("[입력 값이 올바르지 않습니다.] \n [되돌아갑니다.]");
}
}
}
// 책 대여/반납 시스템 메뉴
public void borrowedBookView(){
boolean flag = true;
while (flag) {
System.out.println("=[1. 책 대여하기]=");
System.out.println("=[2. 책 반납하기]=");
System.out.println("=[3. 메인 화면 돌아가기]=");
int input = scanner.nextInt();
switch (input){
case 1 -> library.rentBook();
case 2 -> library.returnBook();
case 3 -> flag = false;
default -> System.out.println("[입력 값이 올바르지 않습니다.] \n [되돌아갑니다.]");
}
}
}
}
책의 등록, 대여, 반납 등의 기능을 구현하면서 실용적인 문제를 해결하는 데 집중할 수 있었다. 사용자 인터페이스를 단순하게 유지하면서도 필요한 기능을 제공하는 방법을 고민할 수 있었다.
앞으로 더 복잡한 애플리케이션을 설계할 때 이번 프로젝트에서 배운 객체지향적 설계와 패턴을 적용해보고 싶다.
'자바' 카테고리의 다른 글
자바 백엔드 면접질문 정리. (0) | 2024.08.28 |
---|---|
[TIL] 2024.08.14 [Java/Spring] (0) | 2024.08.16 |
[TIL] 2024.08.13 [Java/Spring] (0) | 2024.08.13 |
[TIL] Java 2024.08.12 (0) | 2024.08.12 |