아쉽게도 많은 언어들이 자신만의 장점을 소개할 때 많이 사용하는 방법 중 하나는 자바빈(Java Bean)을 얼마나 적은 코드로 구현할 수 있는지를 보여주며 자랑으로 삼곤 한다.
별거 아닌데 살짝 분하다는 생각이 든다. 그게 뭐 큰 자랑이라고!... 라고는 하지만 때때로 자랑은 자랑이다. 너무 축약되서 의미가 훼손되는 수준이 아니라면, 코드 줄 수는 적을 수록 좋은게 맞다.
자바의 대표적인 노다가성 코드가 엔티티 클래스나 자바 빈계열의 DTO클래스를 만들때 발생한다. getter와 setter로 클래스의 대부분을 채우기 십상이다. 그리고 hashcode나 equals구현, toString 정도 집어넣으면 별 로직도 없는 코드가 잔뜩 길어진다. 이럴때 유용한 자바 라이브러리가 바로 Lombok(http://projectlombok.org) 이다.
아래 코드는 Lombok을 사용하기 전
Lombok을 사용하면 동일한 내용이 아래와 같이 구현가능
Lombok에는 이외에도 리소스 정리 작업( close 메소드 호출 계열)을 지원해 주는 @Cleanup 기능.
원하는 수준으로 적절히 Lock을 제공하는 @Synchronized
등등의 기능을 제공한다.
다음 JDK에서는 일부 기능을 언어차원에서 지원해 줘도 괜찮을 것 같다는 생각이 든다. :)
별거 아닌데 살짝 분하다는 생각이 든다. 그게 뭐 큰 자랑이라고!... 라고는 하지만 때때로 자랑은 자랑이다. 너무 축약되서 의미가 훼손되는 수준이 아니라면, 코드 줄 수는 적을 수록 좋은게 맞다.
자바의 대표적인 노다가성 코드가 엔티티 클래스나 자바 빈계열의 DTO클래스를 만들때 발생한다. getter와 setter로 클래스의 대부분을 채우기 십상이다. 그리고 hashcode나 equals구현, toString 정도 집어넣으면 별 로직도 없는 코드가 잔뜩 길어진다. 이럴때 유용한 자바 라이브러리가 바로 Lombok(http://projectlombok.org) 이다.
[IBM DW] Java 코드에서 불필요한 코드를 제거할 수 있는 편리한 방법
http://www.ibm.com/developerworks/kr/library/os-lombok/index.html
http://www.ibm.com/developerworks/kr/library/os-lombok/index.html
아래 코드는 Lombok을 사용하기 전
001 import java.util.Arrays;
002
003 public class DataExample {
004 private final String name;
005 private int age;
006 private double score;
007 private String[] tags;
008
009 public DataExample(String name) {
010 this.name = name;
011 }
012
013 public String getName() {
014 return this.name;
015 }
016
017 void setAge(int age) {
018 this.age = age;
019 }
020
021 public int getAge() {
022 return this.age;
023 }
024
025 public void setScore(double score) {
026 this.score = score;
027 }
028
029 public double getScore() {
030 return this.score;
031 }
032
033 public String[] getTags() {
034 return this.tags;
035 }
036
037 public void setTags(String[] tags) {
038 this.tags = tags;
039 }
040
041 @Override public String toString() {
042 return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")";
043 }
044
045 @Override public boolean equals(Object o) {
046 if (o == this) return true;
047 if (o == null) return false;
048 if (o.getClass() != this.getClass()) return false;
049 DataExample other = (DataExample) o;
050 if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
051 if (this.getAge() != other.getAge()) return false;
052 if (Double.compare(this.getScore(), other.getScore()) != 0) return false;
053 if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
054 return true;
055 }
056
057 @Override public int hashCode() {
058 final int PRIME = 31;
059 int result = 1;
060 final long temp1 = Double.doubleToLongBits(this.getScore());
061 result = (result*PRIME) + (this.getName() == null ? 0 : this.getName().hashCode());
062 result = (result*PRIME) + this.getAge();
063 result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
064 result = (result*PRIME) + Arrays.deepHashCode(this.getTags());
065 return result;
066 }
067
068 public static class Exercise<T> {
069 private final String name;
070 private final T value;
071
072 private Exercise(String name, T value) {
073 this.name = name;
074 this.value = value;
075 }
076
077 public static <T> Exercise<T> of(String name, T value) {
078 return new Exercise<T>(name, value);
079 }
080
081 public String getName() {
082 return this.name;
083 }
084
085 public T getValue() {
086 return this.value;
087 }
088
089 @Override public String toString() {
090 return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
091 }
092
093 @Override public boolean equals(Object o) {
094 if (o == this) return true;
095 if (o == null) return false;
096 if (o.getClass() != this.getClass()) return false;
097 Exercise<?> other = (Exercise<?>) o;
098 if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
099 if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
100 return true;
101 }
102
103 @Override public int hashCode() {
104 final int PRIME = 31;
105 int result = 1;
106 result = (result*PRIME) + (this.getName() == null ? 0 : this.getName().hashCode());
107 result = (result*PRIME) + (this.getValue() == null ? 0 : this.getValue().hashCode());
108 return result;
109 }
110 }
111 }
Lombok을 사용하면 동일한 내용이 아래와 같이 구현가능
01 import lombok.AccessLevel;
02 import lombok.Setter;
03 import lombok.Data;
04 import lombok.ToString;
05
06 @Data public class DataExample {
07 private final String name;
08 @Setter(AccessLevel.PACKAGE) private int age;
09 private double score;
10 private String[] tags;
11
12 @ToString(includeFieldNames=true)
13 @Data(staticConstructor="of")
14 public static class Exercise<T> {
15 private final String name;
16 private final T value;
17 }
18 }
Lombok에는 이외에도 리소스 정리 작업( close 메소드 호출 계열)을 지원해 주는 @Cleanup 기능.
원하는 수준으로 적절히 Lock을 제공하는 @Synchronized
등등의 기능을 제공한다.
다음 JDK에서는 일부 기능을 언어차원에서 지원해 줘도 괜찮을 것 같다는 생각이 든다. :)
'Better SW Development' 카테고리의 다른 글
[FunDev행사] TDD Practice & Agile SW Design 함께 하기 (2) | 2010.11.19 |
---|---|
[dw Review] 미친 과학자의 에디터? 혹은 최고의 에디터! Vi IMproved (1) | 2010.10.28 |
좋은 소프트웨어를 만드는 어떤 방식 하나, 테스트 주도 개발 (Test-Driven Development) : (하편) (9) | 2010.10.23 |
[dW Review] 함수형 언어로 가는 길 (중편) - 일급객체 (2) | 2010.09.30 |
[dW Review] 함수형 언어로 가는 길 (상편) (7) | 2010.09.27 |