[학습 목표]
1. 문자열 처리와 관련된 String , StringBuilder , StringBuffer 클래스의 특징과 차이점을 이해하고, 각 클래스의 적절한 문자열 조작을 수행할 수 있다. 2. 어노테이션 (Annotation) 의 목적과 기본 사용법을 이해하고, 커스텀 어노테이션을 정의하여 코드에 메타데이터를 추가하고 활용할 수 있다. 3. 제네릭(Generic)의 개념과 사용법을 이해하고, 타입 안정성을 보장하면서 재사용 가능한 코드를 작성할 수 있으며, 와일드 카드와 타입 제한을 활용하여 유연한 제네릭 프로그래밍을 구현할 수 있다. 4.컬렉션 프레임워크의 구조와 주요 인터페이스( List , Set, Map )를 이해하고 설명할 수 있다. |
예외 처리
사용자 정의 예외 처리
ex)
// 사용자 정의 예외 클래스
class CustomException extends Exception {
public CustomException(String message) {
super(message); //public Exception (String message)
}
}
public class d_MyException {
public static void main(String[] args) {
try {
if (args.length == 0) {
throw new IllegalArgumentException("값을 입력하세요!"); //명시로
}
int a = Integer.parseInt(args[0]); //정수 범위를 나가면 에러가 남 , NumberFormatException 위임 , 선처리
if (a < 0) {
throw new CustomException("음수잖아~~~");
}
System.out.println("입력 값: " + a);
} catch (CustomException e) {
e.printStackTrace();
System.err.println("사용자 정의 예외 발생: " + e.getMessage()+":"+e.toString());
} catch (NumberFormatException e) {
e.printStackTrace();
System.err.println("숫자가 아닌 값을 입력하셨습니다: " + e.getMessage()+":"+e.toString());
} catch (IllegalArgumentException e) {
e.printStackTrace();
System.err.println("잘못된 입력: " + e.getMessage()+":"+e.toString());
} catch (Exception e) {
e.printStackTrace();
System.err.println("예외 발생: " + e+":"+e.toString());
} finally {
System.out.println("예외 상관 없이 무조건 실행");
}
}
}
위 코드를 보면 다음과 같음을 볼 수 있다.
CustomException -> 음수를 입력했을 때 발생하는 사용자 지정 예외 처리 클래스
NumberFormatException -> 숫자가 아닌 값을 입력 했을 때 그리고 지정된 값보다 많은 값을 입력했을 때
발생하는 예외 처리
IllegalArgumentException -> 입력을 안했을 때 발생하는 예외 처리
String, StringBuffer , StringBuilder
- String 은 불변 (Imutable) 객체이므로 연결 연산(+)이 많을수록 성능이 떨어짐
- StringBuffer와 StringBuilder는 가변 (Mutable) 객체로 , 문자열 변경이 많을 때 성능이 더 좋음 (메모리에 민감)
- StringBuilder 는 싱글쓰레드 환경에서 가장 빠른 성능을 제공
-StringBuffer
public class a_StringBufferTest {
public static void main(String[] args) {
// 1. StringBuffer 객체 생성
StringBuffer sb = new StringBuffer("Hello");
// 2️. append(): 문자열 추가
sb.append(" Java");
System.out.println("append 후: " + sb); // Hello Java
// 3️. insert(): 특정 위치에 문자열 삽입
sb.insert(6, "World ");
System.out.println("insert 후: " + sb); // Hello World Java
// 4️. replace(): 특정 범위를 다른 문자열로 변경
sb.replace(6, 11, "Amazing");
System.out.println("replace 후: " + sb); // Hello Amazing Java
// 5️. delete(): 특정 범위 삭제
sb.delete(6, 13);
System.out.println("delete 후: " + sb); // Hello Java
// 6️.reverse(): 문자열 뒤집기
sb.reverse();
System.out.println("reverse 후: " + sb); // avaJ olleH
// 7️. length()와 capacity() 확인
System.out.println("문자열 길이: " + sb.length()); // 10
System.out.println("버퍼 크기: " + sb.capacity()); // 기본 용량(16) + 초기 문자열 길이
}
}
실행 결과는 다음과 같음을 볼 수 있다.
- String과 StringBuffer , StringBuilder에 대한 성능 시간 차이
public class d_StringPerformanceTest {
public static void main(String[] args) {
final int ITERATIONS = 100000;
// 1.String 성능 테스트
long startTime = System.nanoTime();
String str = "";
for (int i = 0; i < ITERATIONS; i++) {
str += "a";
}
long endTime = System.nanoTime();
System.out.println("String 실행 시간: " + (endTime - startTime) / 1_000_000.0 + " ms");
// 2. StringBuffer 성능 테스트
startTime = System.nanoTime();
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < ITERATIONS; i++) {
stringBuffer.append("a"); // 가변 객체 (성능 향상)
}
endTime = System.nanoTime();
System.out.println("StringBuffer 실행 시간: " + (endTime - startTime) / 1_000_000.0 + " ms");
// 3️. StringBuilder 성능 테스트
startTime = System.nanoTime();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < ITERATIONS; i++) {
stringBuilder.append("a"); // 가변 객체 (StringBuffer보다 빠름)
}
endTime = System.nanoTime();
System.out.println("StringBuilder 실행 시간: " + (endTime - startTime) / 1_000_000.0 + " ms");
}
}
이를 실행해보면 String이 제일 오래 걸림을 볼 수 있다.
reflect
- import java.lang.reflect : 실행 중에 클래스 , 메소드 , 필드 생성자동의 정보를 동적으로 조회하고 조작할 수 있는 기능을 제공하는 API
- 클래스 , 메소드 , 필드 생성자 등의 정보를 동적으로 조회 java Test
- private 필드 메소드 접근 가능
- 프레임워크 (Spring , SpringBoot )에서 객체를 동적으로 생성함
- @랑 함께 사용하면 런타임 조직이 확장가능
- 런타임 중에 특정 메소드 실행 -> invoke()
- 클래스 객체 리플렉트 하고 조작 실행해보기
import java.lang.reflect.Field;
//클래스 객체를 리플렉트 하고 조작 실행 해보자.
class My{
@SuppressWarnings("unused")
private String name = "홍길동";
@SuppressWarnings("unused")
private int a =10;
}
public class a_ClassInfoTest {
public static void main(String[] args) throws Exception {
My m = new My();
Class<?> clazz = m.getClass();
//필드 정보 가져오기
Field field = clazz.getDeclaredField("name");
field.setAccessible(true); //private 멤버 접근
//필드 값 변경
field.set(m, "정길동");
System.out.println("변경된 값 : "+ field.get(m));
System.out.println("=================================");
field = clazz.getDeclaredField("a");
field.setAccessible(true);
//필드 값 변경
field.setInt(m, 20);
System.out.println("변경된 값 : "+field.get(m));
}
}
실행 결과는 다음과 같음을 볼 수 있다.
- 클래스 정보 출력해보기
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class a_ClassInfo {
public static void main(String[] args) {
Integer number = 42;
printClassInfo(number);
}
public static void printClassInfo(Object obj) {
Class<?> clazz = obj.getClass(); // 객체의 클래스 정보
System.out.println("클래스 이름: " + clazz.getName());
// 필드 정보 출력
System.out.println("\n[필드 정보]");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(" - " + field);
}
//메소드 정보 출력
System.out.println("\n[메소드 정보]");
for(Method field : clazz.getMethods()) {
System.out.println(" - "+field);
}
//생성자 정보 출력
System.out.println("\n[생성자 정보]");
for (Constructor field : clazz.getConstructors()) {
System.out.println(" - "+field);
}
}
}
위 코드는 클래스 이름과 필드 정보 , 메소드 정보 , 생성자 정보를 출력하는 코드이다.
어노테이션 (annotation)
FunctionalInterface -> 람다식이랑 같이 사용
SafeVarags -> 가변인자 메소드의 값을 안전하게 보장
Deprecated -> 취소선 , 사용 중지 경고
Override -> 재정의
SuppressWarnings -> 컴파일러 경고 무시
ex)
package com.sec10.myreflect;
//@Override // 메서드 재정의 명시 [검색 결과 없음]
//@Deprecated // 사용 중지 경고
//@SuppressWarnings("unchecked") // 컴파일러 경고 무시
public class c_AnnotatinTest {
@Override
public String toString() {
return "This method overrides Object.toString()";
}
@Deprecated
public void oldMethod() {
System.out.println("This method is deprecated");
}
@SuppressWarnings("unchecked") //타입 체크하지 말고 경고 내지 말아달라고 하는 annotation임
public <T> T unsafeOperation(Object ...obj) { //obj를 한 개 받을 지 여러 개 받을지 모름
//Object ...obj -> 가변 매개이자 , @SafeVarags -> static 메소드 , final 에만 사용한다.
return (T) obj; //값에 의해 타입을 결정하겠다. ... -> 1 more (가변)
//<> Generic type , <T> T -> value 에 의해 type 이 결정되는 것 , 제네릭 타입
}
}
Override는 메소드를 재정의한 것이다.
Deprecated 는 취소선을 만들고 사용 중지 경고를 함을 알 수 있다.
위 코드에서의 SuppressWarnings는 타입을 체크하지 말고 경고 내지 말아달라고 하는 annotation이다.
제네릭스
제네릭스는 컴파일 시 타입 체크하고, 다양한 데이터 타입을 처리할 수 있도록 도와주는 기능
제네릭 클래스 : 특정 타입을 지정하지 않고 , 여러 타입의 데이터를 저장할 수 있는 클래스 T를 사용해 다양한 타입 을 받을 수 있다.
T를 사용해 다양한 타입을 받을 수 있다.
class Test<T> {} - 제네릭 메소드 : 특정 메소드에서만 제네릭 타입을 적용하는 방법
class Test<T> {}-제네릭 메서드(Generic Method) : 특정 메서드에서만 제네릭 타입을 적용하는 방법
public static <T> void print(T item) {
System.out.println(item);}
와일드카드(Generics Wildcard) : 유연한 타입을 허용
List<? extends T> T와 T의 하위 클래스만 허용 -> 상한 제한
List<? super T> T와 T의 상위 클래스만 허용 -> 하한 제한
ex)
public class ProFile<T> {
private String name;
private T dept;
public ProFile(String name, T dept) {
super();
this.name = name;
this.dept = dept;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getDept() {
return dept;
}
public void setDept(T dept) {
this.dept = dept;
}
}
package com.sec11.myutil;
public class ProFileTest {
public static void main(String[] args) {
ProFile<String> p1 = new ProFile<String>("Dominica", "관리자");
ProFile<Integer> p2 = new ProFile<Integer>("Dominico", 1111);
System.out.println(p1.getName() + " " + p1.getDept());
System.out.println(p2.getName() + " " + p2.getDept());
}
}
컬렉션 프레임워크
List : 순서가 있는 데이터의 집합 , 데이터 중복 허용 (ArrayList, LinkedList)
Set : 순서를 유지하지 않는 데이터의 집합 , 데이터 중복 허용 x (HashSet , LinkedHashSet )
Map : 키와 값의 쌍으로 이루어진 데이터의 집합, 순서 유지x , 키 중복 x, 값 중복x ( HashMap, LinkedHashMap , Properties )
- List
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
public class ArrayTest {
public static void main(String[] args) {
List<Integer> arr1 = new LinkedList<>();
arr1.add(80);
arr1.add(90);
arr1.add(100);
arr1.add(200);
System.out.println(" for 문을 이용한 반복 ");
for (int r : arr1) {
System.out.printf("%5d", r);
}
System.out.println("\n listIterator 문을 이용한 반복 ");
ListIterator<Integer> res = arr1.listIterator();
while (res.hasNext()) {
System.out.printf("%5d", res.next());
}
}
}
- Set
package com.sec11.myutil01;
import java.util.*;
public class SetTest {
public static void main(String[] args) {
Set<String> m_set =new HashSet<String>();
m_set.add("java");
m_set.add("servlet/jsp");
m_set.add("spring");
m_set.add("python");
m_set.add("python");
m_set.add(null);
System.out.println("HashSet : " + m_set);
Set<String> t_set = new TreeSet<String>();
t_set.add("java");
t_set.add("servlet/jsp");
t_set.add("spring");
t_set.add("python");
t_set.add("python");
System.out.println("\nTreeSet :"+ t_set);
Set <String> lh_set = new LinkedHashSet <String>();
lh_set.add("java");
lh_set.add("servlet/jsp");
lh_set.add("spring");
lh_set.add("python");
lh_set.add("python");
System.out.println( "\nLinkedHashSet :"+ lh_set);
}
}
-Map
package com.sec11.myutil01;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
public class MapTest {
public static void main(String[] args) {
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("name", "밀로");
hm.put("addr", "Toronto");
hm.put("tel","02-000-000");
System.out.println("전체출력 : " + hm);
//entrySet() -> 키와 값을 분리해주는 역할을 함
System.out.println("\n entrySet()을 이용한 View");
Set< Entry<String, String> > entires = hm.entrySet();
for (Entry<String, String> ent : entires) {
System.out.println(ent.getKey() + " ==> " + ent.getValue());
}
///////////////////////////////
System.out.println("\n keySet()을 이용한 View");
Set<String> keys = hm.keySet();
for (String key : keys) {
System.out.println("Value of " + key + " is: " + hm.get(key));
}
//Collection<V> values()
System.out.println("\n values()을 이용한 View"); //값의 String으로 리턴하겠다.
Collection<String> con = hm.values();
for (String value : con) {
System.out.println("Value is :" + value);
}
System.out.println("\n 키와 값을 찾아 값을 변경 ");
if (hm.containsKey("name") && hm.containsValue("밀로")) {
hm.replace("name", "루리");
}
System.out.println(hm);
}
}
'🦁멋쟁이 사자처럼 15기 > 3월달 수업 내용 정리' 카테고리의 다른 글
멋쟁이 사자처럼 13회차 ( 03 / 17 ) (0) | 2025.03.17 |
---|---|
멋쟁이 사자처럼 12회차 ( 03 / 14 ) (0) | 2025.03.14 |
멋쟁이 사자처럼 11회차 ( 03 / 12 ) (0) | 2025.03.12 |
멋쟁이 사자처럼 10회차 ( 03 / 11 ) (0) | 2025.03.11 |
멋쟁이 사자처럼 9회차 ( 03 / 10 ) (0) | 2025.03.10 |