I have a conundrum that's caused me to ponder whether there are any standard java classes that implement Iterable<T> without also implementing Collection<T>. I'm implementing one interface that requires me to define a method that accepts an Iterable<T>, but the object I'm using to back this method requires a Collection<T>.
This has me doing some really kludgy feeling code that give some unchecked warnings when compiled.
public ImmutableMap<Integer, Optional<Site>> loadAll(
Iterable<? extends Integer> keys
) throws Exception {
Collection<Integer> _keys;
if (keys instanceof Collection) {
_keys = (Collection<Integer>) keys;
} else {
_keys = Lists.newArrayList(keys);
}
final List<Site> sitesById = siteDBDao.getSitesById(_keys);
// snip: convert the list to a map
Changing my resulting collection to use the more generified Collection<? extends Integer> type doesn't eliminate the unchecked warning for that line. Also, I can't change the method signature to accept a Collection instead of an Iterable because then it's no longer overriding the super method and won't get called when needed.
There doesn't seem to be a way around this cast-or-copy problem: other questions have been asked here an elsewhere and it seems deeply rooted in Java's generic and type erasure systems. But I'm asking instead if there ever are any classes that can implement Iterable<T> that don't also implement Collection<T>? I've taken a look through the Iterable JavaDoc and certainly everything I expect to be passed to my interface will actually be a collection. I'd like to use an in-the-wild, pre-written class instead as that seems much more likely to actually be passed as a parameter and would make the unit test that much more valuable.
I'm certain the cast-or-copy bit I've written works with the types I'm using it for in my project due to some unit tests I'm writing. But I'd like to write a unit test for some input that is an iterable yet isn't a collection and so far all I've been able to come up with is implementing a dummy-test class implementation myself.
For the curious, the method I'm implementing is Guava's CacheLoader<K, V>.loadAll(Iterable<? extends K> keys) and the backing method is a JDBI instantiated data-access object, which requires a collection to be used as the parameter type for the #BindIn interface. I think I'm correct in thinking this is tangental to the question, but just in case anyone wants to try lateral thinking on my problem. I'm aware I could just fork the JDBI project and rewrite the #BindIn annotation to accept an iterable...
Although there is no class that would immediately suit your needs and be intuitive to the readers of your test code, you can easily create your own anonymous class that is easy to understand:
static Iterable<Integer> range(final int from, final int to) {
return new Iterable<Integer>() {
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int current = from;
public boolean hasNext() { return current < to; }
public Integer next() {
if (!hasNext()) { throw new NoSuchElementException(); }
return current++;
}
public void remove() { /*Optional; not implemented.*/ }
};
}
};
}
Demo.
This implementation is anonymous, and it does not implement Collection<Integer>. On the other hand, it produces a non-empty enumerable sequence of integers, which you can fully control.
To answer the question as per title:
Are there any Java standard classes that implement Iterable without implementing Collection?
From text:
If there ever are any classes that can implement Iterable<T> that don't also implement Collection<T>?
Answer:
Yes
See the following javadoc page: https://docs.oracle.com/javase/8/docs/api/java/lang/class-use/Iterable.html
Any section that says Classes in XXX that implement Iterable, will list Java standard classes implementing the interface. Many of those don't implement Collection.
Kludgy, yes, but I think the code
Collection<Integer> _keys;
if (keys instanceof Collection) {
_keys = (Collection<Integer>) keys;
} else {
_keys = Lists.newArrayList(keys);
}
is perfectly sound. The interface Collection<T> extends Iterable<T> and you are not allowed to implement the same interface with 2 different type parameters, so there is no way a class could implement Collection<String> and Iterable<Integer>, for example.
The class Integer is final, so the difference between Iterable<? extends Integer> and Iterable<Integer> is largely academic.
Taken together, the last 2 paragraphs prove that if something is both an Iterable<? extends Integer> and a Collection, it must be a Collection<Integer>. Therefore your code is guaranteed to be safe. The compiler can't be sure of this so you can suppress the warning by writing
#SuppressWarnings("unchecked")
above the statement. You should also include a comment by the annotation to explain why the code is safe.
As for the question of whether there are any classes that implement Iterable but not Collection, as others have pointed out the answer is yes. However I think what you are really asking is whether there is any point in having two interfaces. Many others have asked this. Often when a method has a Collection argument (e.g. addAll() it could, and probably should, be an Iterable.
Edit
#Andreas has pointed out in the comments that Iterable was only introduced in Java 5, whereas Collection was introduced in Java 1.2, and most existing methods taking a Collection could not be retrofitted to take an Iterable for compatibility reasons.
In core APIs, the only types that are Iterable but not Collection --
interface java.nio.file.Path
interface java.nio.file.DirectoryStream
interface java.nio.file.SecureDirectoryStream
class java.util.ServiceLoader
class java.sql.SQLException (and subclasses)
Arguably these are all bad designs.
As mentioned in #bayou.io's answer, one such implementation for Iterable is the new Path class for filesystem traversal introduced in Java 7.
If you happen to be on Java 8, Iterable has been retrofitted with (i.e. given a default method) spliterator() (pay attention to its Implementation Note), which lets you use it in conjunction with StreamSupport:
public static <T> Collection<T> convert(Iterable<T> iterable) {
// using Collectors.toList() for illustration,
// there are other collectors available
return StreamSupport.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
}
This comes at the slight expense that any argument which is already a Collection implementation goes through an unnecessary stream-and-collect operation. You probably should only use it if the desire for a standardized JDK-only approach outweighs the potential performance hit, compared to your original casting or Guava-based methods, which is likely moot since you're already using Guava's CacheLoader.
To test this out, consider this snippet and sample output:
// Snippet
System.out.println(convert(Paths.get(System.getProperty("java.io.tmpdir"))));
// Sample output on Windows
[Users, MyUserName, AppData, Local, Temp]
After reading the excellent answers and provided docs, I poked around in a few more classes and found what looks to be the winner, both in terms of straightforwardness for test code and for a direct question title. Java's main ArrayList implementation contains this gem:
public Iterator<E> iterator() {
return new Itr();
}
Where Itr is a private inner class with a highly optimized, customized implementation of Iterator<E>. Unfortunately, Iterator doesn't itself implement Iterable, so if I want to shoe horn it into my helper method for testing the code path that doesn't do the cast, I have to wrap it in my own junk class that implements Iterable (and not Collection) and returns the Itr. This is a handy way to easily to turn a collection into an Iterable without having to write the iteration code yourself.
On a final note, my final version of the code doesn't even do the cast itself, because Guava's Lists.newArrayList does pretty much exactly what I was doing with the runtime type detection in the question.
#GwtCompatible(serializable = true)
public static <E> ArrayList<E> More ...newArrayList(Iterable<? extends E> elements) {
checkNotNull(elements); // for GWT
// Let ArrayList's sizing logic work, if possible
if (elements instanceof Collection) {
#SuppressWarnings("unchecked")
Collection<? extends E> collection = (Collection<? extends E>) elements;
return new ArrayList<E>(collection);
} else {
return newArrayList(elements.iterator());
}
}
Related
In Java 9 we have convenience factory methods to create and instantiate immutable List, Set and Map.
However, it is unclear about the specific type of the returned object.
For ex:
List list = List.of("item1", "item2", "item3");
In this case which type of list is actually returned? Is it an ArrayList or a LinkedList or some other type of List?
The API documentation just mentions this line, without explicitly mentioning that its a LinkedList:
The order of elements in the list is the same as the order of the
provided arguments, or of the elements in the provided array.
The class returned by List.of is one of the package-private static classes and therefore not part of the public API:
package java.util;
...
class ImmutableCollections {
...
// Java 9-10
static final class List0<E> extends AbstractImmutableList<E> {
...
}
static final class List1<E> extends AbstractImmutableList<E> {
...
}
static final class List2<E> extends AbstractImmutableList<E> {
...
}
static final class ListN<E> extends AbstractImmutableList<E> {
...
}
// Java 11+
static final class List12<E> extends AbstractImmutableList<E> {
...
}
static final class ListN<E> extends AbstractImmutableList<E> {
...
}
}
So this is not an ArrayList (neither a LinkedList). The only things you need to know is that it is immutable and satisfies the List interface contract.
However, it is unclear about the specific type of the returned object.
And that is all you need to know! The whole point is: these methods do return some List<Whatever> on purpose. The thing that you get back is guaranteed to fulfill the public contract denoted by the List interface. It is a list of the things given to that method, in the same order as those things were written down.
You absolutely should avoid writing any code that needs to know more about the lists returned by these methods! That is an implementation detail which should not matter to client code invoking these methods!
In that sense: your focus should be much more on the client side - for example by avoiding that raw type you are using in your example (using List without a specific generic type).
Actually the same idea is in Collectors.toList for example - you get a List back and the documentation specifically says : There are no guarantees on the type, mutability, serializability, or thread-safety of the List returned. At the moment it is an ArrayList returned, but obviously this can change at any point in time.
I wonder if the same should be done here - to explicitly mention that the type is a List and nothing more. This let's a lot of ground for future implementations to decide what type to return that would fit best - speed, space, etc.
List.of returns a List of special type like Collections.UnmodifiableList. It is neither an ArrayList nor LinkedList. It will throw an exception when you will try to modify it.
Though the question seems to have been answered by #ZhekaKozlov and #GhostCat both in terms of what the return type would be(ImmutableCollections.List) and how it has been created package private and is not a public API. Also adding to the facts that the implementation of these factory methods guarantees to fulfill the public contract denoted by the List interface.
To further provide a gist of the implementation of the ImmutableCollections then Set, Map and List a step further in it. I would add a sample representation for a List which is quite similar for Map and Set.
The ImmutableCollections currently implements these factory methods on the interface List using:
abstract static class AbstractImmutableList<E>
which extends the AbstractList class and throws an UnsupportedOperationException for all the possible operations overriding their implementation. Meaning no more operations allowed on the collection, making them equivalent to Java Immutable Collections.
Furthermore, this is extended by a class
static final class ListN<E> extends AbstractImmutableList<E>
with a constructor to evaluate certain checks for the input and its elements being NonNull to return the object consisting of an E[] elements(array of elements of type E) and overrides certain implementations as .get(int idx), .contains(Object o) based out of these elements.
The way it goes on for Map and Set is similar, just that the validations on top of the elements or a pair of key and value are ensured there. Such that you can't create these(throws IllegalArgumentException and NullPointer exceptions respectively) :
Set<String> set2 = Set.of("a", "b", "a");
Map<String,String> map = Map.of("key1","value1","key1","value1");
Set<String> set2 = Set.of("a", null);
Map<String,String> map = Map.of("key1",null);
When I try to implement my own ImmutableList (actually a wrapper that delegates to the underlying list) I get the following compiler error:
ImmutableListWrapper is not abstract and does not override abstract method isPartialView() in com.google.common.collect.ImmutableCollection
But in fact, it seems to be impossible to override isPartialView() because it is package protected and I'd like to declare the wrapper in my own package.
Why don't I simply extend ImmutableCollection? Because I want ImmutableList.copyOf() to return my instance without making a defensive copy.
The only approach I can think of is declaring a subclass in guava's package which changes isPartialView() from package-protected to public, and then having my wrapper extend that. Is there a cleaner way?
What I am trying to do
I am attempting to fix https://github.com/google/guava/issues/2029 by creating a wrapper that would delegate to the underlying ImmutableList for all methods except spliterator(), which would it override.
I am working under the assumption that users may define variables of type ImmutableList and expect the the wrapper to be a drop-in replacement (i.e. it isn't enough to implement List, they are expecting an ImmutableList).
If you want your own immutable list but don't want to implement it, just use a ForwardingList. Also, to actually make a copy, use Iterator as parameter for the copyOf. Here's a solution that should fulfill all your requirements described in the question and your answer.
public final class MyVeryOwnImmutableList<T> extends ForwardingList<T> {
public static <T> MyVeryOwnImmutableList<T> copyOf(List<T> list) {
// Iterator forces a real copy. List or Iterable doesn't.
return new MyVeryOwnImmutableList<T>(list.iterator());
}
private final ImmutableList<T> delegate;
private MyVeryOwnImmutableList(Iterator<T> it) {
this.delegate = ImmutableList.copyOf(it);
}
#Override
protected List<T> delegate()
{
return delegate;
}
}
If you want different behavior than ImmutableList.copyOf() provides, simply define a different method, e.g.
public class MyList {
public static List<E> copyOf(Iterable<E> iter) {
if (iter instanceof MyList) {
return (List<E>)iter;
return ImmutableList.copyOf(iter);
}
}
Guava's immutable classes provide a number of guarantees and make a number of assumptions about how their implementations work. These would be violated if other authors could implement their own classes that extend Guava's immutable types. Even if you correctly implemented your class to work with these guarantees and assumptions, there's nothing stopping these implementation details from changing in a future release, at which point your code could break in strange or undetectable ways.
Please do not attempt to implement anything in Guava's Imutable* heirarchy; you're only shooting yourself in the foot.
If you have a legitimate use case, file a feature request and describe what you need, maybe it'll get incorporated. Otherwise, just write your wrappers in a different package and provide your own methods and guarantees. There's nothing forcing you, for instance, to use ImmutableList.copyOf(). If you need different behavior, just write your own method.
Upon digging further, it looks like this limitation is by design:
Quoting
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableList.html:
Note: Although this class is not final, it cannot be subclassed as it has no public or protected constructors. Thus, instances of this type are guaranteed to be immutable.
So it seems I need to create my wrapper in the guava package.
I'm trying to write a generic class in Java. A few methods in that class require that T extends Comparable<T>. How can I make it such that T is required to be comparable only if one of those methods is used? Or maybe there's some other way I should organize my class?
Here's the class I'm trying to implement. Its and array that I plan to use on both comparable and non-comparable types.
// I know Java has its own containers, but this
// is homework and I'm not allowed to use them
class Array<T>
{
// Some methods that pose no
// special restrictions on T
// These require that T be comparable
public Array<T> union(...) {...}
public Array<T> intersect(...) {...}
}
You can hide type T for method. T of Test is not the same as T of CompareMethodhere.
public static class Test<T> {
<T extends Comparable<T>> void compareMethod(T t, Class<T> classt) {
}
void normalMethod(T t) {
}
}
Now example
Test<String> test = new Test<String>();//Comparable class
test.compareMethod("",String.class);//works fine
Test<Random> tes1t = new Test<Random>();//Non Comparable class
tes1t.compareMethod(new Random(),Random.class);//Compilation error here
tes1t.normalMethod(new Random());//Works fine
new Test<Random>().compareMethod("",String.class);// Not a good but can be valid
new Test<String>().compareMethod(new Random(),Random.class);//Compilation error here
Update:
After being cursed about this solution I did some search in java API and this practice gets followed for toArray() method
ArrayList<String> string = new ArrayList<String>();
string.toArray(new Integer[5]);<--Illegal however <T> is hide by toArray method
Edit: It looks like this is possible after all (see AmitD's post). But anyway, other possible solutions are
Refactor the methods requiring comparable into a subclass
Just use casts in the relevant methods, meaning that that part will only be checked at runtime.
It wont be possible through normal method such as using comparable.
It would be better if you share what is the exact requirement.
If Sorting in ArrayList/Arrays are your goal, then Comparing Non Comparable classes is useless. Sorting can only be done in objects of the same or sub types.
But if you are going to use compare for checking if the objects are equal or not then I'll suggest that you override equals(Object O) method.
I wrote a util class to filter elements in java.util.Collection as follows:
public class Util{
public static <T> void filter(Collection<T> l, Filter<T> filter) {
Iterator<T> it= l.iterator();
while(it.hasNext()) {
if(!filter.match(it.next())) {
it.remove();
}
}
}
}
public interface Filter<T> {
public boolean match(T o);
}
Questions:
Do you think it's necessary to write the method?
Any improvement about the method?
You should allow any Filter<? super T> not just Filter<T>.
Clients might also want to have a method that returns a new Collection instead:
public static <T> Collection<T> filter(Collection<T> unfiltered,
Filter<? super T> filter)
No. The guava-libraries already have this functionality. See Iterables.filter(iterableCollection, predicate) where the Predicate implements the filtering
Whether it's necessary depends on what you want to achieve. If you can use other third party libs like Google Collections, then no. If it's planned to be a one-off, then probably not. If you plan on creating different filters, then yep, looks like a good approach to keep things modular and cohesive.
One suggestion - you might want to return a Collection - that way, you have the option of returning a new filtered Collection rather than mutating the original Collection. That could be handy if you need to use it in a concurrent context.
You might also look at the responses to this similar question.
Regarding question 1 there are already a lot of collection libraries. Filtering is offered by instance by apache common-collections CollectionUtils and google collections Iterables .
Looks nice - but we can't decide, if it's 'necessary' to write it (OK, you actually wrote it ;) )
The remove() method is not always implemented, it is labelled (optional). Some Iterators just throw an UnsupportedOperationException. You should catch it or convert it to a custom exception saying, that this collection can't be filtered.
And then you could change the method signature to
public static <T> void filter(Iterable<T> i, Filter<T> filter)
because iterators are not limited to Collections. With this utility method you could filter every 'container' that provides an iterator which allows remove operations.
Do you think it's necessary to write the method?
If you don't mind using a third party library then no.
Some suggestions for third party libraries that provide this functionality:
You might want to look at Functional Java which provides filter plus many other higher order functions found in true-blue functional languages.
Example:
List<Person> adults = filter(people, new F1<Person, Boolean>() {
public Boolean f(Person p) {
return p.getAge() > 18;
}
});
Another alternative is using lambdaj - a library with similar goals but is much more concise than Functional Java. lambdaj doesn't cover as much ground as Functional Java though.
Example:
List<Person> adults = filter(having(on(Person.class).getAge(), greaterThan(18)), people);
I think it would be cool to have a visit(T o) method defined in your Filter<T> interface. That way the filter implementation can decide what action to take on the visited object when there is a match.
In Java, is it possible to declare a field/variable whose type is multiple interfaces? For example, I need to declare a Map that is also Serializable. I want to make sure the variable references a serializable map. The Map interface does not extend Serializable, but most of Map's implementations are Serializable.
I'm pretty sure the answer is no.
Follow up: I'm fully aware of creating a new interface that extends both Map and Serializable. This will not work as existing implementations (such as HashMap) do not implement my new interface.
You can do it with generics, but it's not pretty:
class MyClass<T,K,V extends Serializable & Map<K,V>> {
T myVar;
}
There is no need to declare the field/variable like that. Especially since it can only be tested runtime and not compile time. Create a setter and report an error should the passed Map not implement Serializable.
The answers recommending that you create your own interface are of course not very practical as they will actively prohibit sending in things that are Maps and Serializable but not your special interface.
It's possible to do this using some generics tricks:
public <T extends Map<?,?> & Serializable> void setMap(T map)
The above code uses generics to force you to pass a map which implements both interfaces. However, note that a consequence of this is that when you actually pass it the maps, they will probably need to be either marked as serializable or of a map type which is already serializable. It also is quite a bit more difficult to read. I would document that the map must be serializable and perform the test for it.
public interface MyMap extends Map, Serializable {
}
will define a new interface that is the union of Map and Serializable.
You obviously have to then provide a suitable implementation of this (e.g. MyMapImpl) and you can then provide variable references of the type MyMap (or Map, or Serializable, depending on the requirements).
To address your clarification, you can't retrofit behaviour (e.g. a serializable map). You have to have the interface and some appropriate implementation.
I voted up Brian's answer, but wanted to add a little higher-level thought..
If you look through the SDK, you'll find that they rarely (if ever) pass around actual collection objects.
The reason for that is that it's not a very good idea. Collections are extremely unprotected.
Most of the time you want to make a copy before passing it off and pass the copy so that any modifications to the collection won't change the environment for something else that's relying on it. Also, threading becomes a nightmare--even with a synchronized collection!
I've seen two solutions, one is to always extract an array and pass it. This is how the SDK does it.
The other is to ALWAYS wrap collections in a parent class (And I mean encapsulate, not extend). I've gotten into this habit and it's very worth while. It doesn't really cost anything because you don't duplicate all the collection methods anyway (actually you rarely duplicate any of them). In fact what you end up doing is moving "Utility" functionality from other classes distributed all over your code into the wrapper class, which is where it should have been in the first place.
Any method with a signature that matches "method(collection,...)" should almost certainly be a member method of that collection, as should any loops that iterate over the collection.
I just have to throw this out every now and then because it's one of those things I didn't get for a while (because nobody championed the concept). It always seems like it's going to have some drawback but having done this for a while and seeing the problems it solved and code it eliminated, I can't even imagine any possible drawbacks myself, it's just all good.
You can achieve this by making your own Interface, which extends the interfaces you want
public interface SerializableMap<K, V> extends Map<K, V>, Serializable {
}
In my case it worked just to declare the concrete type:
HashMap<String, String> mySerializableMap = new HashMap<>();
It allowed me to use the Map methods (like put) and pass the map to methods that required a Serializable, without casting. Not perfect when we’ve learned to program towards interfaces, but good enough for me in the situation I was in.
If you really insist: As has been noted, declaring a combined interface alone does not solve the problem since the concrete classes we already have do not implement our combined interface even when they do implement each of the two interfaces we combine. I use it as a first step on the way, though. For example:
public interface SerializableMap<K, V> extends Map<K, V>, Serializable {
// No new methods or anything
}
The next step is also declaring a new class:
public class SerilizableHashMap<K, V> extends HashMap<K, V> implements SerializableMap<K, V> {
private static final long serialVersionUID = 4302237185522279700L;
}
This class is declared to implement the combined interface and thus can be used wherever one of those types is required. It extends a class that already implements each of the interfaces separately, therefore there’s nothing more we need to do. And now we have got what you asked for. Example of use:
public static void main(String[] args) {
SerializableMap<String, String> myMap = new SerilizableHashMap<>();
// myMap works as a Map
myMap.put("colour1", "red");
myMap.put("colour2", "green");
// myMap works as a Serializable too
consumeSerializable(myMap);
}
public static void consumeSerializable(Serializable s) {
// So something with the Serializable
}
For most purposes I suggest that this is overkill, but now I have at least presented it as an option.
Link: What does it mean to “program to an interface”?
You can't really do it if you want to keep using the existing Map implementations.
An alternative would be to make a helper class, and add a method like this one:
public static Serializable serializableFromMap(Map<?, ?> map) {
if (map instanceof Serializable) {
return (Serializable)map;
}
throw new IllegalArgumentException("map wasn't serializable");
}
Nope, you'll pretty much need to cast.