
3주차 더위가 좀 꺽였네~ 😎
이번 주는 자바 고급(?) 기능(자바API, 자바 컬렉션, 파일입출력, stream(), 익명클래스, 람다, 메서드참조와 Oracle로 Database DML, DDL 학습함.
이번 주는 뭘했나 ?
📂📝📌🚅✈🚀🛸🛰🚩
Object 클래스는 자바의 최상위 클래스이다.
equals(), hashCode(), toString(), clone(), getClass(), finalize()
Object 메소드는 클래스에서 Overide 해서 사용할 수 있다. equals()와 hashCode()는 항상 함께 Overide해서 사용해야 한다.
@Override
public String toString() {
return "Person[" +
"age=" + age +
"세, name='" + name + '\'' +
']';
}
System.out.println(kim.toString());
System 클래스는 OS 일부 기능을 사용 가능하게 한다.
exit() , 프로세스 종료
currentTimeMillis(), 밀리초 < 성능시험에 결과에 사용
nanoTime() , 나노초
getProperty() , JVM 실행 환경변수
gc() Garbage Collector 실행
java.lang 은 import 필요없다.
length() 메서드: 문자열의 길이를 반환한다.
String str = "Hello World!";
int len = str.length(); // len에는 12가 저장됨
charAt() 메서드: 지정된 위치의 문자를 반환한다.
String str = "Hello World!";
char ch = str.charAt(1); // ch에는 'e'가 저장됨
substring() 메서드: 지정된 시작 위치에서부터 지정된 끝 위치까지의 문자열을 반환한다.
String str = "Hello World!";
String substr = str.substring(6, 11); // substr에는 "World"가 저장됨
toUpperCase() 메서드: 모든 문자를 대문자로 변환한다.
String str = "Hello World!";
String uppercase = str.toUpperCase(); // uppercase에는 "HELLO WORLD!"가 저장됨
toLowerCase() 메서드: 모든 문자를 소문자로 변환한다.
String str = "Hello World!";
String lowercase = str.toLowerCase(); // lowercase에는 "hello world!"가 저장됨
indexOf() 메서드: 지정된 문자나 문자열이 처음으로 나타나는 위치를 반환한다.
String str = "Hello World!";
int index = str.indexOf("World"); // index에는 6이 저장됨
replace() 메서드: 지정된 문자나 문자열을 다른 문자나 문자열로 바꾼다.
String str = "Hello World!";
String replaced = str.replace("World", "Java"); // replaced에는 "Hello Java!"가 저장됨
split() 메서드: 지정된 문자열을 기준으로 문자열을 나눈다.
String str = "Hello,Java,World!";
String[] tokens = str.split(","); // tokens에는 ["Hello", "Java", "World!"]가 저장됨
String 클래스의 단점(사용할때 마다 객체를 생성하기 때문에 메모리 낭비 초래)을 보완하기 위해 나옴.
StringBuffer, StringBuilder는 둘다 똑같은 기능을 하며, 멀티 스레드에는 StringBuffer에 사용함.
append(), insert(), replace(), delete(), reverse(), indexof()
System.currentTimeMillis() API로 성능 측정
수학계산.
Math 클래스의 모든 메서드는 static이기 때문에 따로 객체 생성 없이 바로 사용가능
abs(): 절대값을 구함.ceil(): 올림값을 구함.floor(): 내림값을 구함.max(): 수를 비교하여 최대값을 구함.min(): 수를 비교하여 최소값을 구함.random(): 랜덤값을 구함(0.0 <= 값 < 1.0)rint(): 현재 수에서 가까운 정수를 실수형태로 구함.round(): 반올림값을 구함. ← 소수 첫째자리에서 반올림하고 정수를 리턴함. 반올림 자리수 지정 안됨.컬렉션에서는 기본 타입을 받아 주지 않는다.
int a = 100; Integer v1 = a;
double d = 3.14; Double v2 = d;
int i = v1;
double j = v2;
1.7이전에 Date, Calendar 제공했었는데, 문제가 있었음. 자바 1.8 부터 LocalDate, LocalTime, LocalDateTime으로 업글해서 제공함.
주요 메서드
now() : 현재 날짜와 시간 정보를 가지는 LocalDateTime 객체를 반환합니다.of() : 지정한 날짜와 시간 정보를 가지는 LocalDateTime 객체를 생성합니다.getXXX() : LocalDateTime 객체에서 지정한 필드의 값을 반환합니다. (예: getYear(), getMonthValue(), getMonth(), getDayOfMonth(), getHour(), getMinute(), getSecond())plusXXX() : LocalDateTime 객체에 지정한 시간을 더한 새로운 LocalDateTime 객체를 생성합니다. (예: plusDays(), plusHours(), plusMinutes(), plusSeconds())minusXXX() : LocalDateTime 객체에서 지정한 시간을 뺀 새로운 LocalDateTime 객체를 생성합니다. (예: minusDays(), minusHours(), minusMinutes(), minusSeconds())format() : LocalDateTime 객체를 지정한 형식으로 변환하여 문자열로 반환합니다. (예: "yyyy-MM-dd HH:mm:ss"), DateTimeFomatter 객체를 활용.DateTimeFormatter.ofPattern("yyyy년MM월dd일 E요일 a hh시mm분ss초");대표적인 컬렉션의 종류로는 리스트(List), 셋(Set), 맵(Map)

출처: https://gangnam-americano.tistory.com/41
List 인터페이스의 주요 메서드
List 인터페이스를 구현했다면 해당 메서드를 공통적으로 가지고 있다.
타입의 형식을 지정하여 타입 안정성을 꾀하기 위한 문법
ArrayList<String> nick = new ArrayList<>()
// <String>은 ArrayList에 모아 둘 리스트 타입은 String이다. 라는 의미임
// new 뒤의 <String>은 생략하여 <> 표현(가능)함.
컬렉션 객체들은 Collections의 기능을 사용할 수 있다.
Collections는 컬렉션 객체들의 부가 기능을 사용할 수 있다.
// 컬렉션 객체는 객체 참조 타입만 가능하다.
// int는 안되고 Integer로 넣어야함.
List<int> score = new ArrayList<>(); -> List<Integer> score = new ArrayList<>();
score.add(65); // Autoboxing
// 리스트 생성과 동시에 객체 초기화 하기
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// add 10번을 한번에 쉽게 추가하기
Collections.addAll(score, 78, 100, 21, 100, 33, 99);
// 컬레션 내의 객체의 개수 구하기
System.out.println("100점 학생수 : " + Collections.frequency(score, 100));
// 최대값, 최소값
System.out.println("최대값 : " + Collections.max(score));
System.out.println("최소값: " + Collections.min(score));
// 정렬
Collections.sort(score);
// 내림차 정렬
Collections.sort(score, Collections.reverseOrder());
// 배열을 단순 역순으로 배치(정렬이 아님)
Collections.reverse(score);
// 두 요소의 위치를 교체: swap(리스트, i, j)
Collections.swap(score, 3, 6);
// 리스트 내의 요소를 무작위로 섞기
Collections.shuffle(score);
// 원하는 객체로 걸렉션을 전부 초기화
Collections.fill(score, 100);
// 리스트 생성과 동시에 객체 초기화 하기
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println("list = " + list);
// asList로 리스트를 만들면 고정된 크기의 리스트가 만들어짐.
// 그래서, 요소 추가/삭제는 안됨.
list.add(100); //삽입 불가
list.remove(6); //삭제 불가
list.set(10, 100); //수정은 가능
연결 리스트(LinkedList)는 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식의 자료구조
출처: https://coding-factory.tistory.com/552
LinkedList<String> list = new LinkedList<>();
list.add("홍길동");
list.addFirst("맨 앞");
list.addLast("맨 뒤");
System.out.println(list.get(3));
System.out.println(list.getFirst());
System.out.println(list.getLast());
list.remove("맨 앞");
System.out.println(list);
// 링크드 리스트가 스택의 기능을 가지고 있다.
// LIFO: Last In First Out, Stack
// push, pop, peek
list.push();
list.pop();
list.peek(); // 데이터는 유지
// FIFO: First In First Out
// offer, poll, peek
링크드 리스트는 검색에서 성능이 ArrayList에 비해서 많이 안 좋다.
Set 컬렉션은 저장 순서를 보장하지 않으며 객체의 중복 저장을 허용하지 않는다.
Set 컬렉션은 인덱스로 관리하지 않으며 들어갈 때의 순서와 나올 때의 순서가 다를 수도 있다.
Set 컬렉션은 인덱스로 객체를 검색하는 기능이 없고 전체 객체를 대상으로 한번씩 반복해서 객체의 값을 가져오는 반복자(Iterator)를 제공한다.
중복을 허용하지 않는다.
/*
* # Set
* - 집합을 구현해 놓은 인터페이스
* - 요소로 같은 값이 들어오는 것을 허용하지 않는다.
* # Hash
* - 어떤 값을 넣었을 때 전혀 예측하지 못할 값이 생성되어야 하는 알고리즘
* - 예측할 수 없는 값을 이용하기 때문에 정렬이 불가능.
* - 생성된 값으로 원래 값을 찾는 것도 불가능에 가깝다.
* - 다시 원래 값으로 돌아갈 수 없는 단방향성 알고리즘
* - 속도가 빠르고 보안성이 뛰어난 알고리즘. 객체의 주소값을 할당하거나
* 암호화 알고리즘에서 많이 사용됩니다.
*/
// HashSet<String> set = new HashSet<>();
// --> 다형성 적용 하면 HashSet<String> --> Set<String>
Set<String> set = new HashSet<>();
// 객체를 저장: add(객체)
set.add("java");
set.add("jsp");
set.add("spring");
set.add("oracle");
Collections.addAll(set, "mysql", "java");
System.out.println(set);
// set의 크기 확인: size()
System.out.println(set.size());
/*
* set은 인덱스가 없기 떄문에 메서드를 이용해서 객체를 얻는게 아니라
* 반복자 (Iterator)를 통해서 요소를 하나씩 꺼내야 함.
* 반복자 객체는 set 인터페이스가 제공하는 iterator()를 호출하여
* 얻어옴
*/
Iterator<String> iter = set.iterator();
// String next = iter.next();
while (iter.hasNext()) {
System.out.println(iter.next());
}
이거는 자료 구조할 때, 시간되면 알려준다고 함. 흐흐흐~
Map은 Collection을 상속하지 않았기 때문에
위에서 확인한 List와 Set 과는 다른 메서드 이름을 가진다.
Map 인터페이스를 구현한 Map 컬렉션 클래스들은 키와 값을 하나의 쌍으로 저장하는 방식
(Key - Value 방식) 을 사용한다.
Key는 실질적인 값을 찾기 위한 이름의 역할을 하기 때문에 중복을 허용하지 않는다.
출처: https://velog.io/@gillog/Map-컬렉션-HashMap
Map 인터페이스를 구현한 클래스 중 가장 흔하게 사용하는 클래스이며 키 값을 중복하지 않게 하기 위해 hashCode(), equals() 메서드가 오버라이딩 된 객체를 key로 지정해야 한다.
그래서, 대부분 key를 String으로 많이 지정한다.
키와 값의 쌍으로 저장하는 Map의 특징을 그대로 가지고 있으며, 저장 순서를 보장하지 않는다.
Map의 특징을 가지고 있으면서, 저장된 순서를 보장하고 싶을 때 사용하는 클래스이다.
LinkedList처럼 데이터와 주소값을 함께 저장해서, 연결되어 있는 형태라고 생각하면 된다.
/*
* Map
* - Key/Value가 한 세트를 이루는 자료구조
* - Key 값을 통해 value를 참조하는 방식(인덱스 없다.)
* - Key는 중복 저장을 허용하지 않음.
*/
// Map은 Key, Value 쌍을 이루기 때문에 멀티 제레닉<T, T>을 설정해야한다.
// Collections의 메서드는 Collections 인터페이스 타입을 전달받기 때문에
// Map에 사용이 힘들다.
// Collections.addAll(map, 1, 2, 3, 4); // Collections 사용 못함.
리스트에서 <>를 지정 안하면 Object 타입으로 인식 되어 자식 Casting을 해줘야 하는 불편함이 생긴다.
<T> <K, V> 객체 생성 시점에 필드와 타입을 정한다./*
* Object타입으로 선언하면 무엇이든 저장할 수는 있지만,
* 반대로 저장했던 값을 꺼내올 때는 타입별로 일일히 형변환을 해야하는
* 문제가 발생합니다.
* 잘못 형 변환 했을 시에는 예외가 발생할 수도 있다.
*/
/*
* # <> 제네릭
* - 클래스 내부에서 타입을 지정하는 것이 아니라
* 외부에서 객체를 생성할 때 타입이 지정될 수 있게 하는 문법.
* 제네릭을 사용하면 객체로 생성할 때 사용할 타입을 지정할 수 있고,
* 따로 타입을 체크하고 변환해줄 필요가 없다.
* 관리가 용이하고 잘못된 타입이 들어올 수 있는 것을 방지
* 유지보수성, 코드의 재사용성이 높아진다.
*/
public interface GenericPredicate<T> {
boolean test(T t);
}
상수를 정의해서 코드를 작성하면 다양한 문제가 발생할 수 있다.
1. 상수의 값 자체는 변경이 불가하겠지만, 상수를 받는 객체의 필드 값은 안정적이지 못함.
2. 상수는 어느 클래스에서나 선언할 수 있기 때문에 무분별한 상수 선언이 이뤄질 수 있음.
3. 코드의 가독성 또한 좋지 못하다.
enum 클래스를 사용하면 얻을 수 있는 장점.
1. 코드가 단순해지고 가독성이 좋아짐.
2. 정의한 상수 이외의 값을 컴파일 과정에서 막기 때문에 타입 안정성이 증가함.
3. 관련있는 상수들끼리 모아놓기 때문에 구현의 의도를 명확하게 파악 가능.
예제 코드: package etc.enum_;
public enum Language {
JAVA("자바", true),
JAVASCRIPT("자바스크립트", false),
PHYTON("파이썬", false),
CPP("C++", true),
C("C", true);
...
}
폴더 생성, 파일 정보를 가지는 객체 생성
File directory = new File(ROOT_PATH + "/hello");
try/catch로 IOException 처리를 해주어야 한다.
// 폴더 생성
if (!directory.exists()) {
directory.mkdir();
}
// 파일 생성하기
File newFile = new File(ROOT_PATH + "/hello/food.txt");
if (!newFile.exists()) {
try {
newFile.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
close가 필요한 하드에어 접근 코드에 대해 메모리 자원 반납 처리(1.8 부터 사용가능)
close 하려는 객체가 AutoCloseable 인터페이스의 구현체여야 함.
// FileOutputStream fos = null;
try(FileOutputStream fos
= new FileOutputStream(FileExample.ROOT_PATH+"/hello.txt")) {
// fos = new FileOutputStream(FileExample.ROOT_PATH + "/hello.txt");
fos.write(msg.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
// finally {
// try {
// fos.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
try (FileInputStream fis
= new FileInputStream(FileExample.ROOT_PATH + "/hello.txt")) {
int data =0;
// fis.read()를 통해 지정한 파일의 내용을 바이트 단위로 읽어들임.
// 더 이상 읽을 데이터가 없다면, -1을 리턴
while ((data = fis.read()) != -1) {
//data = fis.read();
//if(data == -1) break;
System.out.write(data);
}
// 미리 작성했던 출력 데이터를 한 번에 비워내기
System.out.flush();
} catch (Exception e) {
e.printStackTrace();
}
String targetPath = FileExample.ROOT_PATH + "/member.txt";
try (FileReader fr = new FileReader(targetPath)) {
while (true) {
int i = fr.read();
if (i == -1) {
break;
}
System.out.println((char) i);
}
} catch (Exception e) {
e.printStackTrace();
}
String targetPath = FileExample.ROOT_PATH + "/member.txt";
try (FileReader fr = new FileReader(targetPath)) {
BufferedReader br = new BufferedReader(fr); // BufferedReader(new FileReader)
while (true) {
// int i = fr.read();
// if (i == -1) {
// break;
// }
// System.out.println((char) i);
String str = br.readLine();
if(str==null) break;
System.out.println(str);
}
} catch (Exception e) {
e.printStackTrace();
}
객체를 스트림으로 전송하려면 직렬화가 가능해야 함.
// 객체를 세상 밖으로 보내기 위해서는 Serializable 인터페이스를 구현해야 한다.
public class Snack implements Serializable {
...
}
---- 저장 ---
List<Snack> snackList = new ArrayList<>();
Collections.addAll(snackList,
new Snack("콘칩", 1970, 1500, Snack.Taste.GOOD),
new Snack("새우깡", 1971, 2000, Snack.Taste.SOSO),
new Snack("나쁜깡", 1999, 3000, Snack.Taste.BAD)
);
System.out.println(snackList.toString());
try (FileOutputStream fos = new FileOutputStream(FileExample.ROOT_PATH + "/snack.sav")) {
// 객체를 출력할 수 있는 보조 스트림
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(snackList);
} catch (Exception e) {
e.printStackTrace();
}
--- 읽기 ---
try (FileInputStream fis
= new FileInputStream(FileExample.ROOT_PATH + "/snack.sav")) {
// 객체를 불러 올 보조 스트림
ObjectInputStream ois = new ObjectInputStream(fis);
List<Snack> snackList = (List<Snack>) ois.readObject();
for (Snack snack : snackList) {
System.out.println(snack);
}
} catch (Exception e) {
e.printStackTrace();
}
// 빠르게 입력받는 방법: BufferedReader
// 빠르게 출력하는 방법: BufferedWriter
// 토크나이져: split(), StringTokenizer()
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String str = br.readLine();
// split()
// String[] arr = str.split(" ");
// System.out.println(Integer.parseInt(arr[0]) + Integer.parseInt(arr[1]));
//
// long end = System.currentTimeMillis();
// System.out.println("소요시간: " + (end - start + "ms"));
// StringTokenizer
StringTokenizer st = new StringTokenizer(str, " ");
int i = Integer.parseInt(st.nextToken());
int j = Integer.parseInt(st.nextToken());
// System.out.println(i + j);
bw.write(i + j + "\n");
bw.flush();
bw.close();
백준, 프로그래머스
내부 클래스(inner class)
특정 클래스(아래 예: Main)에서만 쓰는 클래스
작업중인 클래스와 밀접한 연관이 있는 경우 클래스 내에 클래스를 선언
일반 class에서는 private 선언 안됨.
클래서 안에서 클래스를 선언하면 private 선언 가능
내부에서는 static을 붙이는 것을 권장.
(메모리 낭비 방지, 바깥 쪽 클래스 호출시마다 재생성되는 것을 방지함.)
public class Main {
private static class SubCalculator implements Calculator {
@Override
public int operator(int n1, int n2) {
return n1 - n2;
}
}
public static void main(String[] args) {
Calculator cal = new AddCalculator();
int r1 = cal.operator(10, 20);
System.out.println(r1);
cal = new SubCalculator();
int r2 = cal.operator(50, 27);
System.out.println("r2 = " + r2);
// 익명 클래스(인터페이스의 구현체를 즉석에서 선언 후 사용)
cal = new Calculator() {
@Override
public int operator(int n1, int n2) {
return n1 * n2;
}
};
int r3 = cal.operator(10, 40);
System.out.println("r3 = " + r3);
}
}
참고사이트: 꼭 읽어 보자
☕ 내부 클래스(Inner Class) 장점 & 종류 총정리
코드의 간결성과 가독성을 높이기 위해 도입된 기능으로, 주로 함수형 프로그래밍을 지원. 자바 8부터 도입되었으며, 익명 함수(anonymous function)를 표현할 때 사용됩니다. 람다식은 주로 함수형 인터페이스(functional interface)와 함께 사용
@FunctionalInterface // 람다를 사용할 수 있는 인터페이스인지 문법을 점검해준다.
@FunctionalInterface // 어노테이션을 선언하면 람다 I/F 가능하므로, 메서드는 하나만 존재해야함.
@FunctionalInterface
public interface Calculator {
int operator(int n1, int n2);
}
// 람다
cal = (n1, n2) -> n1 / n2; // 화살표 옆의 문장이 리턴 값 의미. 함수형 코드 작성.
// 위를 풀어 쓴 코드
cal = (n1, n2) -> {
return n1 / n2;
};
ex2) stream()을 이용하여 짝수만 뽑아 새 배열 생성:
// filter() 파라미터 람다식
int[] arrInt = strTmp.concat(Arrays.stream(num_list).filter(n -> n % 2 == 0).toArray());
참고사이트: https://blog.jetbrains.com/idea/2010/11/smarter-and-faster-introduce-variable-in-java/
코드 적용할 위치에 커서를 위치시킨 후 Alt+Enter 호출하여 Method reference로 변경가능

// Method Refecence 적용결과
// d->d.isVegeterian() --> Dish::isVegeterian
boolean flag1 = menuList.stream().anyMatch(Dish::isVegeterian); // Method reference 적용
Oracle 11g Express Version 설치
다운로드: https://www.oracle.com/database/technologies/xe-prior-release-downloads.html











그 다음 아래 그림과 같이 alter 명령 입력 후 DB unlock






SQL은 크게 다음과 같은 4가지 종류로 분류됩니다.
| 종류 | FullName | 설명 | 대표명령어 |
|---|---|---|---|
| DDL | Data Definition Language | 데이터베이스 스키마를 생성, 변경, 삭제 | CREATE, ALTER, DROP, RENAME, TRUNCATE |
| DML | Data Manipulation Language | 데이터를 검색, 삽입, 수정, 삭제 | SELECT, INSERT, UPDATE, DELETE |
| DCL | Data Control Language | 데이터베이스 사용자의 권한 관리 | GRANT, REVOKE |
| TCL | Transaction Control Language | 데이터베이스 트랜잭션 관리 | COMMIT, ROLLBACK, SAVEPOINT} |
https://github.com/jh080724/sql_study202408.git
| Section | URL |
|---|---|
| SELECT | github - SELECT * FROM table |
| WHERE | github - WHERE 절 |
| 문자열 함수 | 문자열 함수 |
| 숫자 날짜 함수 | 숫자날짜 함수 |
| 형변환 함수 | 형변환 함수 |
| 집합 연산자 | 집합 연산자 |
| 그룹함수 | 그룹함수(GROUP BY, HAVING) |
| JOIN | 조인 1 |
| JOIN | 조인 2 |
| JOIN | 조인 3 |
| JOIN | JOIN 4 |
| 서브쿼리 | Sub Query |
| 테이터 조작 | INSERT INTO table, UPDATE table SET, DELETE table |
| 트랜젝션 | TRANSACTION |
| 제약조건 | CONSTRAINT |
| 테이블 생성 | CREATE TABLE |
| View 생성 | CREATE VIEW |
| 시퀀스 | CREATE SEQUENCE |
| 계정생성 및 권한관리 | CREATE USER, GRANT, REVOKE |
| 그룹함수 | GROUP BY ROLLUP,CUBE,GROUPING SETS |
| 윈도우 함수 | ROW_NUMBER, RANK, DENSE_RANK, LEAD, FIRST_VALUE, LAST_VALUE, NTILE |
람다, stream() 들어가면서 좀 혼란 스러웠는데, 걍 수학 공식같은 syntax로 받아 들이기로 했다. 흠냐~ 자바스러운 코드에 익숙해지기 위해서 프로그래머스 코딩테스트 문제를 stream, collection등을 적용해서 인텔리J에서 직접 코딩해보기로 한다. 인프런 김영한 자바 기본 강의로 복습을 진행했는데, 이거 강추다~ 이제 Java를 쬐금 더 알아가고 있는 듯 하긴 한데... Java의 정석 책 고급 부분을 좀 봐야 하나 싶다. 네트웍 프로그램 부분과 쓰레드 프로그램은 알아서 공부해야 하나 봄... ^^;