사용자 도구

사이트 도구


study:java:javachobo:appendix

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판 이전 판
다음 판
이전 판
study:java:javachobo:appendix [2010/03/19 20:52]
gauryan
study:java:javachobo:appendix [2010/03/21 14:48] (현재)
gauryan
줄 1: 줄 1:
 ====== JDK 1.5에 추가된 기능 ====== ====== JDK 1.5에 추가된 기능 ======
 +
 +===== StringBuilder =====
 +StringBuilder 가 새로 추가되었다. StringBuilder 는 StringBuffer 와 완전히 동일한 클래스이다. 다만 동기화(synchronization)처리를 하지 않기 때문에 멀티쓰레드 프로그래밍에서는 사용하면 안 되지만 멀티쓰레드 프로그래밍이 아닌 경우에는 StringBuffer 보다 바른 성능을 보장한다.
 +동기화의 여부를 제외하고 두 클래스가 기능상으로 완전히 동일하기 때문에 코드에서 StringBuffer 를 StringBuilder 로 바꾸기만 하면 된다. 즉, StringBuffer 타입의 참조변수를 선언한 부분과 StringBuffer 의 생성자만 바꾸면 된다는 말이다.
 +<code java>
 +StringBuffer sb;
 +sb = new StringBuffer();
 +sb.append("abc");
 +</code>
 +<code java>
 +StringBuilder sb;
 +sb = new StringBuilder();
 +sb.append("abc");
 +</code>
 +StringBuffer도 충분히 성능이 좋기 때문에 성능향상이 반드시 필요한 경우를 제외하고는 기존에 작성한 코드에서 StringBuffer를 StringBuilder로 굳이 바꿀 필요는 없을 것이다.
 +
 +===== 오토박싱(autoboxing) =====
 +컬렉션에는 객체로 저장해야하기 때문에 기본형 값을 저장하기 위해서는 Integer나 Long과 같은 Wrapper클래스를 사용해야했다. 그러나 이제부터는 기본형 값을 직접 컬렉션에 저장할 수 있다. 컴파일러에 의해서 자동적으로 Wrapper클래스로 변환되어 저장되는 데 이것을 오토박싱(autoboxing)이라고 한다. 뿐만아니라 저장된 값을 꺼낼 때도 변환과정을 거치지 않고도 기본형 형태의 값을 바로 얻을 수 있는 데 이것을 언박싱(unboxing)이라고 한다.
 +<code java>
 +ArrayList list = new ArrayList();
 +list.add(new Integer(10));
 +list.add(new Integer(20));
 +list.add(new Integer(30));
 +
 +Integer i = (Integer)list.get(0);
 +int value = i.intValue();
 +</code>
 +이전에는 위와 같은 코드를 사용했지만 이제는 아래와 같이 코드를 간략히 할 수 있다.
 +<code java>
 +ArrayList<Integer> list = new ArrayList<Integer>();
 +list.add(10); // 오토박싱(autoboxing)
 +list.add(20); // 오토박싱(autoboxing)
 +list.add(30); // 오토박싱(autoboxing)
 +
 +int value = list.get(0); // 언박싱(unboxing)
 +</code>
 +
 +===== 향상된 for 문 =====
 +배열과 컬렉션에 저장된 요소에 접근할 때 기존보다 편리한 방법으로 처리할 수 있도록 for문의 새로운 문법이 추가되었다.
 +<code java>
 +1. 배열
 +    for( 배열의 타입 변수명 : 배열 ) {
 +        // 반복할 문장
 +    }
 +    
 +2. 컬렉션
 +    for( 컬렉션에 저장된 요소의 타입 변수명 : 컬렉션 ) {
 +        // 반복할 문장
 +    }
 +</code>
 +
 +먼저, 정수형 배열이 다음과 같이 선언되어 있다고 가정하자.
 +<code java>
 +int[] arr = {10, 20, 30, 40, 50};
 +</code>
 +
 +아래의 두 for 문은 서로 동일하다.
 +<code java>
 +for(int i=0 ; i < arr.length ; i++) {
 +    System.out.println(arr[i]);
 +}
 +</code>
 +<code java>
 +for(int i : arr) {
 +    // arr[i]가 아닌 i라는 것에 유의
 +    System.out.println(i);
 +}
 +</code>
 +
 +이번엔 ArrayList를 생성하고 다음과 같이 세 개의 Integer객체를 저장하고 각 요소에 접근하기 위해 Iterator를 얻었다.
 +<code java>
 +ArrayList<Integer> list = new ArrayList<Ingeger>();
 +list.add(new Ingerger(10));
 +list.add(new Ingerger(20));
 +list.add(new Ingerger(30));
 +
 +Iterator it = list.iterator();
 +</code>
 +
 +<code java>
 +for(;it.hasNext();) {
 +    System.out.println(it.next());
 +}
 +</code>
 +<code java>
 +for(Integer i : list) {
 +    System.out.println(i);
 +}
 +</code>
 +향상된 for 문은 배열보다는 컬렉션에 저장된 요소에 접근할 때 더욱 코드가 간결해진다는 것을 알 수 있다. 한 가지 주의해야할 점은 향상된 for 문내에서 삭제와 같이 컬렉션을 변경하는 동작을 해서는 안 된다는 것이다.
  
 ===== 제네릭스(Generics) ===== ===== 제네릭스(Generics) =====
줄 75: 줄 165:
 } }
 </code> </code>
-위와 같이 선언된 메서드가 있을 때, 이 메서드의 매개변수로는 Array<Unit>타입의 변수만 사용할 수 있다. 즉, ArrayList<Unit> list = new ArrayList<Unit>();으로 생성된 객체만 매개변수로 사용될 수 있다는 뜻이다.+위와 같이 선언된 메서드가 있을 때, 이 메서드의 매개변수로는 ArrayList<Unit>타입의 변수만 사용할 수 있다. 즉, ArrayList<Unit> list = new ArrayList<Unit>();으로 생성된 객체만 매개변수로 사용될 수 있다는 뜻이다.
  
 <code java> <code java>
줄 95: 줄 185:
 </code> </code>
 <code java> <code java>
-public static <T extends Unit> printAll(ArrayList<T> list, ArrayList<T> list2) {+public static <T extends Unit> void printAll(ArrayList<T> list, ArrayList<T> list2) {
     for(Unit u : list) {     for(Unit u : list) {
         System.out.println(u);         System.out.println(u);
줄 103: 줄 193:
 **[주의]** 여기서 만일 Unit이 클래스가 아닌 인터페이스라 할지라도 키워드로 'implements'를 사용하지 않고 클래스와 동일하게 'extends'를 사용한다는 것에 주의하자. **[주의]** 여기서 만일 Unit이 클래스가 아닌 인터페이스라 할지라도 키워드로 'implements'를 사용하지 않고 클래스와 동일하게 'extends'를 사용한다는 것에 주의하자.
  
-예제 : /GenericsEx1.java +  * 예제 : /GenericsEx1.java <code java>
-<code java>+
 import java.util.*; import java.util.*;
  
 class Unit() {} class Unit() {}
 +class Tank extends Unit {}
 +class Dropship extends Unit {}
 +
 +class GenericsEx1 {
 +    public static void main(String[] args) {
 +        ArrayList<Unit> unitList = new ArrayList<Unit>();
 +        ArrayList<Tank> tankList = new ArrayList<Tank>();
 +        
 +        unitList.add(new Tank());
 +        unitList.add(new Dropship());
 +        
 +        tankList.add(new Tank());
 +        tankList.add(new Tank());
 +        
 +        printAll(unitList);
 +//      printAll(tankList);  // 컴파일 에러가 발생한다.
 +
 +        printAll2(unitList);
 +        printAll2(tankList);
 +    }
 +    
 +    public static void printAll(ArrayList<Unit> list) {
 +        for( Unit u : list ) {
 +            System.out.println(u);
 +        }
 +    }
 +    
 +//  public static void printAll2(ArrayList<? extends Unit> list) {
 +    public static <T extends Unit> void printAll2(ArrayList<T> list) {
 +        for( Unit u : list ) {
 +            System.out.println(u);
 +        }
 +    }
 +}
 </code> </code>
 +
 +===== 타입에 안전한 열거형 (Typesafe enums) =====
 +이전까지 자바는 C언어와 달리 열거형이라는 것이 존재하지 않았으나 새로 추가되었다. 자바의 열거형은 C언어의 열거형보다 더 향상된 개념의 열거형으로 열거형이 갖는 값 뿐만아니라 타입까지 관리하기 때문에 보다 논리적인 오류를 줄일 수 있다.
 +<code java>
 +class Card {
 +    static final int CLOVER  = 0;
 +    static final int HEART   = 1;
 +    static final int DIAMOND = 2;
 +    static final int SPADE   = 3;
 +    
 +    static final int TWO     = 0;
 +    static final int THREE   = 1;
 +    static final int FOUR    = 2;
 +    
 +    final int kind;
 +    final int num;
 +}
 +</code>
 +
 +<code java>
 +class Card {
 +    enum Kind { CLOVER, HEART, DIAMOND, SPADE }
 +    enum Value { TWO, THREE, FOUR }
 +    
 +    final Kind kind;    // 타입이 int가 아닌 Kind임에 유의하자.
 +    final Value value;
 +}
 +</code>
 +이전 방식으로는 타입이 달라도 값이 같으면 조건식결과가 true였으나, 새로 도입된 타입에 안전한 열거형에서는 실제 값이 같아도 타입이 다르면 조건식의 결과가 false가 된다. 이처럼 값뿐만 아니라 타입까지 체크하기 때문에 안전한(typesafe) 열거형이라고 하는 것이다.
 +<code java>
 +if(Card.CLOVER == Card.TWO)            // true지만 false이어야 의미상 맞음.
 +if(Card.Kind.CLOVER == Card.Value.TWO) // false
 +</code>
 +
 +  * 예제 : EnumEx.java <code java>
 +import java.util.*;
 +
 +class EnumEx {
 +    public static void main(String[] args) {
 +        Deck deck = new Deck();
 +        
 +        System.out.println(deck.pick(0));
 +        System.out.println(deck.pick(1));
 +        System.out.println(deck.pick(2));
 +    }
 +}
 +
 +class Card {
 +    enum Kind { CLOVER, HEART, DIAMOND, SPADE }
 +    enum Value { TWO, THREE, FOUR, FIVE, SIX,
 +                 SEVEN, EIGHT, NINE, TEN,
 +                 JACK, QUEEN, KING, ACE }
 +                 
 +    final Kind kind;
 +    final Value value;
 +    
 +    Card(Kind kind, Value value) {
 +        this.kind = kind;
 +        this.value = value;
 +    }
 +    
 +    Card() {
 +        this(Kind.SPADE, Value.ACE);
 +    }
 +    
 +    public String toString() {
 +        return "["+kind+","+value="]";
 +    }
 +}
 +
 +class Deck {
 +    ArrayList<Card> cards = new ArrayList<Card>();
 +    
 +    Deck() {
 +        for(Card.Kind kind : Card.Kind.values()) {
 +            for(Card.Value value : Card.Value.values()) {
 +                cards.add(new Card(kind, value));
 +            }
 +        }
 +    }
 +    
 +    Card pick(int index) {
 +        return cards.get(index);
 +    }
 +}
 +</code>
 +
 +===== 가변인수 (Varargs) =====
 +기존에는 메서드의 매개변수 개수를 고정적으로 지정해주어야만 했으나 JDK 1.5 부터는 동적으로 매개변수의 개수를 지정해 줄 수 있게 되었다.
 +<code java>
 +public String concatenate(String s1, String s2) { /* 내용생략 */ }
 +public String concatenate(String s1, String s2, String s3) { /* 내용생략 */ }
 +public String concatenate(String s1, String s2, String s3, String s4) { /* 내용생략 */ }
 +...
 +public String concatenate(String[] strArr) { /* 내용생략 */ }
 +</code>
 +문자열을 결합하여 반환하는 concatenate메서드를 위와 같이 오버로딩하여 정의하는 대신 아래와 같이 가변인수를 정의하면 된다. 가변인수는 '타입... 변수명'와 같은 형식으로 정의한다.
 +<code java>
 +public String concatenate(String... str) { /* 내용생략 */ }
 +</code>
 +가변인수의 대표적인 예는 PrintStream의 printf()와 MessageFormat의 format()이다.
 +<code java>
 +public PrintStream printf(String format, Object... args) { /* 내용생략 */ }
 +public static String format(String pattern, Object... arguments) { /* 내용생략 */ }
 +</code>
 +가변인수를 사용할 때 한 가지 주의해야할 점은 오버로딩을 하는 경우인데, 먼저 예제를 살펴보고 그 다음에 자세히 설명하겠다.
 +
 +  * 예제 : VarArgsEx1.java <code java>
 +class VarArgsEx1 {
 +    public static void main(String[] args) {
 +        System.out.println(concatenate("-", "100", "200", "300"));
 +    }
 +    
 +    static String concatenate(String delim, String... args) {
 +        String result = "";
 +        
 +        for(String str : args) {
 +            result += str + delim;
 +        }
 +        
 +        return result;
 +    }
 +
 +/*
 +    static String concatenate(String... args) {
 +        return concatenate("", args);
 +    }
 +*/
 +}
 +</code>
 +concatenate 메서드는 매개변수로 입력된 문자열에 구분자를 사이에 포함시켜 결합해서 반환한다. 가변인수로 매개변수를 선언했기 때문에 문자열을 개수의 제약없이 매개변수로 지정할 수 있다. 위의 예제에서는 주석처리하였지만 concatenate 메서드의 또 다른 오버로딩된 메서드가 있다.
 +이 두 메서드는 별 문제가 없어 보이지만 위의 예제에서 주석을 풀고 컴파일을 하면 아래와 같이 컴파일에러가 발생한다.
 +<code>
 +VarArgsEx1.java:5: reference to concatenate is ambigous, both method
 +concatenate(java.lang.String,java.lang.String...) in VarArgsEx1 and
 +method concatenate(java.lang.String...) in VarArgsEx1 match
 +         System.out.println(concatenate("-", "100", "200", "300"));
 +
 +1 error
 +</code>
 +에러의 내용을 살펴보면 두 오버로딩된 메서드를 구분되지 않아서 발생하는 것임을 알 수 있다. 가변인수를 선언한 메서드를 오버로딩할 때는 이와 같이 구별되지 못하는 경우가 발생하기 쉽기 때문에 주의해야 한다. 그래서 가능하면 가변인수를 사용한 메서드를 오버로딩하지 않는 것이 좋다.
 +
 +===== static import =====
 +import 문을 사용하면 클래스의 패키지명을 생략할 수 있는 것과 같이 static import 문을 사용하면 static 멤버를 호출할 때 클래스명을 생략할 수 있다. 이러한 기능은 코딩을 편리하게 해주지만 남용하면 오히려 독이 될 수 있기 때문에 주의하도록 하자.
 +<code java>
 +import static java.lang.System.out;
 +import static java.lang.Math.*;
 +</code>
 +만일 위와 같이 static import 문을 선언하였다면, 아래의 코드처럼 간략히 할 수 있다.
 +<code java>
 +System.out.println(Math.random());
 +</code>
 +<code java>
 +out.println(random());
 +</code>
 +
 +  * 예제 : StaticImportEx1.java <code java>
 +import static java.lang.System.out;
 +import static java.lang.Math.*;
 +
 +class StaticImportEx1 {
 +    public static void main(String[] args) {
 +        // System.out.println(Math.random());
 +        out.println(random());
 +        
 +        // System.out.println("Math.PI : " + Math.PI);
 +        out.println("Math.PI : " + PI);
 +    }
 +}
 +</code>
 +
 +
study/java/javachobo/appendix.1268999529.txt.gz · 마지막으로 수정됨: 2010/03/19 20:52 저자 gauryan