Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I'd say that Guava is most definitely not harder to use than Apache Collections. I'd say it's a lot easier, actually.</p> <p>One of the big points in Guava's advantage is that it doesn't expose so many new object types... it likes to keep most of the actual implementation types it uses hidden neatly away behind static factory methods that only expose the interface. Take the various <code>Predicate</code>s, for example. In Apache Collections, you have top level public implementation classes like:</p> <pre><code>NullPredicate NotNullPredicate NotPredicate AllPredicate AndPredicate AnyPredicate OrPredicate </code></pre> <p>Plus a ton more.</p> <p>In Guava, these are neatly packaged up in a single top level class, <code>Predicates</code>:</p> <pre><code>Predicates.isNull() Predicates.notNull() Predicates.not(...) Predicates.and(...) Predicates.or(...) </code></pre> <p>None of them expose their implementation class, because you don't need to know it! While Apache Collections does have an equivalent <code>PredicateUtils</code>, the fact that it exposes the types of its <code>Predicate</code>s makes it harder to use. As I see it, Apache Collections is just a whole mess of unnecessary visible classes and not-very-useful parts that add clutter and make it harder to get at and use the useful parts. The difference is clear when you look at the number of classes and interfaces the two libraries expose:</p> <ul> <li>Apache Collections exposes 309 types.</li> <li>Guava, including all its packages (not just Collections) exposes just 191 types.</li> </ul> <p>Add to that the way Guava is much more careful only to include truly useful utilities and classes, its rigorous adherence to the contracts of the interfaces it implements, etc. and I think it's a much higher quality, easier to use library.</p> <p>To address some of your specific points:</p> <p>I actually think that the order Guava chose for <code>Functions.compose</code> is <em>more</em> intuitive (though I think that's quite a subjective argument to begin with). Note that in your example of composition with Guava, the order in which the functions will be applied reads from the end of the declaration <em>toward</em> the place where the final result is assigned. Another problem with your example is that it isn't type-safe to begin with, since the original example involves casting the result of the <code>get</code> method to another type. An advantage of Guava's <code>compose</code> over the array of <code>Transformer</code>s in the Apache Commons example is that <code>compose</code> can do a type-safe composition of functions, ensuring (at compile time) that the series of functions you're applying will work correctly. The Apache version is completely unsafe in this regard.</p> <p><strong>Views are superior to copies:</strong></p> <p>Second, about the live view "issue" of <code>Collections2.transform</code>. To be blunt, you're completely wrong on that point. The use of a live view rather than copying all elements of the original <code>Collection</code> into a new <code>Collection</code> is actually far more efficient! Here's what's going to happen when you call <code>Collections2.transform</code> and then call <code>contains</code> on the <code>Collection</code> it returns:</p> <ul> <li>A view <code>Collection</code> wrapping the original is created... the original and the <code>Function</code> are both simply assigned to fields in it.</li> <li>The <code>Collection</code>'s iterator is retrieved.</li> <li>For each element in the <code>Iterator</code>, the <code>Function</code> will be applied, getting the transformed value of that element.</li> <li>When the first element for which the transformed value <code>equals</code> the object you're checking for is found, <code>contains</code> will return. You only iterate (and apply the <code>Function</code>) until a match is found! The <code>Function</code> is applied at most once per element!</li> </ul> <p>Here's what the Apache Collections version does:</p> <ul> <li>Creates a new <code>ArrayList</code> to store the transformed values.</li> <li>Gets the original <code>Collection</code>'s iterator.</li> <li>For each element in the original <code>Collection</code>'s iterator, applies the function and adds the result to the new <code>Collection</code>. This is done for <em>every element</em> of the original <code>Collection</code>, even if the result of applying the <code>Transformer</code> to the very first element would have matched the object we're looking for!</li> <li><em>Then</em>, <code>contains</code> will iterate over each element in the new <code>Collection</code> looking for the result.</li> </ul> <p>Here's the best and worst case scenarios for a <code>Collection</code> of size N using both libraries. The best case is when the transformed value of the first element <code>equals</code> the object you're looking for with <code>contains</code> and the worst case is when the value you're looking for with <code>contains</code> does not exist in the transformed collection.</p> <ul> <li><strong>Guava</strong>: <ul> <li><strong>Best case</strong>: iterates 1 element, applies <code>Function</code> 1 time, stores 0 additional elements.</li> <li><strong>Worst case</strong>: iterates N elements, applies <code>Function</code> N times, stores 0 additional elements.</li> </ul></li> <li><strong>Apache</strong>: <ul> <li><strong>Best case</strong>: iterates N + 1 elements, applies <code>Transformer</code> N times, stores N additional elements (the transformed collection).</li> <li><strong>Worst case</strong>: iterates 2N elements, applies <code>Transformer</code> N times, stores N additional elements (the transformed collection).</li> </ul></li> </ul> <p>I hope it's obvious from the above that, in general, a view is a <em>very</em> good thing! Plus, it's really easy to copy a view into a non-view collection any time that would be useful, and that will have the same performance as the Apache version does to begin with. However, it would decidedly <em>not</em> be useful in any of the examples you've given.</p> <p>As a final minor note, <code>Iterables.contains</code> exists simply to allow you to check if an <code>Iterable</code> that you do not know to be a <code>Collection</code> contains a value. If the <code>Iterable</code> you give it actually is a <code>Collection</code>, it nicely just calls <code>contains()</code> on that <code>Collection</code> for you to allow for possible better performance (if it's a <code>Set</code>, say).</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload