Note that there are some explanatory texts on larger screens.

plurals
  1. POFiltering lists of generic types
    primarykey
    data
    text
    <p>Lists or Iterables can be filtered easily using guavas <a href="http://guava-libraries.googlecode.com/svn/tags/release09/javadoc/com/google/common/collect/Iterables.html#filter%28java.lang.Iterable,%20java.lang.Class%29" rel="nofollow noreferrer"><code>filter(Iterable&lt;?&gt; unfiltered, Class&lt;T&gt; type)</code></a>. This operation performs two tasks: the list is filtered <em>and</em> transformed into a sequence of the given type T.</p> <p>Quite often however I end up with <code>Iterables&lt;Something&lt;?&gt;&gt;</code> and I want to get a subsequence of <code>Iterables&lt;Something&lt;T&gt;&gt;</code> for some specialized T. </p> <p>It is clear, that Guava can't solve this problem out of the box due to type erasure: <code>Something&lt;T&gt;</code> does not provide any direct information about its T.</p> <p>Lets say I have something like <code>S&lt;? extends Number&gt;</code>. If I am able to define some predicate which tells me if <code>S&lt;?&gt;</code> may be casted to <code>S&lt;Double&gt;</code> I may use it as a filer:</p> <pre><code>&lt;T extends Number&gt; Predicate&lt;S&lt;?&gt;&gt; isOfType(Class&lt;N&gt; type) {...} </code></pre> <p>with:</p> <pre><code>Iterable&lt;S&lt;?&gt;&gt; numbers; Iterable&lt;S&lt;?&gt;&gt; filtered = Iterable.filter(numbers, isOfType(Double.class)); </code></pre> <p>This performs the task of filtering but it misses the transformation step. If I think my Predicate works well I may even think of casting:</p> <pre><code>Iterable&lt;S&lt;Double&gt;&gt; doubles = (Iterable&lt;S&lt;Double&gt;&gt;) filtered; </code></pre> <p>But this exposes some ugly cast operation.</p> <p>As an alternative I may provide a <code>Function&lt;S&lt;?&gt;, S&lt;Double&gt;&gt;</code> to perform the cast. In constrast to <a href="http://download.oracle.com/javase/6/docs/api/java/lang/Class.html#cast%28java.lang.Object%29" rel="nofollow noreferrer"><code>Class.cast()</code></a> however it should not throw a <code>ClassCastException</code> but simply return <code>null</code> if the element can not be casted (or transformed). This way the sequence may be converted without any explicit cast:</p> <pre><code>&lt;T extends Number&gt; Function&lt;S&lt;?&gt;, S&lt;T&gt;&gt; castOrNull(Class&lt;N&gt; type) {...} Iterable&lt;S&lt;Double&gt;&gt; doubles = Iterable.filter(numbers, castOrNull(Double.class)); </code></pre> <p>But the list is not really filtered: instead it still contains null objects for each element which could not converted or casted to <code>S&lt;Double&gt;</code>. But this may solved easily by an additional filtering step like:</p> <pre><code>Iterable&lt;S&lt;Double&gt;&gt; doubles = Iterables.filter(doubles, Predicates.notNull()); </code></pre> <p>The second solution seems much smarter to me. The <code>Function</code> to be defined may either perform a cast (which hides the unchecked operation) or it may really create some new Object <code>S&lt;T&gt;</code> if necessary.</p> <p>The remaining question is: Is there any smarter way to perform the necessary converting and filtering by a single step? I may simply define some utility function like:</p> <pre><code>&lt;I,O&gt; Iterables&lt;O&gt; convert( Iterables&lt;O&gt; input, Function&lt;? super I, ? extends O&gt; convert, Predicate&lt;? super O&gt; filter); &lt;I,O&gt; Iterables&lt;O&gt; convert( Iterables&lt;O&gt; input, Function&lt;? super I, ? extends O&gt; convert); </code></pre> <p>Where the second function is a short cut of the first one with a <code>Predicates.notNull()</code>;</p> <p>But it's worth to have the first function, too, as the predicate is not necessary <code>Predicates.notNull()</code>. </p> <p>Imagine an <code>Iterable&lt;Iterable&lt;? extends Number&gt;&gt;</code>. The converter function <code>Function&lt;Iterable&lt;? extends Number&gt;, Iterable&lt;Double&gt;&gt;</code> may simply return a filtered sequence which may be empty instead of returning null. The additional filter may finally drop empty sequences using <code>Iterables.isEmpty()</code>. </p>
    singulars
    1. This table or related slice is empty.
    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.
 

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