본문 바로가기

날리지/언어

Guava 를 사용해야 하는 5가지 이유

얼마전에 올렸던 List에서 중복요소 제거한 List로 만들기에서 많은 댓글이 오가면서 반농담삼아 그냥 Guava를 쓰자라는 결론(?)에 이르르면서 최근에 Guava를 좀 찾아서 써보면서Insightful Logic이라는 런던의 스타트업회사의 회사의 블로그에서 작성한 5 Reasons to use Guava라는 글을 보고 Guava를 파악해보기 위해서 번역한 글을 포스팅합니다. 이 내용은 Insightful Logic에 번역허락을 받고 올립니다.





Guava는 구글이 작성한 자바 오픈소스 라이브러리입니다. 개발자라면 이전에 한번정도는 스스로 작성해 보았거나 필요했지만 작성할 시간이 없었을만한 유용한 유틸리티 함수와 클래스들을 다양하게 제공하고 있습니다. 여기에 Guava를 사용하면 좋은 5가지 이유가 있습니다.


1. 컬렉션 초기화와 유틸리티
동질한 제너릭 컬렉션(제너릭 호모지니어스 컬렉션)은 자바가 가진 좋은 기능입니다. 하지만 때때로 컬렉션의 생성하기 아주 거추장 스럽습니다. 

Java

// 컬렉션 생성
final Map<String, Map<String, Integer>> lookup = new HashMap<String, Map<String, Integer>>();


Java 7에서는 이 문제를 정말 제너릭한 방법으로 해결했는데 제한된 타입추론의 형식을 형식에 구애받지 않고 다이아몬드 오퍼레이터로 참조할 수 있도록 하였습니다다. 그래서 위의 예제를 다음처럼 작성할 수 있습니다:

Java

// in Java 7
final Map<String, Map<String, Integer>> lookup = new HashMap<>();


이전의 자바버전에서도 생성자없는 메서드생성자가 아닌 메서드를 통해서 이러한 추론은 사실상 가능했습니다. 그리고 Guava는 이미 존재하는 자바 컬렉션에 생성자를 만드는 준비를 위해 많을 것을 제공합니다. 위의 예제는 다음처럼 작성할 수 있다:

Java

// in Guava
final Map<String, Map<String, Integer>> lookup = Maps.newHashMap();


또한 Guava는 많은 유용한 유틸리티 함수가 MapsSets등의 컬렉션에 들어있습니다. 특별히 제가 좋아하는 것은 Sets.union과 Sets.intersection메서드인데 이는 값을 재계산하지 않고 sets의 뷰를 리턴합니다.



2. 제한된 함수형 스타일의 프로그래밍
Guava는 함수형 스타일로 메서드를 전달하기 위한 일반적인 메서드들을 제공합니다. 예를 들어 많은 함수형 언어가 가지고 있는 map이 Collections2.transform 메서드의 형식으로 존재합니다. 또한 Collections2는 컬렉션에서 어떤 값을 제한하도록 하는 filter 메서드를 가지고 있습니다. 예를 들어 컬렉션에서 null인 요소들을 제거하고 다른 컬렉션에 저장하기 위해서 다음처럼 사용할 수 있습니다:

Java

// Collections2.filter
Collection<?> noNullsCollection = filter(someCollection, notNull());


존재하는 컬렉션을 수정하는 대신에 새로운 컬렉션을 리턴하고 계산된 컬렉션은 Lazy하게 계산된다는 것을 알아야 합니다.



3. 멀티맵(Multimaps)과 바이맵(Bimaps)
단일키에 여러 값을 저장하는 것등은 Map의 정말 일반적인 사용입니다. 일반적으로 표준 자바 컬렉션의 사용은 값타입처럼 또 다른 컬렉션을 사용함으로써 이루어집니다. 이것은 안타깝게도 결국에는 컬렉션 초기화같은 반복되는 많은 형식를 포함하게 됩니다. 멀티맵(Multimaps)은 이것을 아주 깔끔하게 만들어줍니다.

Java

Multimap<String, Integer> scores = HashMultimap.create();
scores.put("Bob", 20);
scores.put("Bob", 10);
scores.put("Bob", 15);
System.out.println(Collections.max(scores.get("Bob"))); // prints 20


또한 다른 방향의 바이맵(Bimaps) 클래스가 있습니다. 바이맵은 키처럼 값의 유일함을 강제합니다. 값도 유일하기 때문에 바이맵은 반대로 값을 키처럼 사용할 수도 있습니다.



4. 쉬운 해쉬코드와 비교자(Comparators)
자바에서 필드들의 해쉬코드로 클래스의 해쉬코드를 생성하는 것은 아주 일반적입니다. Guava는 이것을 위해서 Object 클래스에 유틸리티 메서드를 제공합니다. 다음은 그 예제입니다:

Java

int foo;
String bar;

@Override
public int hashCode() {
  return Objects.hashCode(foo, bar);
}


해쉬코드 메서드를 정의했다면 equals 계약을 유지하는 것을 잊지 말아야 합니다.

비교자(Comparator)는 오퍼레이션의 순서를 연결하는 것을 포함해서 자주 작성하게되는 또 다른 예입니다. Guava는 이 과정을 쉽게 하기 위해서 ComparisonChain 클래스를 제공합니다. 여기 int와 String클래스의 예제가 있습니다.

Java

int foo;
String bar;

@Override
public int compareTo(final GuavaExample o) {
  return ComparisonChain.start().compare(foo, o.foo).compare(bar, o.bar).result();
}




5. 방어적 코딩
메서드의 형식을 위해서 어떠한 필수조건들을 작성하는 것에 대해서 스스로 찾아본 적이 있습니까? 때때로 이것은 불필요하게 거추장스럽게 되거나 의도를 직접적으로 전달하는데 실패할 수 있습니다. Guava는 Preconditions 클래스를 일반적인 필수조건의 시리즈로 제공합니다.

필수조건을 위해서 if문과 명시적인 예외를 던지는 예제가 있습니다.

Java

if (count <= 0) {
  throw new IllegalArgumentException("must be positive: " + count);
}


명시적으로 필수조건을 작성할 수 있습니다.

Java

// in Guava
checkArgument(count > 0, "must be positive: %s", count);




결론
존재하는 라이브러리 클래스를 Guava로 교체하는 것은 유지보수를 위해 필요한 많은 양의 코드를 줄여주고 잠재적으로 생산성을 높여줍니다. 예를 들어 Apache Commons 프로젝트의 대안이 될 수 있습니다. 당신은 이미 이러한 라이브러리를 알고 있거나 사용할 수도 있고 Guava의 접근과 api를 선호할 수도 있습니다. Guava는 Idea Graveyard를 가지고 있습니다. Idea Graveyard 구글 엔지니어들이 라이브러리의 제한과 나쁜 디자인 결정에 대해서 무엇을 이해하고 있는가에 대한 아이디어를 줍니다. 자신만의 라이브러리 클래스를 작성하는 것으로 다시 돌아간다는 점에서 이러한 결정에 개인적으로 동의하지 않을 수도 있습니다. 그럼에도 불구하고 Guava는 간결하고 적은 형식을 장려하고 Guava의 몇몇 적절한 애플리케이션의 많은 자바 프로젝트에 도움이 될 수 있습니다.



-- Comment 

그러나 현재 진행하고 있는 과제에서 Guava를 사용할 수 없다. 왜냐하면  jdk 5 버전을 쓰고 있기 때문이다. jdk 버전도 7을 넘어서 9까지 출시되고 있는 판에 아직도 jdk5가 아니면 돌아가지 않는 시스템을 가지고 있다는 게 너무 심한 거 아닌가 하는 생각을 넘어서 정상인의 논리로 도저히 이해할 수 없는 경우인 거 같다. 



From Outsider's Blog

https://blog.outsider.ne.kr/710