【发布时间】:2011-04-26 05:49:24
【问题描述】:
我正在考虑让我的团队(技能水平参差不齐)使用 Google Guava。在 Guava 之前,我会使用 Apache Collections(或其通用版本)。
与 Apache Collections 相比,Guava 在某些方面似乎更强大,但对于经验不足的程序员来说可能不太容易使用。这是我认为可以说明这一点的一个领域。
我继承的代码包含大量循环列表,这些列表本质上是异构值的映射,探测它们的值,进行空值检查,然后做一些琐碎的事情:
boolean foo( final List< MapLike > stuff, final String target ) {
final String upperCaseTarget = target.toUpperCase(0;
for( MapLike m : stuff ) {
final Maplike n = (MapLike) m.get( "hard coded string" );
if( n != null ) {
final String s = n.get( "another hard code string" );
if( s != null && s.toUpperCase().equals( upperCaseTarget ) ) {
return true ;
}
}
return false ;
}
我最初的想法是使用 Apache Collections Transformers:
boolean foo( final List< MapLike > stuff, final String target ) {
Collection< String> sa = (Collection< String >) CollectionUtils.collect( stuff,
TransformerUtils.chainedTransformer( new Transformer[] {
AppUtils.propertyTransformer("hard coded string"),
AppUtils.propertyTransformer("another hard coded string"),
AppUtils.upperCaseTransformer()
} ) );
return sa.contains( target.toUpperCase() ) ;
}
使用番石榴,我可能有两种方式:
boolean foo( final List< MapLike > stuff, final String target ) {
Collection< String > sa = Collections2.transform( stuff,
Functions.compose( AppUtils.upperCaseFunction(),
Functions.compose( AppUtils.propertyFunction("another hard coded string"),
AppUtils.propertyFunction("hard coded string") ) ) );
return sa.contains( target.toUpperCase() ) ;
// or
// Iterables.contains( sa, target.toUpperCase() );
// which actually doesn't buy me much
}
与 Apache Collections 相比,Functions.compose( g, f ) 颠倒了“直观”的顺序:函数从右到左应用,而不是 TransformerUtils.chainedTransformer 的“明显”从左到右应用。
一个更微妙的问题是,当 Guava 返回实时视图时,在实时视图上调用 contains 可能会多次应用(组合)函数,所以我真正应该这样做做的是:
return ImmutableSet.copy( sa ).contains( target.toUpperCase() ) ;
但我的转换集中可能有空值,所以我不能这样做。当然,我可以将其转储到 java.util.Collection 中。
但这对我的(经验较少的)团队来说并不明显,即使我解释了它,也可能会在编码的热度中错过。我希望 Iterables.contains() 可能会“做正确的事”并知道一些魔术实例来区分实时视图代理和普通的旧集合,但事实并非如此。这使得番石榴可能更难使用。
也许我在我的实用程序类中编写了类似静态方法的东西来处理这个问题?
// List always uses linear search? So no value in copying?
// or perhaps I should copy it into a set?
boolean contains( final List list, final Object target ) {
return list.contains( target ) ;
}
// Set doesn't use linear search, so copy?
boolean contains( final Set set, final Object target ) {
//return ImmutableSet.copy( set ).contains( target ) ;
// whoops, I might have nulls
return Sets.newHashSet( set ).contains( target ) ;
}
或者也许只是超过一定大小的副本?
// Set doesn't use linear search, so copy?
boolean contains( final Set set, final Object target ) {
final Set search = set.size() > 16 : Sets.newHashSet( set ) : set ;
return search.contains( target ) ;
}
我想我是在问,“为什么在 Guava 中没有一个‘更简单的’transform”,我想答案是,“好吧,总是将它返回的内容转储到一个新的集合中,或者写您自己的转换可以做到这一点”。
但如果我需要这样做,可能不是 Guava 库的其他客户端吗?也许在 Guava 中有更好的方法,我不知道?
【问题讨论】:
-
"即使在我解释之后,也很可能会在编码的热潮中错过。" - 你们没有定期的代码检查吗?
-
好吧,我继承的团队没有。我现在已经制定了。但我更愿意利用审查时间来解决更大的问题。另外,如果我的团队认为“新方法太难了”,我不会接受。而且我更喜欢一个想要以正确方式做事的团队,而不是一个仅仅因为害怕警告而以正确方式做事的团队。
-
compose() 参数顺序:我对走哪条路有一定程度的焦虑,所以我做了研究,发现两种方式的先例大致相同。
-
我见过很少有库比 apache commons 库“更难”(这将是一个 eufemism)。除了必须说的话,我真的很喜欢番石榴。是对 Java 集合类的完美补充。
-
ListUtils.union 是一个令人困惑的 Apache Commons 方法的好例子。它使用两个列表的元素创建一个新列表,但是您需要检查 javadoc 以确定重复项会发生什么(很难不考虑使用 union 之类的名称的 SQL)。
标签: java collections guava