본문 바로가기

Web Development/SIST

[Java] 3주차 수업: 2024.03.04 - 2024.03.08

2024.03.04

 

*StringBuffer

-스트링 클래스와 달리 스트링버퍼는 수정해도 새로운 문자열이 만들어지지 않음

  -> 수정을 많이 해야 하는 경우에는 스트링보다 스트링버퍼 사용

 

-sb.insert(index, 문자열) : 지정한 인덱스에 문자 삽입

-sb.append(문자열) : 문자 뒤에 문자열 삽입

-sb.replace(시작 인덱스, 끝 인덱스, 문자열) : 시작 인덱스부터 끝 인덱스 전까지 문자열 대체

-sb.deleteCharAt(인덱스) : 지정한 인덱스의 문자를 삭제

- sb.delete(시작 인덱스, 끝 인덱스) : 시작 인덱스부터 끝 인덱스 전까지 문자열 삭제

 

-StringBuffer를 String으로 변환할 때에는 toString() 메서드 사용

 

*Wrapper 클래스

: 기본자료형을 객체 형태로 저장

 

*Wrapper 클래스 생성 방법

char c = 'A';
Character wrap_c = c; // 기본 자료형 데이터 -> 참조 자료형 데이터 (직접 대입)

-생성자를 만들지 않고 String 문자열 암시적 생성하듯이 생성.

-자동적으로 기본자료형에서 참조자료형이 되는걸 auto boxing이라고 함 (캐스팅이라는 말 쓰지 x)

-값을 끄집어낼때도 따로 메서드 사용하지 않고 참조변수를 명시 (auto unboxing)

// auto boxing/unboxing 
Integer obj3 = 12;
Integer obj4 = 20;

Integer result2 = obj3 + obj4;  // 바로 연산 가능

 

*java.lang.Math

-Java.lang 패키지는 가장 기본적인 클래스들이 모여있기 때문에 따로 import 하지 않아도 됨

 

-Math.abs(a) : 절대값

-Math.ceil(a) : 올림

-Math.floor(a) : 내림

-Math.round(a) : 반올림

-Math.max(a, b) : 최대값

-Math.min(a, b) : 최소값

 

-Math.random() : 0 ~ 1미만의 실수인 무작위 난수 생성

-0~3 까지의 값 중 랜덤한 정수를 얻고싶다면 위 메서드로 얻은 난수에 정수의 개수(4)를 곱해주고 (int)로 형변환

-1~4의 값을 얻고싶다면 +1을 해주면 됨

package kr.s20.object.lang;

import java.util.Random;

public class MathMain02 {
	public static void main(String[] args) {
		String[] gift = {"스마트폰", "TV", "냉장고", "꽝"};
					    //  0       1       2     3
		  
		//난수 발생 : 0 ~ 1미만의 실수
		double ran = Math.random();
		System.out.println("발생한 난수 : " + ran);
		int index = (int) (ran*4); //0~3
		System.out.println("정수로 변환한 난수: " + index);
		System.out.println("오늘의 선물 : " + gift[index]);
		
		System.out.println("---------------------");
		
		String[] luck = {"귀인을 만남", "해외여행", "로또 당첨", "피곤한 하루"};
		
		Random r1 = new Random();
		// 0부터 인자로 전달된 값의 전까지의 범위로 난수 발생 0 ~ 3
		index = r1.nextInt(4);
		System.out.println("발생한 난수 : " + index);
		System.out.println("오늘의 운세 : " + luck[index]);
		
	}
}

 

*java.util.Random

Random 클래스로 난수를 얻을 수도 있음

-nextInt(), nextBoolean(), nextFloat() 등의 메서드를 통해 다양한 자료형의 랜덤 값을 얻을 때 유용

 

*Date 클래스

-현재 날짜/시간 구하기

Date now = new Date();
System.out.println(now.toString());

-Date 클래스의 메서드들은 거의 다 deprecated되어 Calendar 클래스를 사용하는 것을 권장

 

*java.text.SimpleDateFormat

-DateFormat 클래스를 상속받아 날짜를 좀 더 예쁜 형태로 표현하게 해주는 클래스

-쉽게 한글 포맷으로 쉽게 사용 가능(Locale.KOREA 인자 추가)

SimpleDateFormat sf = new SimpleDateFormat("yyyy년MM월dd일 (E) a hh:mm:ss", Locale.KOREA);
String today = sf.format(now);
System.out.println(today);  // 2024년03월04일 (월) 오후 10:30:40

 

-API: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/SimpleDateFormat.html

 

*java.util.Calendar

-현재 날짜/시간 구하기

Calendar today = Calendar.getInstance();
// 여기서 원하는 값을 상수로 받아와서 사용해야함

int year = today.get(Calendar.YEAR);  //연도
int month = today.get(Calendar.MONTH) + 1;  //월 (MONTH 상수는 0~11을 반환함)
int date = today.get(Calendar.DATE);  //날짜

System.out.printf("%d년 %d월 %d일 ", year, month, date);
		
int day = today.get(Calendar.DAY_OF_WEEK); //요일 (DAY_OF_WEEK 상수는 1~7을 반환)
String days[] = {"일", "월", "화", "수", "목", "금", "토"};
	
System.out.print(days[day-1]+"요일 ");

int amPm = today.get(Calendar.AM_PM);  //오전 0, 오후 1
String str = amPm == Calendar.AM ? "오전" : "오후";
		
int hour = today.get(Calendar.HOUR);
int min = today.get(Calendar.MINUTE);
int sec = today.get(Calendar.SECOND);
		
System.out.printf("%s %d시 %d분 %02d초", str, hour, min, sec);

 

※MONTH 상수는 0~11 을 반환하기 때문에 실제 월을 구하려면 +1 해줘야함

※DAY_OF_WEEK 상수는 일요일부터 1~7을 반환

 

-Calendar.getInctance() 메서드를 통해 인스턴스를 생성하고 get() 메서드를 통해 원하는 값을 상수로 받아와 사용

 

-Calendar 인스턴스에 희망날짜 세팅하기

Calendar cal = Calendar.getInstance();
cal.set(int year, int month, int date);

 

-특정 달의 마지막 날짜 구하기

int lastOfDate = cal.getActualMaximum(Calendar.DATE);

 

*java.util.StringTokenizer

-String 클래스의 split() 메서드와 비슷하게 구분자를 이용하여 문자열을 쪼개어주는 기능

String source = "100,200,300,400";
StringTokenizer st = new StringTokenizer(source, ",");
		
// 구분자를 통해서 잘려진 문자열이 있는지 검증
while (st.hasMoreTokens()) {
	System.out.println(st.nextToken());
}

 

[StringTokenizer와 split() 비교]

StringTokenizer split()
java.util에 포함된 클래스다. String 클래스에 속해있는 메소드
문자로 문자열을 구분 정규표현식으로 구분
오직 단 한 문자의 구분자만 사용 가능 정규표현식을 이용하면 두 문자 이상의 구분자도 사용 가능
복수의 구분자 지정 가능 하나의 구분자만 지정 가능
결과값이 문자열 String 결과값이 문자열 배열 String[]
빈 문자열을 토큰으로 인식하지 않음 빈 문자열을 토큰으로 인식함

 

→ 데이터 양이 적을 때 배열에 담아 반환하는 split는 데이터를 바로 잘라서 반환해주는 StringTokenizer보다 느릴 수 있다.

(출처: https://velog.io/@effirin/Java-StringTokenizer%EC%99%80-Split-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%96%B8%EC%A0%9C-%EC%8D%A8%EC%95%BC%ED%95%A0%EA%B9%8C)

 

<실습>

kr.s20.object.lang.StringMain05

package kr.s20.object.lang;

public class StringMain05 {
	public static void main(String[] args) {
		/*
		 * [실습]
		 * 아래 문자열의 대문자->소문자, 소문자->대문자
		 */

		// 아스키코드와 String 클래스의 메서드 이용한 방법
		String str = "abcMDye-4W?EWzz";
		String result = "";

		for (int i = 0; i < str.length(); i++) {
			char c = str.charAt(i);

			if (c >= 'A' && c <= 'Z') {
				result += String.valueOf(c).toLowerCase();
			} else if (c >= 'a' && c <= 'z') {
				result += String.valueOf(c).toUpperCase();
			} else {
				result += c;
			}
		}

		System.out.println(result);

		System.out.println("--------------------");

		
		// 다른 방법: Character wrapper class 이용
		String result2 = "";

		for (char c : str.toCharArray()) {

			if (Character.isUpperCase(c)) {  // 대문자이면 true 반환
				result2 += Character.toLowerCase(c);
			} else if (Character.isLowerCase(c)) {  // 소문자이면 true 반환
				result2 += Character.toUpperCase(c);
			} else {
				result2 += c;
			}
		}

		System.out.println(result2);

		System.out.println("--------------------");

		
		// 다른 방법: 아스키 코드만 이용
		String result3 = "";
		
		for (int i = 0; i < str.length(); i++) {
			char c = str.charAt(i);

			if (c >= 'A' && c <= 'Z') {
				result3 += (char)(c + 32);  // char로 형변환하지 않으면 아스키코드 형태로 표현됨
			} else if (c >= 'a' && c <= 'z') {
				result3 += (char)(c - 32);
			} else {
				result3 += c;
			}
		}
		
		System.out.println(result3);

		System.out.println("--------------------");
	}
}

 

-기본 자료형을 wrapper class로 묶으면 다양한 메서드를 이용할 수 있음

 

 

*추상클래스

: 일반클래스와 달리 미완성되어 있는 클래스

-일반적으로 한 개 이상의 추상메서드를 가짐

-객체 생성이 불가능하고 상속관계를 맺은 자식 클래스에서 구현해야 사용이 가능

 

*추상메서드

: 선언부만 있고 구현부가 없는 메서드

public abstract void make();

 

-어떤 클래스에서 자식클래스에서 꼭 의무적으로 구현해야 할 메서드가 있는 경우 추상클래스를 만듦

-> 의무를 부여

 

-추상클래스가 추상클래스를 상속하면 추상메서드 구현의 의무를 지지 않음

  (어차피 추상클래스라서 메모리에 올라갈 수 없기 때문에)

 

 

2024.03.05

 

*인터페이스

-클래스가 멤버필드(변수,상수)와 실행 가능한 메서드를 구성요소로 한다면 인터페이스는 상수와 추상메서드를 구성요소로 함

-추상메서드는 일반클래스에 구현되어야만 사용이 가능

-인터페이스를 이용하면 정의해야 하는 메소드(프로그램기능)을 표준화하고 강제할 수 있음

 

*인터페이스의 규칙

1) 모든 멤버 변수는 public static final 이어야 하며, 이를 생략할 수 있다.
2) 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.(단, static메서드와 default 메서드는 JDK1.8부터 예외)

 

-인터페이스 타입을 매개변수로 받는다는 것

  = 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야 한다는 의미

-리턴 타입이 인터페이스 타입이라는 것

  = 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 의미

 

-인터페이스는 인터페이스만 상속받을 수 있으며 다중상속, 다중구현 가능

-상속과 구현을 동시에 하는 것도 가능

// 다중상속
interface Inter3 extends Inter1,Inter2{
	public int getData();
}
// 다중구현
public class InterfaceMain05 implements Inter3,Inter4{
	@Override
	public int getA() {
		return 10;
	}
	@Override
	public int getB() {
		return 20;
	}
	@Override
	public int getData() {
		return 30;
	}
	@Override
	public String getMsg() {
		return "서울";
	}
	public static void main(String[] args) {
		InterfaceMain05 it = new InterfaceMain05();
		System.out.println(it.getA());
		System.out.println(it.getB());
		System.out.println(it.getData());
		System.out.println(it.getMsg());
	}
}

 

*Enum

-클래스처럼 보이게 하는 문자열 상수
-서로 관련있는 상수들끼리 모아 상수들을 대표할 수 있는 이름으로 타입을 정의하는 것
-Enum 클래스 형을 기반으로 한 클래스형 선언

-> enum의 핵심: 상수를 단순히 정수로 치부하지말고 객체 지향적으로 객체화해서 관리하자는 취지

 

*java.lang.Enum 객체의 메서드

메소드 설명 리턴 타입
name() 열거 객체의 문자열을 리턴 String
ordinal() 열거 객체의 순번(0부터 시작)을 리턴 int
compareTo() 열거 객체를 비교해서 순번 차이를 리턴 int
valueOf(String name) 문자열을 입력받아서 일치하는 열거 객체를 리턴 enum
values() 모든 열거 객체들을 배열로 리턴 enum[]

 

-Enum 클래스도 Object 클래스를 상속함

(출처: https://inpa.tistory.com/entry/JAVA-☕-열거형Enum-타입-문법-활용-정리)

 

 

*내부클래스

-특정 클래스 내에 또 다른 클래스가 정의되는 것

종류 설명
Member 멤버 변수나 멤버 메서드들과 같이 클래스가 정의된 경우에 사용한다.
Local 특정한 메서드 내에 클래스가 정의된 경우에 사용
Static static 변수(클래스 변수)와 같이 클래스가 static으로 선언된 경우에 사용
Anonymous 참조할 수 있는 이름이 없는 경우에 사용

 

*멤버 내부클래스

class Outer {
	// Outer의 멤버 변수
	int x= 100;
	
	// 내부 클래스 (멤버 내부클래스)
	class Inner {
		// Inner의 멤버 변수
		int y = 200;
	}
}

public class MemberMain01 {
	public static void main(String[] args) {
		Outer ot = new Outer();
		// Outer의 내부클래스인 Inner 클래스를 객체 생성
		Outer.Inner oi = ot.new Inner();
	}
}

 

-멤버 내부클래스의 객체를 생성할 때 외부클래스 객체의 참조변수를 참조해주어야 함

-멤버 내부클래스에서는 외부클래스 내의 다른 멤버 변수에 접근할 수 있음

 

*로컬 내부클래스

-로컬 내부클래스에서 외부 클래스의 멤버 변수에는 자유롭게 접근 가능

-로컬 내부클래스가 포함된 메서드의 지역 변수를 호출할 때 자동으로 상수화가 진행되어 데이터를 변경할 수 없음

  (값을 가져와서 쓸 수는 있지만 변경 불가)

-그 이유는 메서드가 수행을 마쳐서 지역변수가 소멸된 시점에도, 로컬 내부클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수 있기 때문

public class LocalMain02 {
	// 멤버 변수
	int a = 100;
	
	// 멤버 메서드
	public void innerTest() {
		int b = 500;  //지역변수
		
		// 로컬 내부클래스
		class Inner {
			public void getData() {
				//멤버 변수 호출
				System.out.println("변경 전 : " + a);
				a = 200;
				System.out.println("변경 후 : " + a);
				System.out.println("-------------------");
				
				//지역 변수 호출
				System.out.println("지역 변수 변경 전 : " + b);
				// 로컬 내부클래스가 포함된 메서드의 지역 변수를 호출할 때
				// 자동으로 상수화가 진행되어 데이터를 변경할 수 없음
				// b = 1000;
			}
		}
		
		// 내부클래스 객체 생성
		Inner i = new Inner();
		i.getData();
	}

 

*static 내부클래스 (멤버 내부클래스의 변형)

 (일반 클래스에는 스태틱을 붙일 수 없음)

-외부클래스의 객체를 생성하지 않고 내부클래스에 접근/호출

public class StaticMain {
	// static 내부클래스
	public static class Inner {
		// 인스턴스 변수
		int iv = 100;
		// static 변수
		static int cv = 200;
		// static 메서드
		public static void make() {
			System.out.println("하하하");
		}
	}
	
	
	public static void main(String[] args) {
		// static 내부클래스 객체 생성
		Inner i = new Inner();
		
		// 인스턴스 변수 호출
		System.out.println(i.iv);
		
		// static 변수 호출
		System.out.println(Inner.cv);
		
		// static 메서드 호출
		Inner.make();
	}
}

 

*Anonymous 내부클래스

-자기 이름을 사용하지 않고 부모 이름을 빌려다 쓰는 클래스 (따로 부모클래스가 없으면 최고조상인 Object를 상속받을 수도 있음)

-생성자 뒤에 중괄호가 있으면 100% 익명 내부클래스가 생성된 것

-내부클래스를 정의하는 부분과 생성하는 부분을 합친 것

  -> 생성자 뒤에 있는 중괄호는 클래스 정의부 & 앞부분은 객체 생성 부분

class Inner7 {
	public void disp() {
		System.out.println("부모클래스의 disp");
	}
}

public class AnonymousMain {
	public void make() {
		// 익명 내부클래스
		// Inner7 클래스가 상속된 이름 없는 클래스를 객체 생성
		Inner7 i = new Inner7() {  //클래스 정의부
			@Override
			public void disp() {
				System.out.println("익명 내부클래스의 disp");
			}
		};
		i.disp();
	}

 

*java.util.Arrays 클래스

-Arrays.sort(a) : 배열 오름차순 정렬

 

*예외처리

구분 설명
예외(Exception) 가벼운 오류이며 프로그램적으로 처리
오류(Error)  치명적인 오류이며 JVM에 의존하여 처리

-예외는 발생할 것을 미리 예측 가능 (불안정하게 프로그램이 종료되는 것을 방지 가능)

-오류는 예측이 불가능하여 발생하면 프로그램이 중단됨

-> 프로그래머가 집중해야할 것은 예외처리 (예외가 발생하더라도 프로그램이 안정적으로 동작할 수 있도록 설계)

 

-예외가 발생하면 예외 발생 지점에서 프로그램이 강제로 종료됨

-예외가 발생하면 예외 정보를 담고 있는 예외 객체가 생성되고 예외 문구가 콘솔에 출력됨

  (e.g. java.lang.ArrayIndexOutOfBoundsException)

 

*try-catch

-우리가 원하는 정보를 출력한 다음 프로그램을 안정적으로 종료할 수 있게 도와줌

public class ExceptionMain03 {
	public static void main(String[] args) {
		//예외처리
		try {
			System.out.println(args[0]);
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("입력한 데이터가 없습니다.");
		}

		System.out.println("프로그램 종료");
	}
}

 

-다중 catch 블럭

public class ExceptionMain03 {
	public static void main(String[] args) {
		int var = 50;
		//예외처리
		//다중 catch문
		//예외가 발생하면 예외객체가 전달되는 catch블럭으로 이동해서 수행문을 실행함
		try {
			int data = Integer.parseInt(args[0]);  //String -> int 변환
			System.out.println(var/data);
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("입력한 데이터가 없습니다.");
		} catch (NumberFormatException e) {
			System.out.println("숫자가 아닙니다.");
		}

		System.out.println("프로그램 종료");
	}
}

 

 

 

2024.03.06

 

-다중 catch문을 사용할 때 Exception과 하위 예외 클래스를 동시에 명시할 때

 하위 예외 클래스를 먼저 명시하고 가장 뒤에 Exception을 명시해야 동작상의 문제가 발생하지 않음

 

*멀티 catch

-하나의 catch 블럭에서 여러 개의 예외를 처리할 수 있도록 예상되는 예외클래스를 여러 개 명시하는 방식

		try {
			int value1 = Integer.parseInt(args[0]);
			int value2 = Integer.parseInt(args[1]);
			int result = value1 + value2;
			System.out.println(value1 + "+" + value2 + "=" + result);
		} catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
			System.out.println("실행 매개값의 수가 부족하거나 숫자를 변환할 수 없습니다.");
		} catch (Exception e) {
			System.out.println("알 수 없는 예외 발생");
		}

 

*finally

-예외가 발생하든 발행하지 않든 무조건 수행하는 부분

-Database처리나 File처리를 한다면 꼭 필요한 부분

  (Database를 열었다거나 또는 File을 열었다면 꼭 닫아주고 프로그램이 종료되어야 하기 때문)

-시스템에 부하를 줄 수 있는 부분을 주로 처리 (자원 정리)

 

-자바는 생성한 객체를 임의로 소멸시킬 수 없음 (가비지 콜렉터의 역할)
  -> 갑자기 예외가 발생해서 사용할 수 없는 객체를 작업을 못하게 만들어 메모리에 부하 발생을 줄임 (자원 정리)

       c.f close() 메서드

 

*throws

-메서드 안에서 예외처리(try~catch)를 하지 않고 예외를 보관하여 메서드가 호출된 곳으로 예외를 양도하는 방법

-메서드가 하나가 아닌 여러개일 때 여러개 메서드에서 모두 try~catch를 반복적으로 넣어야하는 문제를 해결해줌

-메서드명 뒤에 명시

package kr.s26.exception;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class ExceptionMain06 {

	public void printData() throws IOException, NumberFormatException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.print("단 입력: ");

		// String -> int
		int dan = Integer.parseInt(br.readLine()); // readline()은 한 라인에 입력한 데이터를 String으로 반환
		System.out.println(dan + "단");
		System.out.println("--------------");
		for (int i = 1; i <= 9; i++) {
			System.out.println(dan + "*" + i + "=" + dan * i);
		}
	}

	public static void main(String[] args) {
		ExceptionMain06 em = new ExceptionMain06();
		try {
			em.printData();

		} catch (IOException e) {
			System.out.println("입력시 오류 발생");
		} catch (NumberFormatException e) {
			System.out.println("숫자를 입력하세요");
		}
	}

}

 

 

*BufferedReader로 입력받기

-IOException을 무조건 예외처리 해주어야 함

 (※ IOException: 입출력 작업 중에 발생하는 예외,

                                   파일이 존재하지 않거나 파일에 접근할 수 없는 경우 등의 입출력 관련 오류 시 발생)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class ExceptionMain06 {

	public void printData() throws IOException, NumberFormatException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.print("단 입력: ");

 

*예외의 종류

-Exception 클래스와 그 자손들은 예외처리 필수(Checked 예외)

-RuntimeException 클래스와 그 자손들은 예외처리 선택(Unchecked 예외)

 

*throw 예외 던지기

-사용자(프로그래머)가 의도적으로 예외를 발생시킬 때 throw문을 사용해 인위적으로 예외를 발생시킴

package kr.s26.exception;

public class ExceptionMain07 {
	public void methodA(String[] n) throws Exception {
		if (n.length > 0) { // 데이터 입력한 경우
			for (String s : n) {
				System.out.println(s);
			}
		} else { // 데이터 입력 안한 경우
			// 예외를 인위적으로 발생시킴
			throw new Exception("배열에 요소가 없습니다.");
		}
	}
	
	public static void main(String[] args) {
		ExceptionMain07 em = new ExceptionMain07();
		try {
			em.methodA(args);
		} catch(Exception e) {
			// 예외 문구 출력
			// System.out.println(e.toString());
			System.out.println(e.getMessage());
		}
	}
}

 

-> 이 프로그램에서는 데이터를 입력 안 한 것을 예외로 보겠다!

 

*사용자 정의 예외클래스

-예외의 종류를 구분하기 위해 사용

-Exception 클래스를 상속받아 필요한 기능만 넣어서 만들 수 있음

class NegativeNumberUseException extends Exception {
	public NegativeNumberUseException(String str) { // 메세지를 넘겨주는 생성자만 정의
		super(str);
	}
}

 

public class ExceptionMain08 {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);

		System.out.print("0 이상의 정수 입력: ");
		try {
			int num = input.nextInt();
			if (num >= 0) {
				System.out.println("입력한 숫자 : " + num);
			} else {  // 음수 입력
				// 사용자 정의 예외 클래스에 예외 문구를 저장해서 객체로 생성해서 예외를 발생시킴
				throw new NegativeNumberUseException("음수를 사용할 수 없습니다.");
			}
		} catch (NegativeNumberUseException e) {
			System.out.println(e.getMessage());
		} catch (Exception e) {
			System.out.println("알 수 없는 예외 발생!");
		} finally {
			if (input != null) {
				input.close();
			}
		}

	}
}

 

 

*컬렉션(Java Collections Framework)

-데이터를 많이 저장할 수 있는 클래스들의 집합

-컬렉션 쪽은 인터페이스 형태로 값만 저장

-맵 쪽은 식별자(key)와 값(value) 같이 저장

 

*java.util.ArrayList (리스트)

-데이터를 1차원으로 늘어놓은 형태의 자료구조 (배열과 유사)

-배열과 달리 길이가 고정되어 있지 않음 => 가변길이

-데이터의 저장, 추가, 삭제, 변경이 모두 가능

-인터페이스

- (auto boxing) 기본 자료형은 자동으로 오토박싱됨 e.g. int -> Integer

-데이터 타입이 모두 달라서 Object 타입으로 저장됨

-일반적으로는 한가지 데이터타입을 선택해서 저장

 

*list 구조의 특징

-저장된 순서 유지

-중복 저장 허용

 

-실수로 다른 타입의 데이터를 저장하면 코드 실행시 다운캐스팅 과정에서 런타임에러 발생

 -> 제네릭 표현으로 해결

 

*제네릭 표현

-객체를 생성할 때 객체에 저장할 수 있는 요소의 타입을 지정

-제네릭 표현은 객체 타입만 허용

  e.g. int (x),  Integer (o) 

ArrayList<String> list = new ArrayList<String>();
list.add("장영실"); // String
list.add("홍길동"); // String
list.add(1000);     // Integer 에러

 

 

*요소의 추가

// 요소의 추가
list.add("홍길동");
list.add("김유신");
list.add("박문수");
list.add("장영실");
list.add("홍길동");

 

*요소의 삭제

-Integer 타입의 ArrayList에서 요소를 삭제할 때, 숫자를 그대로 넣으면 인덱스로 취급함

// 요소의 삭제

list.remove(2);  // 인덱스
list.remove("홍길동");  // 요소

list2.remove(2); // 인덱스
list2.remove(Integer.valueOf(40)); // 요소, int -> Integer

 

*요소의 변경

// 요소의 변경
// list명.set(인덱스, 데이터);
list2.set(1, 30);

 

-인덱스를 차례대로 검증하면서 삭제하고 싶을 때 인덱스 0부터 체크하여 삭제하면 놓치는 데이터가 발생할 수 있음

  -> 가장 마지막 인덱스부터 순회

// 짝수 삭제

//		for (int i = 0; i < list.size(); i++) {
//			if (list.get(i) % 2 == 0) {
//				list.remove(i);
//			}
//		}
		
		for (int i = list.size() - 1; i >= 0; i--) {
			if (list.get(i) % 2 == 0) {
				list.remove(i);
			}
		}

 

-indexOf()/lastIndexOf()

// 인덱스 탐색
int index1 = list.indexOf("사과");
System.out.println("첫번째 사과 : " + index1); //1

int index2 = list.lastIndexOf("사과");
System.out.println("마지막 사과 : " + index2); //4
	
// 망고가 존재하지 않으면 -1 반환
int index3 = list.indexOf("망고");
System.out.println("망고 : " + index3); //-1

 

-contains()

// ArrayList에 머루가 저장되어 있으면 true 반환, 없으면 false 반환
boolean f1 = list.contains("머루");
System.out.println("머루 : " + f1);
		
boolean f2 = list.contains("망고");
System.out.println("망고 : " + f2);

 

*정렬

-java.util.Collections 클래스 사용

// 정렬(사전 순서대로)
Collections.sort(list);

// 정렬(현재 순서의 역순으로)
Collections.reverse(list);

 

*java.util.Vector

-ArrayList와 마찬가지로 List 인터페이스를 구현했기 때문에 구조가 거의 동일

-ArrayList의 동작속도가 더 빠름

 

 

 

2024.03.07

 

*java.util.Stack

-후입선출 LIFO (Last-In First-Out)

-stk.push() :데이터 삽입

-stk.pop() :스택에 저장된 마지막 요소 반환하고 제거

-stk.isEmpty()

 

*큐(Queue)

-선입선출 FIFO(First-In First-Out)

-java.util.LinkedList를 이용해서 구현

-linked.offer() :데이터 삽입

-linked.peek() :큐에 저장된 첫번째 요소를 검색

-linked.poll() :큐에 저장된 첫번째 요소 반환하고 제거

 

*Set

-java.util.HashSet에서 Set 인터페이스를 구현해서 만듦

-중복값 불허(중복이면 저장을 하지 않음)

 

-java.util.Iterator를 이용해 데이터 검색

Iterator<String> ir = hs.iterator();
while(ir.hasNext()) {
	System.out.print(ir.next() + "  ");
}

 

-전통적으로는 이터레이터를 사용했으나 지금은 확장for문도 사용 가능

 

-Collections로 정렬하기 위해서 HashSet을 ArrayList 타입으로 형변환

//HashSet은 Collections를 이용해 sort 할 수 없어서 형변환
//HashSet -> Set -> Collection
List<Integer> list = new ArrayList<Integer>(hs);
//오름차순 정렬
Collections.sort(list);

 

*Map

-java.util.HashMap 사용

-key와 value의 쌍을 저장

-저장된 순서가 유지되지 않음

HashMap<String, Integer> map = new HashMap<String, Integer>();

 

-map.put(k, v) :데이터 저장

-map.get(k) :데이터 검색

-key를 중복해서 입력할 시 나중에 입력한 값으로 덮어씀

-key와 value에 null을 허용

 

-java.util.Iterator를 이용해 데이터 검색

 

-키값만 뽑아내기 (키를 통해서 밸류를 구하기 위해)

//키값을 뽑아내기 위해 HashMap -> Set -> Iterator
Set<Integer> s = map.keySet();
Iterator<Integer> keys = s.iterator();
while(keys.hasNext()) {
	Integer key = keys.next();
	System.out.println(key);
}

 

 

*java.util.Hashtable

-key를 중복해서 입력할 시 나중에 입력한 값으로 덮어씀

-key와 value에 null을 허용하지 않음

-hashmap과 거의 유사하고 가능한 hashmap을 사용하는 편이 좋음

 

-java.util.Enumeration 이용해 키값 뽑아낼 수 있음

 (Enumeration 인터페이스는 Iterator 인터페이스의 부모 클래스)

//Enumeration을 이용하여 key 구하기
Enumeration<String> en = h.keys();
while (en.hasMoreElements()) {
	System.out.println(en.nextElement());
}

 

 

 

2024.03.08

 

*multi catch문에서 에러 메세지 각각 지정하기

-instanceof 연산자 사용

} catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {

			if (e instanceof ArrayIndexOutOfBoundsException) {
				System.out.println("입력한 데이터가 없습니다.");
			} else if (e instanceof NumberFormatException) {
				System.out.println("숫자가 아닙니다.");
			}
}

 

 

*java.io.File

-절대경로: String path = "C:\\javaWork\\sample.txt";
-상대경로: String path = "sample.txt";

 

-f1.createNewFile(): 제공된 경로를 기반을 파일을 생성.

  파일이 생성되면 true 반환, 생성되지 않으면 false 반환. 경로가 잘못되면 IOException 발생 

public class FileMain02 {
	public static void main(String[] args) {
		//절대경로
		// String path = "C:\\javaWork\\sample.txt";

		//상대경로
		String path = "sample.txt";

		File f1 = new File(path);
		System.out.println("---------파일 생성---------");
		try {
			/*
			 * 제공된 경로를 기반을 파일을 생성.
			 * 파일이 생성되면 true 반환, 생성되지 않으면 false 반환
			 * 경로가 잘못되면 IOException 발생 
			 */
			System.out.println(f1.createNewFile());
		} catch (IOException e) {
			e.printStackTrace();
		}

		System.out.println("---파일 정보---");
		System.out.println("절대경로: " + f1.getAbsolutePath());
		System.out.println("상대경로: " + f1.getPath());
		System.out.println("디렉토리명: " + f1.getParent());
		System.out.println("파일명: " + f1.getName());
	}

}

 

-f1.renameTo(f2): 파일명을 변경할 수 있으면 변경하고 true를 반환, 불가능하면 false를 반환

인자에 파일명을 String으로 넣는게 아니라 File 객체를 생성해서 그걸 인자로 넣어줘야 함

public class FileMain03 {
	public static void main(String[] args) {
		//상대경로
		String path = "sample.txt"; //원래 파일명
		String new_path = "example.txt"; //새 파일명
		
		File f1 = new File(path);
		System.out.println("-----파일명 변경-----");
		File f2 = new File(new_path);
		//파일명을 변경할 수 있으면 변경하고 true 반환,
		//변경이 불가능하면 false 반환
		System.out.println(f1.renameTo(f2));
	}
}

 

-f1.delete(): 삭제할 수 있으면 삭제하고 true를 반환, 불가능하면 false를 반환

if (f1.delete()) {
	System.out.println(f1.getName() + " 파일 삭제");
} else {
	System.out.println("파일을 삭제하지 못했습니다.");
}

 

-f1.mkdir(): 새로운 디렉토리를 생성할 수 있으면 생성하고 true를 반환, 불가능하면 false를 반환

-f1.delete(): 디렉토리 삭제도 파일 삭제와 동일

 

 

*스트림

-데이터를 목적지로 입출력하기 위한 방법
-스트림에 데이터를 쓸 수 있고, 스트림에서 데이터를 읽을 수 있음
-출력 스트림(output stream): 스트림에 데이터를 쓸 경우
-입력 스트림(input stream): 스트림에서 데이터를 읽을 경우

 

-FIFO 구조

-스트림은 넣어진 데이터가 처리되기 전까지는 스트림에 사용되는 스레드는 지연상태에 빠짐

-IOException이 발생할 수 있어서 꼭 예외처리를 해주어야 함

 

*스트림의 분류

-용도에 의한 분류 
① 1차 스트림 : 디바이스에 직접 연결되는 스트림 
② 2차스트림 : 1차 스트림과 연결을 통해 디바이스에 연결되는 스트림

-전송 방향에 의한 분류 
① 입력 스트림 : 디바이스로부터 데이터를 읽어오는 스트림 
② 출력스트림 : 디바이스로 데이터를 출력하는 스트림 
-전송 단위에 의한 분류 
① 바이트스트림 : 1 Byte 단위로 입력, 출력하는 스트림 
② 문자스트림 : 한 문자(2 Byte) 단위로 입력, 출력하는 스트림

 

*바이트스트림(기본)

-한글을 처리할 때는 2바이트가 필요해서 바이트 배열로 처리해야 함

 

*java.io.InputStream

-추상클래스라서 직접 객체 생성 할 수 없음

  -> System.in 으로 InputStream을 반환해서 사용함

-System.in.read(): 문자 하나를 입력 받아서 아스키 코드로 반환(표준입력방법)

  -> char로 캐스팅해서 사용

 

-엔터키가 \r과 \n으로 구성되어 있어 엔터를 치면 \r\n이 전달되어 버림

 ->엔터 키를 read() 받아서 사용하지 않는 방법으로 처리

	public static void main(String[] args) {
		System.out.print("영문자 1개 입력: ");
		try {
			int a = System.in.read();
			System.out.println(a + ", " + (char) a);
			
			System.in.read(); //enter 처리(입력받고 사용하지 않기) \r 13
			System.in.read(); //enter 처리(입력받고 사용하지 않기) \n 10
			
			System.out.print("숫자 1개 입력: ");
			int b = System.in.read() - 48; //아스키코드로 반환된 것을 10진수로 변환
			System.out.println(b);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 

*InputStream으로 여러 문자 입력받기

-while문 이용

int input = 0;
try {
	//명시적으로 -1을 만들려면 ctrl+z
	while ((input = System.in.read())!=-1) {
		System.out.println(input + ", " + (char)input);
	}

-초기 input 값을 0으로 설정해두고 input이 -1이 될 때 while문을 빠져나오도록 설정

-명시적으로 -1을 받아오기 위해서는 콘솔창에 ctrl+z 입력

 

-Scanner는 JDK 5.0 이후에 도입됨

-범용적으로는 BufferedReader가 많이 사용됨

 

 

*java.io.FileInputStream

-파일의 정보를 한 문자씩 읽어 들여 아스키 코드로 반환

	public static void main(String[] args) {
		FileInputStream fis = null;
		int readbyte;
		try {
			fis = new FileInputStream("file.txt");
			//파일의 정보를 한 문자씩 읽어 들여 아스키 코드로 반환
			//영문 이외의 문자는 crash
			while ((readbyte = fis.read()) != -1) {
				System.out.print((char) readbyte);
			}
		} catch(FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			//자원정리
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {}
			}
		}
	}

 

-사운드나 그림, 동영상 등을 처리할 때 바이트스트림 사용

 

*byte 배열 이용하기 (한글 입력)

-파일명.available(): 파일의 바이트 수를 읽어옴

 -> 바이트 배열의 사이즈 설정 가능

-파일명.read(바이트배열): 파일로부터 읽어 들인 데이터를 byte[]에 저장

byte[] readbyte2;
    try {
			fis = new FileInputStream("file.txt");
			
			//영문 이외의 문자도 처리 가능
			readbyte2 = new byte[fis.available()];
			//파일로부터 읽어 들인 데이터를 byte[]에 저장
			fis.read(readbyte2);
							   // byte[] -> String
			System.out.println(new String(readbyte2));
			
			
		}

 

 

*java.io.FileOutputStream

-파일로 출력하기

-String을 getBytes() 메서드 사용하여 바이트 배열로 만들고 파일명.write(바이트배) 메서드 사용하여 파일에 데이터 기록

//파일 생성
fos = new FileOutputStream("fileout.txt");
	
String message = "Hello File! 파일에 내용 기술 ...";
			
//파일에 데이터 기록
          // String -> byte[]
fos.write(message.getBytes());

 

*파일 생성모드 (2)

1) 덮어쓰기

//덮어쓰기
fos = new FileOutputStream("fileout.txt");

2) 이어쓰기

-두번째 인자를 true로 설정 (기본값은 false로 덮어쓰기 모드임)

//이어쓰기
fos = new FileOutputStream("fileout.txt", true);

 

*java.io.BufferedOutputStream: 버퍼 사용해서 파일로 출력

-계란을 판에 담아서 한번에 옮기는 방법

 (<->FileOutputStream은 계란을 하나하나 옮기는 방법)

-데이터량이 많을 경우 더 효율적인 방법

-버퍼를 활용해서 일정량을 메모리 공간에 담은 다음 그 일정량 단위로 파일에 flush

 

-FileOutputStream으로 파일을 생성한 다음 생성한 파일을 BufferedOutputStream에 넘겨줌

-write()를 통해 버퍼에 데이터를 담은  flush()를 해서 버퍼를 비우고 버퍼에 있는 데이터를 파일에 출력해주어야 함.

-flush()하지 않으면 버퍼에 담겨있는 데이터를 파일에 저장하지 않음

-BOS의 close() 메서드가 실행되면 버퍼를 최종적으로 검사해주어 버퍼에 남은 데이터가 있으면 자동적으로 flush()가 수행됨

-자원정리를 할때는 BOS를 먼저 정리하고 FOS를 정리해서 에러를 방지

 

 

*문자 입력 스트림

-입력 클래스에는 이름에 모두 Reader가 붙어있고 출력 클래스에는 모두 Writer가 붙어 있음

 

-System.in으로 받아온 스탠다드 인풋을 InputStreamReader에서 2바이트 문자로 반환함.

  그걸 BufferedReader가 라인 바이 라인으로 받아옴.

(즉, 표준 입력-1바이트(System.in) -> 문자스트림(InputStreamReader)으로 가공

         -> 메서드로 라인바이라인으로 읽어옴(BufferedReader)

br = new BufferedReader(new InputStreamReader(System.in));

 

-문자 출력 스트림은 거의 사용하지 않음

 

*java.io.FileReader

-파일로부터 데이터를 한 문자씩 읽어들여 유니코드로 반환

fr = new FileReader("file.txt");
//파일로부터 데이터를 한 문자씩 읽어들여 유니코드로 반환
while ((readChar = fr.read()) != -1) {
	System.out.print((char) readChar);
}

 

*java.io.FileWriter

-FileOutputStream과 달리 버퍼 기능을 가지고 있음

-write() 메서드는 버퍼에 출력을 하는 기능

-flush()를 명시해야 함

 

*toString() 메서드 오버라이딩

-데이터를 읽어오는 코드를 줄일 수 있음

 

*문자열 포맷하기

-String.format("포맷 스트링", arguments)

-printf()와 동일