gpt4 book ai didi

java - Google Guava "harder"是否比 Apache Collections 更有用?

转载 作者:IT老高 更新时间:2023-10-28 21:17:06 31 4
gpt4 key购买 nike

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

7年前关闭。




Improve this question




我正在考虑让我的混合技能水平的团队使用 Google Guava。在加入 Guava 之前,我会使用 Apache Collections(或其通用版本)。

Guava 与 Apache Collections 不同,在某些方面似乎更强大,但对于经验不足的程序员来说可能不太容易使用。这是我认为可以证明这一点的一个领域。

我继承的代码包含大量循环遍历本质上是异构值映射的列表,探测它们的值,进行空检查,然后做一些微不足道的事情:

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() ) ;

}

使用 Guava ,我可能有两种方式:
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 集合相比,Functions.compose( g, f) 颠倒了“直观”的顺序:从右到左应用函数,而不是 TransformerUtils.chainedTransformer 的“明显”从左到右应用。

一个更微妙的问题是,当 Guava 返回实时 View 时,调用 contains在实时 View 中可能会多次应用(组合)函数,所以我真正应该做的是:
   return ImmutableSet.copy( sa ).contains( target.toUpperCase() ) ;

但是我的转换集中可能有空值,所以我不能完全做到这一点。当然,我可以将它转储到 java.util.Collection 中。

但这对我的(经验不足的)团队来说并不明显,即使在我解释之后,也可能会在编码的热潮中被错过。我希望也许 Iterables.contains() 会“做正确的事”并且知道一些魔法实例来区分实时 View 代理和普通的旧集合,但事实并非如此。这使得 Guava 可能更难使用。

也许我在实用程序类中编写了类似静态方法的东西来处理这个问题?
// 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 中有更好的方法,但我不知道?

最佳答案

我想说 Guava 绝对不比 Apache Collections 更难使用。我会说这实际上要容易得多。

Guava 的一大优点是它不会暴露这么多新的对象类型……它喜欢将它使用的大多数实际实现类型整齐地隐藏在只暴露接口(interface)的静态工厂方法后面。取各种Predicate s,例如。在 Apache 集合中,您拥有顶级公共(public)实现类,例如:

NullPredicate
NotNullPredicate
NotPredicate
AllPredicate
AndPredicate
AnyPredicate
OrPredicate

再加上一吨。

在 Guava 中,这些被整齐地打包在一个顶级类中, Predicates :
Predicates.isNull()
Predicates.notNull()
Predicates.not(...)
Predicates.and(...)
Predicates.or(...)

他们都没有公开他们的实现类,因为你不需要知道它!虽然 Apache Collections 确实有一个等效的 PredicateUtils ,事实是它暴露了其 Predicate 的类型s 使其更难使用。在我看来,Apache Collections 只是一堆不必要的可见类和不是非常有用的部分,这些部分会增加困惑并使获取和使用有用部分变得更加困难。当您查看两个库公开的类和接口(interface)的数量时,区别就很明显了:
  • Apache Collections 公开了 309 种类型。
  • Guava,包括它的所有包(不仅仅是 Collections)只公开了 191 种类型。

  • 除此之外,Guava 更加谨慎地只包含真正有用的实用程序和类,它严格遵守它实现的接口(interface)的契约等。我认为它是一个质量更高、更易于使用的库。

    要解决您的一些具体问题:

    我实际上认为 Guava 为 Functions.compose 选择的顺序更直观(尽管我认为这是一个非常主观的论点)。请注意,在您使用 Guava 进行组合的示例中,应用函数的顺序从声明的末尾到分配最终结果的位置。您的示例的另一个问题是开始时它不是类型安全的,因为原始示例涉及转换 get 的结果。方法到另一种类型。 Guava的优势 composeTransformer 的数组上Apache Commons 示例中的 s 是 compose可以执行类型安全的函数组合,确保(在编译时)您正在应用的一系列函数将正常工作。 Apache 版本在这方面是完全不安全的。

    浏览量优于副本:

    二、关于 Collections2.transform的直播“问题” .坦率地说,你在这一点上完全错了。使用实时 View 而不是复制原始元素的所有元素 Collection成新 Collection实际上效率更高!以下是您拨打 Collections2.transform 时会发生的事情然后拨打 containsCollection它返回:
  • View Collection包装原件创建...原件和Function两者都简单地分配给其中的字段。
  • Collection的迭代器被检索。
  • 对于 Iterator 中的每个元素, Function将被应用,获取该元素的转换值。
  • 当第一个元素的变换值 equals找到您要检查的对象,contains将返回。您只需迭代(并应用 Function )直到找到匹配项! Function每个元素最多应用一次!

  • 以下是 Apache Collections 版本的作用:
  • 创建新 ArrayList存储转换后的值。
  • 获取原文Collection的迭代器。
  • 对于原始 Collection 中的每个元素的迭代器,应用该函数并将结果添加到新的 Collection .这是为原始 Collection 的每个元素完成的。 ,即使应用 Transformer 的结果到第一个元素将匹配我们正在寻找的对象!
  • 然后,contains将迭代新 Collection 中的每个元素寻找结果。

  • 以下是 Collection 的最佳和最坏情况使用两个库的大小为 N。最好的情况是当第一个元素的变换值 equals您正在寻找的对象 contains最坏的情况是您正在寻找的值 contains不存在于转换后的集合中。
  • Guava :
  • 最佳案例 : 迭代 1 个元素,应用 Function 1 次,存储 0 个附加元素。
  • 最坏情况 : 迭代 N 个元素,适用 Function N 次,存储 0 个附加元素。
  • Apache :
  • 最佳案例 : 迭代 N + 1 个元素,适用 Transformer N 次,存储 N 个附加元素(转换后的集合)。
  • 最坏情况 : 迭代 2N 个元素,应用 Transformer N 次,存储 N 个附加元素(转换后的集合)。

  • 我希望从上面可以明显看出,总的来说, View 是一件非常好的事情!另外,在任何有用的时候将 View 复制到非 View 集合中真的很容易,并且这将具有与 Apache 版本开始时相同的性能。但是,它在您给出的任何示例中都绝对没有用。

    作为最后的小调, Iterables.contains存在只是为了让您检查是否 Iterable你不知道是 Collection包含一个值。如果 Iterable你给的其实是 Collection ,它很好地只是调用 contains()在那 Collection以便您获得更好的性能(如果它是 Set ,比如说)。

    关于java - Google Guava "harder"是否比 Apache Collections 更有用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3947560/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com