java.util 패키지
유용한 클래스들을 많이 가지고 있는 패키지
- Date, Calendar 클래스: 날짜와 관련
- Date클래스는 지역화를 지원하지 않음
- 지역화(Localization): 국가별로 현재 날짜와 시간은 다를 수 있음
- 이런 문제를 해결하기 위하여 나온 클래스가 Calendar클래스(Java 1.1에 등장)
- 지역화와 관련된 클래스들은 Locale로 시작되는 이름을 가진 클래스들( Java 1.1 이후에 등장)
- Locale, Locale.Builder, Locale.LanguageRange
- Date클래스는 지역화를 지원하지 않음
- Collection, Set, List, Map 인터페이스: 자료구조 즉, 컬렉션 프레임워크와 관련된 인터페이스
- Java API에서 deprecated: 더이상 지원하지 않는 기능이니 사용하지 않는 것이 좋다는 의미
컬렉션 프레임워크
java.util 패키지에는 자료를 다룰 수 있는 자료구조 클래스가 다수 존재함
자료구조 클래스들 = 컬렉션 프레임워크
- 자료구조: 자료를 저장할 수 있는 구조
컬렉션 프레임워크(collection framework)
- 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합
- 데이터를 저장하는 자료 구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현한 것
- Java의 인터페이스(interface)를 사용하여 구현됨
- 주요 인터페이스
- List 인터페이스
- Set 인터페이스
- Map 인터페이스
주요 인터페이스 간의 상속 관계
- <E>나 <K, V>라는 것은 컬렉션 프레임워크를 구성하는 모든 클래스가 제네릭으로 표현되어 있음을 알려줌
Collection인터페이스 - 중복 O, 순서 X
- 컬렉션 프레임워크에서 가장 기본적인 동작들을 정의하고, 그것을 메소드로 제공
- ‘여기에 자료가 있다’라는 것을 표현
- 중복도 허용하고, 자료가 저장된 순서도 기억하지 못함
- List와 Set 인터페이스의 많은 공통된 부분을 Collection인터페이스에서 정의하고, 두 인터페이스는 그것을 상속받음
- Collection인터페이스의 메소드
- Collection이 가지고 있는 대표적인 메소드는 add( ), size( ), Iterator( ) 메소드
메소드 | 설명 |
boolean add(E e) | 해당 컬렉션(collection)에 전달된 요소를 추가 (선택적 기능) |
int size( ) | 해당 컬렉션 요소의 총 개수를 반환 |
Iterator<E> iterator( ) | 자료를 하나씩 꺼내기 위한 iterator 인터페이스를 반환 |
void clear( ) | 해당 컬렉션의 모든 요소를 제거 (선택적 기능) |
boolean contains(Object o) | 해당 컬렉션이 전달된 객체를 포함하고 있는지를 확인 |
boolean equals(Object o) | 해당 컬렉션과 전달된 객체가 같은지를 확인 |
boolean isEmpty() | 해당 컬렉션이 비어있는지를 확인 |
boolean remove(Object o) | 해당 컬렉션에서 전달된 객체를 제거 (선택적 기능) |
Object[] toArray( ) | 해당 컬렉션의 모든 요소를 Object 타입의 배열로 반환 |
- 저장된 순서를 기억하지 못하기 때문에 "첫 번째 자료를 달라, 두 번째 자료를 달라"와 같은 기능을 가질 수 없음
- 대신, 저장된 자료를 하나씩 꺼낼 수 있는 Iterator라는 인터페이스를 반환
- Iterator 인터페이스의 메소드
- hasNext( )메소드: 꺼낼 것이 있는지 없는지 살펴봄
- next( )메소드: 하나씩 자료를 꺼낼 때 사용
- Iterator 인터페이스의 메소드
Set인터페이스: Set<E> - 중복 X, 순서 X
- Collection인터페이스를 상속받음
- 순서를 기억하지 못하지만, 중복은 허용하지 않는 자료구조
- add(Object) 메소드: 같은 자료가 있으면 false, 없으면 true를 반환 (중복을 허용하지 않는 Set의 속성)
- 구현 클래스: HashSet, TreeSet
List인터페이스: List<E> - 중복 O, 순서 O
- Set인터페이스와 마찬가지로, Collection인터페이스를 상속받음
- 순서는 기억하지만, 중복은 허용하는 자료구조
- get(int) 메소드: 0번째, 1번째, …, n번째의 자료를 꺼낼 수 있음 (순서를 기억하는 List의 속성)
- 구현 클래스: Vector, ArrayList, LinkedList, Stack, Queue
Map인터페이스: Map<K, V> - Key중복 X, Value중복 O, 순서 X
- Key와 Value의 한 쌍으로 이루어지는 자료구조
- put(Object, Object) 메소드를 이용해 key와 value를 함께 저장
- key를 매개변수로 받아들이는 get(Object) 메소드를 이용해 원하는 값을 꺼냄
- 순서를 기억하지 못함
- Key엔 중복을 허용하지 않지만, Value는 중복될 수 있음
- keySet( ) 메소드: 자신이 가지고 있는 모든 Key들에 대한 정보를 읽어들일 수 있는 Set을 반환(Key의 중복을 허용하지 않는 Map의 속성)
- 구현 클래스: HashMap, TreeMap, Hashtable, Properties
컬렉션 클래스(collection class)
- 컬렉션 프레임워크에 속하는 인터페이스를 구현한 클래스
- 컬렉션 프레임워크의 모든 컬렉션 클래스는 List와 Set, Map 인터페이스 중 하나의 인터페이스를 구현
- 클래스 이름에도 구현한 인터페이스의 이름이 포함되므로 바로 구분할 수 있음
- Vector나 Hashtable과 같은 컬렉션 클래스는 예전부터 사용해 왔으므로, 기존 코드와의 호환을 위해 아직도 남아 있음
- But, 기존에 사용하던 컬렉션 클래스를 사용하는 것보다는 새로 추가된 ArrayList나 HashMap 클래스를 사용하는 것이 성능 면에서도 더 나은 결과를 얻을 수 있음
Generic
Box 클래스
public class Box {
private Object obj; //필드의 데이터타입: Object 클래스
public void setObj(Object obj){ //필드의 값을 설정하는 메소드
this.obj = obj; //필드와 매개변수의 이름이 같으니 this 사용
}
public Object getObj(){ //필드의 값을 반환하는 메소드
return obj;
}
}
BoxExam 클래스
public class BoxExam {
public static void main(String[] args) {
Box box = new Box();
box.setObj(new Object()); //setObj 메소드에 매개변수로 Object 객체를 생성해 넣어줌
Object obj = box.getObj(); //참조변수 box가 가지고 있는 Object 클래스를 리턴해줌
box.setObj("hello"); //box에 String 값을 넣을 수도 있음
//box에 값을 넣을 때 Object 타입을 썼으니, box에서 값을 꺼내서 사용할 떄도 리턴타입이 Object
String str = (String)box.getObj(); //Object를 String으로 다운캐스팅하는 거니까 명시해줘야 함
System.out.println(str);
box.setObj(1); //box에 int 값을 넣을 수도 있음
int value = (int)box.getObj();
System.out.println(value);
}
}
- Box는 매개변수로 Object를 하나 받아들이고(setObj 메소드), Object를 반환(getObj 메소드)
- 매개변수로 Object를 받아들일 수 있다는 것은 Object의 후손(String, int 등)이라면 무엇이든 받아들일 수 있다는 것
- box에 값을 넣을 때 Object 타입을 썼으니, box에서 값을 꺼내서 사용할 떄도 리턴타입이 Object
- Object를 String으로 다운캐스팅하는 거니까 명시해줘야 함
- String str = (String)box.getObj( );
- Object를 String으로 다운캐스팅하는 거니까 명시해줘야 함
Java 5에는 Generic이라는 문법이 사용됨으로써 인스턴스를 만들 때 사용하는 데이터타입을 지정하는 문법이 추가
- Java 5 이전에는 여러 타입을 사용하는 대부분의 클래스/메소드에서 인수나 리턴값으로 Object 타입을 사용해 모든 데이터타입의 객체가 들어갈 수 있음
- But, 꺼내서 사용할 때 반환된 Object 객체를 다시 원하는 타입으로 타입 변환해야 하며, 이때 오류가 발생할 가능성도 존재
- Java 5부터 도입된 제네릭을 사용하면 컴파일 시에 미리 타입이 정해지므로, 타입 검사나 타입 변환과 같은 번거로운 작업을 생략할 수 있음
Generic을 이용하여 수정한, Box 클래스
public class Box<E> {
private E obj;
public void setObj(E obj){
this.obj = obj;
}
public E getObj(){
return obj;
}
}
- 클래스 이름 뒤에 <E>가 제네릭을 적용한 것
- Box는 가상의 클래스 E를 사용한다는 의미
- 꼭 E여야 할 필요는 없음
- Object를 받아들이고 리턴하던 부분이 E로 변경. E는 실제로 존재하는 클래스는 아님.
Generic을 이용하여 수정한, Box를 이용하는 BoxExam클래스
public class BoxExam {
public static void main(String[] args) {
Box<Object> box = new Box<>();
box.setObj(new Object());
Object obj = box.getObj();
Box<String> box2 = new Box<>();
box2.setObj("hello");
String str = box2.getObj();
System.out.println(str);
Box<Integer> box3 = new Box<>();
box3.setObj(1);
int value = box3.getObj();
System.out.println(value);
}
}
- 참조타입에 <Object> , <String>, <Integer>가 있는 것을 볼 수 있음
- 첫번째는 Object를 사용하는 Box 인스턴스를 만들겠다는 의미
- 두번째는 String을 사용하는 Box 인스턴스를 만들겠다는 의미
- 세번째는 Integer를 사용하는 Box 인스턴스를 만들겠다는 의미
Generic을 사용함으로써 가상의 타입으로 선언하고, 사용 시에는 구체적인 타입을 설정함으로써 다양한 타입의 클래스를 이용하는 클래스를 만들 수 있음
Generic을 사용하는 대표적인 클래스는 컬렉션 프레임워크와 관련된 클래스
- Set, List, Map 인터페이스의 컬렉션 클래스
제네릭(Generic)
- 데이터의 타입(data type)을 일반화한다(generalize)는 의미
- 클래스나 메소드에서 사용할 내부 데이터 타입을 클래스 외부에서 사용자의 필요에 의해 컴파일 시 미리 지정하는 방법 (컴파일 시 미리 타입 검사(type check) 수행)
- 제네릭의 장점
- 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있음 (잘못된 타입이 들어오는 걸 컴파일 단계에서 방지)
- 클래스 외부에서 타입을 지정해주기 때문에 반환값에 대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있음 (관리가 편함)
- 비슷한 기능을 지원하는 경우 코드의 재사용성이 높아짐
- 제네릭의 타입
타입 설명 <T> Type <E> Element <K> Key <V> Value <N> Number <?> 모든 타입 가능
(= <? extends Object>)- 반드시 한 글자일 필요도, 설명과 반드시 일치해야 할 필요도 없음 (예: <Ele>도 가능)
- But, 대체로 위와 같이 사용
제네릭의 선언
- 클래스 뒤에 <타입>을 적고, 타입이 들어가는 자리에 꺽쇠 안에 들어간 타입을 적어주면 됨
class MyArray<T> {
T element;
void setElement(T element){
this.element = element;
}
T getElement(){
return element;
}
}
- 예제의 'T'를 타입 변수(type variable)라고 하며, 임의의 참조형 타입을 의미
- 꼭 'T'뿐만 아니라 어떠한 문자를 사용해도 상관없으며, 여러 개의 타입 변수는 쉼표(,)로 구분하여 명시할 수 있음
- 타입 변수는 클래스에서뿐만 아니라 메소드의 매개변수나 반환값으로도 사용할 수 있음
제네릭의 생성
- 타입 변수 자리에 사용할 실제 타입을 명시해야 함
- 타입 변수 자리에 사용할 실제 타입을 명시할 때 기본 타입을 바로 사용할 수는 없음 Integer와 같이 래퍼(wrapper) 클래스를 사용해야 함
- 내부적으로는 정의된 타입 변수가 명시된 실제 타입으로 변환되어 처리됨
MyArray<Integer> myArr = new MyArray<Integer>();
- Java 7부터 인스턴스 생성 시 타입을 추정할 수 있는 경우에는 타입을 생략할 수 있음
MyArray<Integer> myArr = new MyArray<>();
제네릭의 사용
- 메소드의 인자로는 제네릭을 생성할 때 지정한 데이터타입의 값을 넣어줘야 함
public class Box<E> {
private E obj;
public void setObj(E obj){
this.obj = obj;
}
public E getObj(){
return obj;
}
}
public class BoxExam {
public static void main(String[] args) {
Box<Object> box = new Box<>();
box.setObj(new Object());
Object obj = box.getObj();
Box<String> box2 = new Box<>();
box2.setObj("hello");
String str = box2.getObj();
System.out.println(str);
Box<Integer> box3 = new Box<>();
//Integer라고 선언했는데 int 값이 들어가는 이유
//오토박싱과 오토언박싱이 적용되어
//자동으로 int로 바꿔서 넣어주고 자동으로 int로 바꿔서 꺼내주기 때문
box3.setObj(1);
int value = box3.getObj();
System.out.println(value);
}
}
- 아래 코드에서 Integer라고 선언했는데 int 값이 들어가는 이유
Box<Integer> box3 = new Box<>();
box3.setObj(1);
- 오토박싱과 오토언박싱이 적용되어 자동으로 int로 바꿔서 넣어주고 자동으로 int로 바꿔서 꺼내주기 때문
Set
중복이 없고, 순서도 없는 자료구조
- 구현 클래스: Hashset과 TreeSet
- Set 인터페이스를 구현하는 HashSet을 인스턴스로 만드는 예제
- Set, HashSet, Iterator를 사용할 때마다 import해야 함(Ctrl+Space로 자동완성해도 됨)
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetExam {
public static void main(String[] args) {
//제네릭을 이용해 String만 다루도록 지정
//Set은 인터페이스라 객체 생성 불가능 > Set을 구현한 클래스인 HashSet으로 객체 생성
Set<String> set1 = new HashSet<>();
//Set의 메소드 add는 값을 저장할 때마다 boolean값을 반환
//Set은 중복이 불가능하기 때문에 같은 값을 넣으면 add 메소드는 false를 반환
boolean flag1 = set1.add("kim");
boolean flag2 = set1.add("lee");
boolean flag3 = set1.add("kim");
//저장된 크기를 출력. 3개를 저장했지만, 이미 같은 값이 있었기 때문에 2개가 출력
System.out.println(set1.size());
System.out.println(flag1); //true
System.out.println(flag2); //true
System.out.println(flag3); //false
//값을 하나씩 꺼내보기 위해서는* Set의 부모클래스인 Collection이 갖고 있는 Iterator 인터페이스를 이용
Iterator<String> iter = set1.iterator();
while (iter.hasNext()) { // 꺼낼 것이 있다면 true 리턴
// next()메소드는 하나를 꺼냄. 하나를 꺼내면 자동으로 다음 것을 참조.
String str = iter.next();
System.out.println(str);
}
}
}
- 결과
- 2
true
true
false
kang
kim
- 2
- Set의 메소드 add는 값을 저장할 때마다 boolean값을 반환
- Set은 중복이 불가능하기 때문에 같은 값을 넣으면 add 메소드는 false를 반환
boolean flag1 = set1.add("kim");
System.out.println(flag1); *//true*
- Set 자료구조에 들어있는 값들을 하나씩 꺼내보기 위해서는 Set의 부모클래스인 Collection이 갖고 있는 Iterator 인터페이스를 이용해야 함
- Set 인터페이스는 Collection 인터페이스를 상속받는데, Collection 인터페이스의 iterator 메소드도 사용할 수 있게 됨
Iterator<String> iter = set1.iterator();
- Iterator 인터페이스가 갖고 있는 hasNext( )메소드 활용
- hasNext( ): 꺼낼 것이 있는지 없는지 살펴보고 있으면 true, 없으면 false 리턴
- 값을 꺼낼 때 index가 필요하진 않기 때문에 간단하게 while문 사용
- Iterator 인터페이스가 갖고 있는 hasNext( )메소드 활용
- next( ): 하나를 꺼내고 나면, 자동으로 다음 것을 참조.
while (iter.hasNext()) { *// 꺼낼 것이 있다면 true 리턴*
String str = iter.next();
** System.out.println(str);
}
실습 1
- 문제 설명
- 다음 코드는 set에 a를 두 번 더하고, b를 한 번 더합니다. 출력해 보면 a와 b가 각각 한 번씩만 출력되는데요. set은 이미 있는 값이면 값을 더해도 2개가 아니라 하나의 값만 유지하기 때문입니다. [제출]을 눌러서 출력을 확인해 보세요.
- 참고: set의 내용은 for each문 또는 Iterator를 활용해서 출력할 수 있습니다. for each문을 복습하려면 이 링크를 참고하세요.
- SetExam 클래스
import java.util.*;
public class SetExam{
public static void main(String[] args){
Set<String> set = new HashSet<String>();
set.add("a");
set.add("a");
set.add("b");
System.out.println("set의 내용을 출력합니다.");
for(String str : set){
System.out.println(str);
}
}
}
실습 2
- 문제 설명
- Iterator iter의 hasNext와 next메소드를 이용해서 set의 내용을 모두 출력해 보세요.
- SetExam 클래스
import java.util.*;
public class SetExam{
public static void main(String[] args){
Set<String> set = new HashSet<String>();
set.add("a");
set.add("b");
Iterator<String> iter = set.iterator();
//iter를 이용해서 set의 내용을 출력하세요.
while(iter.hasNext()){
String str = iter.next();
System.out.println(str);
}
}
}
List
데이터의 중복이 있을 수 있고, 순서도 있음
- 구현 클래스: Vector, ArrayList, LinkedList, Stack, Queue
- 리스트와 배열
- 공통점: 자료구조임
- 차이점
- 리스트: 저장공간이 필요에 따라 자유롭게 늘어남 > 길이를 알 수 없는 배열을 더할 때 유용
- 배열: 한 번 생성하면 크기 변경 불가
- List 인터페이스를 구현하는 ArrayList 클래스 예제
import java.util.ArrayList;
import java.util.List;
public class ListExam {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// list에 3개의 문자열을 저장
list.add("kim");
list.add("lee");
list.add("kim");
//list에 저장된 자료의 수를 출력 (중복을 허용하므로 3 출력)
System.out.println(list.size());
for(int i = 0; i < list.size(); i++){
String str = list.get(i);
System.out.println(str);
}
}
}
- List는 순서가 있는 자료구조이기 때문에 index를 활용하는 for문 사용 가능
- List에서 값을 꺼낼 땐 get( ) 메소드 사용
- get(int) 메소드: 0번째, 1번째, …, n번째의 자료를 꺼낼 수 있음
- 결과
- 3
kim
kang
kim
- 3
실습
- 문제 설명
- List는 길이가 정해져 있지 않기 때문에 길이를 알 수 없는 배열을 더할때 유용하게 사용할 수 있습니다. 다음 코드의 addArray는 매개변수로 두개의 String배열을 받고 있는데요. arr1과 arr2의 각 값을 순서대로 list에 저장해서 return하도록 만들어 보세요.
- ListExam 클래스
import java.util.*;
public class ListExam{
public List<String> addArray(String[]arr1, String[]arr2){
List<String> list = new ArrayList<String>();
for(String str : arr1){
System.out.println(list.add(str));
}
for(String str : arr2){
System.out.println(list.add(str));
}
return list;
}
public static void main(String[] args){
}
}
Map
key와 value를 쌍으로 저장하는 자료구조
- put( ) 메소드: Map에 값을 추가
- get(Object) 메소드: key를 매개변수로 받아들여 원하는 값을 꺼냄
- keySet( ) 메소드: 자신이 가지고 있는 모든 Key들에 대한 정보를 읽어들일 수 있는 Set을 반환
- Set을 모두 꺼내기 위해 Iterator 인터페이스 사용
- 구현 클래스: HashMap, TreeMap, Hashtable, Properties
key는 중복될 수 없고, value은 중복될 수 있음
- Map 인터페이스를 구현하는 HashMap 클래스 예제
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapExam {
public static void main(String[] args) {
//Key, Value가 모두 String 타입인 HashMap인스턴스를 만듦
Map<String, String> map = new HashMap<>();
//key와 value값을 put으로 저장
map.put("001", "kim");
map.put("002", "lee");
map.put("003", "choi");
//같은 key가 2개 존재할 수 없음. 첫 번째로 저장했던 001, kim은 001, kang으로 바뀜
map.put("001", "kang");
//map에 저장된 자료의 수를 출력 - 3이 출력됨
System.out.println(map.size());
//키가 001, 002, 003인 값을 꺼내 출력
System.out.println(map.get("001"));
System.out.println(map.get("002"));
System.out.println(map.get("003"));
// map에 저장된 모든 key들을 Set자료구조로 꺼냄
Set<String> keys = map.keySet();
// Set자료구조에 있는 모든 key를 꺼내기 위하여 Iterator를 구함
Iterator<String> iter = keys.iterator();
while (iter.hasNext()) {
// key를 꺼냄
String key = iter.next();
//key에 해당하는 value를 꺼냄
String value = map.get(key);
//key와 value를 출력
System.out.println(key + " : " + value);
}
}
}
- Map 인터페이스에서 key 값은 중복될 수 없음
- 나중에 들어온 값이 원래 있던 값을 대체함
- Map에 값을 추가하기 위해서는 put( ) 메소드 사용
- 원하는 값을 꺼내기 위해서는 key를 매개변수로 받아들이는 get(Object) 메소드 사용
map.put("001", "kim");
map.put("002", "lee");
map.put("003", "choi");
**map.put("001", "kang");
System.out.println(map.size()); //3
System.out.println(map.get("001")); //kang
- keySet( ) 메소드: 자신이 가지고 있는 모든 Key들에 대한 정보를 읽어들일 수 있는 Set을 반환
Set<String> keys = map.keySet();
- Set을 모두 꺼낼 때 사용하는 Iterator 인터페이스 사용
Iterator<String> iter = keys.iterator();
while (iter.hasNext()) {
*// key를 꺼냄*
String key = iter.next();
*//key에 해당하는 value를 꺼냄*
String value = map.get(key);
*//key와 value를 출력*
System.out.println(key + " : " + value);
}
실습
- 문제 설명
- products는 상품의 이름을 key로 가격을 값으로 가지는 Map입니다. "가위"는 2500원, "크레파스"는 5000원이 되도록 products에 값을 추가해 보세요.
- MapExam 클래스
import java.util.*;
public class MapExam{
public Map<String, Integer> makeMap(){
Map<String, Integer> products = new HashMap<>();
//상품의 이름과 값을 products에 추가해 보세요.
products.put("가위", 2500);
products.put("크레파스", 5000);
return products;
}
public static void main(String[] args){
}
}
'☕ Java 웹 프로그래밍 > Java' 카테고리의 다른 글
[프로그래머스] Java(자바) 중급 | Part 5. IO (0) | 2023.05.15 |
---|---|
[프로그래머스] Java(자바) 중급 | Part 4. 날짜와 시간 (2) | 2023.05.13 |
[프로그래머스] Java(자바) 중급 | Part 2. java.lang 패키지 (0) | 2023.05.11 |
[프로그래머스] Java(자바) 중급 | Part 1. Object 클래스 (0) | 2023.05.10 |
[프로그래머스] Java(자바) 입문 | Part 10. 연습문제 (약수의 합) (0) | 2023.05.10 |