Guava를 사용하여 컬렉션을 변환하는 동안 null을 제거하는 우아한 방법이 있습니까?
Google 컬렉션 ( update : Guava )을 사용할 때 일부 컬렉션 처리 코드를 단순화하는 것에 대한 질문이 있습니다 .
나는 많은 "컴퓨터"개체를 가지고 있고, 그들의 "리소스 ID"컬렉션으로 끝내고 싶습니다. 이것은 다음과 같이 수행됩니다.
Collection<Computer> matchingComputers = findComputers();
Collection<String> resourceIds =
Lists.newArrayList(Iterables.transform(matchingComputers, new Function<Computer, String>() {
public String apply(Computer from) {
return from.getResourceId();
}
}));
이제 getResourceId()
null을 반환 할 수 있습니다 (그리고 지금은 옵션이 아닌 변경). 그러나이 경우 결과 String 컬렉션에서 null을 생략하고 싶습니다.
다음은 null을 필터링하는 한 가지 방법입니다.
Collections2.filter(resourceIds, new Predicate<String>() {
@Override
public boolean apply(String input) {
return input != null;
}
});
다음과 같이 모두 합칠 수 있습니다.
Collection<String> resourceIds = Collections2.filter(
Lists.newArrayList(Iterables.transform(matchingComputers, new Function<Computer, String>() {
public String apply(Computer from) {
return from.getResourceId();
}
})), new Predicate<String>() {
@Override
public boolean apply(String input) {
return input != null;
}
});
그러나 이것은 그러한 간단한 작업에 대해 읽기는 말할 것도없고 우아하지도 않습니다! 사실, 평범한 오래된 자바 코드 (멋진 Predicate 나 Function이 전혀 없음)는 틀림없이 훨씬 더 깨끗할 것입니다.
Collection<String> resourceIds = Lists.newArrayList();
for (Computer computer : matchingComputers) {
String resourceId = computer.getResourceId();
if (resourceId != null) {
resourceIds.add(resourceId);
}
}
위를 사용하는 것도 확실히 옵션이지만 호기심 (그리고 Google 컬렉션에 대해 더 많이 배우고 싶은 마음 ) 으로 Google 컬렉션을 사용하여 더 짧거나 우아한 방식으로 똑같은 작업을 할 수 있습니까?
Predicates
여기에 도움이 될 술어가 이미 있습니다 Predicates.notNull()
.-그리고 이것을 좀 더 정리 하는 데 사용할 수 Iterables.filter()
있는 사실을 Lists.newArrayList()
사용할 수 있습니다 Iterable
.
Collection<String> resourceIds = Lists.newArrayList(
Iterables.filter(
Iterables.transform(matchingComputers, yourFunction),
Predicates.notNull()
)
);
당신이 실제로 필요하지 않으면 Collection
, 그냥 Iterable
, 다음 Lists.newArrayList()
호출은있는 거 한 단계 청소기 다시 너무 멀리 갈 수 있습니다!
나는 당신이 Function
의지가 다시 유용하다는 것을 알게 될 것이라고 생각하며, 다음과 같이 선언하면 가장 유용 할 것입니다.
public class Computer {
// ...
public static Function<Computer, String> TO_ID = ...;
}
이를 훨씬 더 정리하고 재사용을 촉진합니다.
A bit "prettier" syntax with FluentIterable
(since Guava 12):
ImmutableList<String> resourceIds = FluentIterable.from(matchingComputers)
.transform(getResourceId)
.filter(Predicates.notNull())
.toList();
static final Function<Computer, String> getResourceId =
new Function<Computer, String>() {
@Override
public String apply(Computer computer) {
return computer.getResourceId();
}
};
Note that the returned list is an ImmutableList
. However, you can use copyInto()
method to pour the elements into an arbitrary collection.
It took longer than @Jon Skeet expected, but Java 8 streams do make this simple:
List<String> resourceIds = computers.stream()
.map(Computer::getResourceId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
You can also use .filter(x -> x != null)
if you like; the difference is very minor.
Firstly, I'd create a constant filter somewhere:
public static final Predicate<Object> NULL_FILTER = new Predicate<Object>() {
@Override
public boolean apply(Object input) {
return input != null;
}
}
Then you can use:
Iterable<String> ids = Iterables.transform(matchingComputers,
new Function<Computer, String>() {
public String apply(Computer from) {
return from.getResourceId();
}
}));
Collection<String> resourceIds = Lists.newArrayList(
Iterables.filter(ids, NULL_FILTER));
You can use the same null filter everywhere in your code.
If you use the same computing function elsewhere, you can make that a constant too, leaving just:
Collection<String> resourceIds = Lists.newArrayList(
Iterables.filter(
Iterables.transform(matchingComputers, RESOURCE_ID_PROJECTION),
NULL_FILTER));
It's certainly not as nice as the C# equivalent would be, but this is all going to get a lot nicer in Java 7 with closures and extension methods :)
You could write your own method like so. this will filter out nulls for any Function that returns null from the apply method.
public static <F, T> Collection<T> transformAndFilterNulls(List<F> fromList, Function<? super F, ? extends T> function) {
return Collections2.filter(Lists.transform(fromList, function), Predicates.<T>notNull());
}
The method can then be called with the following code.
Collection c = transformAndFilterNulls(Lists.newArrayList("", "SD", "DDF"), new Function<String, Long>() {
@Override
public Long apply(String s) {
return s.isEmpty() ? 20L : null;
}
});
System.err.println(c);
'development' 카테고리의 다른 글
collectstatic을 수행 할 수 없습니다. (0) | 2020.12.07 |
---|---|
자바에서 UTF-8을 ISO-8859-1로 변환-단일 바이트로 유지하는 방법 (0) | 2020.12.07 |
변경 사항을 확인하려면 nodejs를 다시 시작하지 않고 서버 파일을 편집하려면 어떻게해야합니까? (0) | 2020.12.07 |
PHP CURL 및 HTTPS (0) | 2020.12.07 |
배열이 비어 있지 않은지 확인하는 방법은 무엇입니까? (0) | 2020.12.07 |