I have the following interface:
public interface DataSet<T> extends Iterable<T> {
public int nExamples();
public T getExample(int index);
public Iterator<T> iterator();
}
Then a class implementing this interface:
public class StringTupleDataset implements DataSet<StringTuple> {
Vector<StringTuple> examples;
public StringTupleDataset(Vector<StringTuple> examples) {
if(examples == null)
throw new IllegalArgumentException("null parameter: examples");
this.examples = examples;
} // constructor
#Override
public int nExamples() {
return examples.size();
} // nExamples
#Override
public StringTuple getExample(int index) {
return examples.get(index);
} // getExample
#Override
public Iterator<StringTuple> iterator() {
return examples.iterator();
} // getAllExamples
} // class
The class StringTupleDataset compiles with no problem.
However, when I try and write this piece of code in another class:
public abstract class AbstractOntologyFiller<T> {
private AbstractOntologyFiller() {}
public static <T> void fill(OntologyManager ontoManager, DataSet<T> dataset) {
for(T e : dataset.iterator()) {
// do something
} // for
} // fill
} // class
I have a compilation error saying:
Can only interate over an array or an instance of java.lang.Iterable
Is there anyone who can help me?
You cannot iterate over an Iterator, but you can iterate through an Iterable.
for(T e : dataset)
will be enough, since Dataset extends Iterable, while dataset.iterator gives you an Iterator.
You just need to iterate over dataset instead of dataset.iterator()
Explanation: the for loop is expecting an Iterable. The Iterable is not the iterator: it is the object that has the iterator() method on it.
Ok, got the error.
I should have written:
public static <T> void fill(OntologyManager ontoManager, DataSet<T> dataset) {
for(T e : dataset) { // (without .iterator()
Related
First the simple case (A):
public class PsList implements List<Ps> { ... }
elsewhere
private void doSomething(List<Ps> list) { ... }
// compiles
List<Ps> arrayList = new ArrayList<Ps>();
doSomething(arrayList);
// does not compile
PsList psList = new PsList();
doSomething(psList);
Ok. I know that I can change this to "work" by adding ? extends as such:
private void doSomething(? extends List<Ps> list) { ... }
// compiles
List<Ps> arrayList = new ArrayList<Ps>();
doSomething(arrayList);
// compiles
PsList psList = new PsList();
doSomething(psList);
My question is why do I need to do that? It makes no sense to me. I am implementing the exact interface that is is expecting. I can pass other List types other than ArrayList why not mine?
Life is always more complicated than this, so my real coding issue is (B):
public class PsList implements List<Ps> { ... }
private void doSomething(Map<String, ? extends List<Ps>> map, Boolean custom) {
...
// need to create a new List<Ps> of either an ArrayList<Ps> or PsList
map.put("stringValue", custom ? new PsList() : new ArrayList<Ps>());
...
}
So, in either case Java is complaining that map is expecting ? extends List as the value.
even if I change this to be:
List<Ps> list = new ArrayList<>();
List<Ps> psList = new PsList();
map.put("string", custom ? psList : list);
and of course this doesn't compile:
? extends List<Ps> list = new ArrayList<>();
? extends List<Ps> psList = new PsList();
map.put("string", custom ? psList : list);
So what am I supposed to do to get something like this to work?
Edit 1:
Ok, a minimal reproduction:
Ps.java
package com.foo;
public class Ps
{
}
PsList.java
package com.foo;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class PsList implements List<Ps>
{
#Override
public int size()
{
return 0;
}
#Override
public boolean isEmpty()
{
return false;
}
#Override
public boolean contains(Object o)
{
return false;
}
#Override
public Iterator<Ps> iterator()
{
return null;
}
#Override
public Object[] toArray()
{
return new Object[0];
}
#Override
public <T> T[] toArray(T[] a)
{
return null;
}
#Override
public boolean add(Ps ps)
{
return false;
}
#Override
public boolean remove(Object o)
{
return false;
}
#Override
public boolean containsAll(Collection<?> c)
{
return false;
}
#Override
public boolean addAll(Collection<? extends Ps> c)
{
return false;
}
#Override
public boolean addAll(int index, Collection<? extends Ps> c)
{
return false;
}
#Override
public boolean removeAll(Collection<?> c)
{
return false;
}
#Override
public boolean retainAll(Collection<?> c)
{
return false;
}
#Override
public void clear()
{
}
#Override
public Ps get(int index)
{
return null;
}
#Override
public Ps set(int index, Ps element)
{
return null;
}
#Override
public void add(int index, Ps element)
{
}
#Override
public Ps remove(int index)
{
return null;
}
#Override
public int indexOf(Object o)
{
return 0;
}
#Override
public int lastIndexOf(Object o)
{
return 0;
}
#Override
public ListIterator<Ps> listIterator()
{
return null;
}
#Override
public ListIterator<Ps> listIterator(int index)
{
return null;
}
#Override
public List<Ps> subList(int fromIndex, int toIndex)
{
return null;
}
}
OtherService.java
package com.foo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OtherService
{
private void doSomething(Map<String, List<Ps>> map, Boolean custom)
{
if (custom)
{
map.put("someValue", new PsList());
} else {
map.put("someValue", new ArrayList<>());
}
}
private void callDoSomethingNotCustom()
{
Map<String, List<Ps>> map = new HashMap<>();
doSomething(map, false);
}
private void callDoSomethingCustom()
{
Map<String, PsList> map = new HashMap<String, PsList>();
// map is not the right format
doSomething(map, true);
}
}
Wrong 1st argument type. Found: 'java.lang.String,com.foo.PsList>', required: 'java.util.Map>'
As you seemed to realize halfway through your question, your problem is not about List<Ps> being interchangeable with PsList.
The problem is that you can’t add to a Map<String, ? extends List<Ps>>.
Let’s consider a simpler example:
void doSomething(Map<String, ? extends Number> map) {
map.put(String, Integer.valueOf(0)); // Not allowed.
}
The problem is that Map<String, ? extends Number> does not mean “values can be Number or any subclass of Number.”
Every generically typed object has a specific, non-wildcard type. Meaning, there does not exist a Map whose type is Map<String, ? extends Number>. However, the following can exist:
Map<String, Integer> (allows Integer values only)
Map<String, Double> (allows Double values only)
Map<String, Number> (allows values of any Number subclass)
Map<String, ? extends Number> refers to a Map that might be any one of the above (or, of course, any other specific Number subclass). The compiler doesn’t know which specific type the Map’s values are, but the Map still has a specific type for its values which does not make use of ? in any way.
So, looking at the example method again:
void doSomething(Map<String, ? extends Number> map) {
// Not allowed. The caller might have passed a Map<String, Double>.
map.put(String, Integer.valueOf(0));
// Not allowed. The caller might have passed a Map<String, Integer>.
map.put(String, Double.valueOf(0));
// Not allowed. The caller might have passed a Map<String, Integer>
// or Map<String, Double>. This method has no way of knowing what the
// actual restriction is.
Number someNumber = generateNewNumber();
map.put(String, someNumber);
}
Indeed, you cannot add anything to a Map or Collection whose type is an upper bound wildcard, because there is no way to know whether it’s correct and safe to do so.
In your case, the simplest solution is to remove the wildcard:
private void doSomething(Map<String, List<Ps>> map, boolean custom) {
// ...
map.put("stringValue", custom ? new PsList() : new ArrayList<Ps>());
}
If you really have Maps with different value types, you would need to tell the method the specific type being used:
private <L extends List<Ps>> void doSomething(Map<String, L> map,
Supplier<L> listCreator) {
// ...
map.put("stringValue", listCreator.get());
}
And then you can call the method like this:
if (custom) {
doSomething(psMap, PsList::new);
} else {
doSomething(listMap, ArrayList::new);
}
You can absolutely do that. Here is an example:
public class MyClass {
static interface FooList<T> {}
static class Ps {}
static void doSomething(FooList<Ps> list) { }
static class PsList implements FooList<Ps> { }
public static void main(String[] args)
{
FooList psList = new PsList();
doSomething(psList);
System.out.println("HelloWorld!");
}
}
See demo here.
I have something like this:
public class A implements Comparable<A> {
...
#Override
public int compareTo(A obj) {
...
}
}
public class B implements Comparable<B> {
...
#Override
public int compareTo(B obj) {
...
}
}
I also have a bunch of HashSet collections that are slowly populated over the course of a program, e.g.:
private Collection<A> col = new HashSet<A>();
At the very end of the program I would like to convert them to sorted lists so they can be displayed sorted:
public class Utils {
public static <T> Collection<Comparable<T>> toSortedList(Collection<Comparable<T>> col) {
List<Comparable<T>> sorted = new ArrayList<Comparable<T>>(col);
Collections.sort(sorted);
return sorted;
}
}
Unfortunately I get the compile error:
The method sort(List<T>) in the type Collections is not applicable for the arguments (List<Comparable<T>>)
How do I go about modifying the above so HashSets of both Comparable<A> and Comparable<B> can be passed to this method? Thanks!
Use <T extends Comparable<? super T>> generic syntax:
public class Utils {
public static <T extends Comparable<? super T>> Collection<T> toSortedList(Collection<T> col) {
List<T> sorted = new ArrayList<T>(col);
Collections.sort(sorted);
return sorted;
}
}
I have a List defined with generics. All elements in this list define the interface TransferableData. Depending on the object that eventually populates the list, i want to call a method to do something with the data.
So I want to archive something like this:
private <T extends TransferableData> String doSomething(List<T> data, Class<T> dataType){
if(returnType.equals(A.class)){
for(T singleElement : data){
((A)singleElement).methodInsideA();
}
}else if(returnType.equals(B.class)){
for(T singleElement : data){
((B)singleElement).methodInsideB();
}
}
}
I realize that this is NOT the way to do this. I just cannot find a proper way without all the if-else and the unchecked casting.
Based on the assumption that your classes are implementing TransferableData interface, you can add a method invokeMethod() which has void as return type. For below solution to work, you should have same method signature in all the classes.
public interface TransferableData {
void invokeMethod();
}
public class A implements TransferableData {
#Override
public void invokeMethod() {
//Your business logic A
}
}
public class B implements TransferableData {
#Override
public void invokeMethod() {
//Your business logic for B
}
}
Iterate over your list of objects as (No need to pass dataType to this method):
private <T extends TransferableData> String doSomething(List<T> data) {
for(T object: data){
object.invokeMethod();
}
//return the string according to your business logic.
}
As per the comment from Mena you can try something like this,
public interface TransferableData {
void genericInvoker();
}
public class A implements TransferableData {
#Override
public void genericInvoker() {
methodInsideA();
}
void methodInsideA(){
// Do specific thing to A
}
}
public class B implements TransferableData {
#Override
public void genericInvoker() {
methodInsideB();
}
void methodInsideB(){
// Do specific thing to B
}
}
Then you can invoke the methods as follows:
private <T extends TransferableData> String doSomething(List<T> data, Class<T> dataType){
for(T singleElement : data){
singleElement.genericInvoker();
}
//Don't forget to return a String from this method
}
I am trying to implement a Tree structure using a doubly linked list (called LinkedTree). With that said, when using my for-each loops, I end up getting the same repeated error: Can only iterate over an array or an instance of java.lang.Iterable. I've looked up some similar questions online but I can't seem to locate the problem. I know in order to iterator, you must have instances of iterable but isn't positions as well as children() both instances of iterable? I've included both methods with the errors, my children method, and my own implementation of iterable and iterator. Thanks in advance for the assistance.
public Iterator<E> iterator() {
Iterable<Position<E>> positions = positions();
PositionalList<E> elements = new NodePositionalList<E>();
for (Position<E> p: positions) // ERROR # positions
elements.addLast(p.element());
return elements.iterator();
}
private void preOrderPositions(Position<E> v, PositionalList<Position<E>> pos)
throws InvalidPositionException {
pos.addLast(v);
for (Position<E> w : children(v)) //ERROR # children (v)
preOrderPositions(w, pos);
}
Children Method
public Iterable<Position<E>> children(Position<E> v)
throws InvalidPositionException {
TreePosition <E> p = checkPosition(v);
if (isExternal(v))
throw new InvalidPositionException("");
return p.getChildren();
Iterator
public interface Iterator<E> {
public boolean hasNext();
public E next();
public void remove();
}
Iterable
public interface Iterable <E> {
public Iterator<E> iterator();
public Iterable<Position<E>> positions();
}
ElementIterator (my iterator implementation)
public class ElementIterator<E> implements Iterator <E> {
private PositionalList <E> list;
private Position <E> cursor;
public ElementIterator (PositionalList <E> L){
list = L;
cursor = (list.isEmpty())? null: list.first();
}
public boolean hasNext() {
return (cursor != null);
}
public E next(){
E toReturn = cursor.element();
cursor = (cursor == list.last())? null: list.next(cursor);
return toReturn;
}
public void remove(){
throw new UnsupportedOperationException();
}
}
EDIT: I converted the for-each loop into a while loop as shown below....
protected void preOrderPositions(Position<E> v,
PositionalList<Position<E>> pos) throws InvalidPositionException {
pos.addLast(v);
Iterator<Position<E>> iter = children(v).iterator();
while (iter.hasNext()) {
Position<E> w = iter.next();
preOrderPositions(w, pos);
}
}
You can only iterate over a class that implements java.lang.Iterable. You however try to iterate over your custom iterable interface. That doesnt work:
public interface Iterable <E> {
public Iterator<E> iterator();
public Iterable<Position<E>> positions(); // <- your custom Iterable class is returned here, NOT java.lang.Iterable
}
If you want to iterate using your iterable class, extend java.lang.Iterable
public interface Iterable <E> extends java.lang.Iterable<E>
HINT: Do not write classes / interfaces that have the same name as anything in the java.lang package.
So I am attempting to create a LinkedHashedDictionary's Iterator member for a homework assignment, however I am having multiple issues regarding its types.
Iterator Interface:
package nhUtilities.containers2;
public interface Iterator<Element> extends Cloneable, java.util.Iterator<Element>
{
public void reset ();
public void advance ();
public boolean done ();
public Element get ();
public boolean equals (Object obj);
public boolean traverses (Object container);
public Object clone ();
public void setEqualTo (Iterator<Element> other);
public boolean hasNext ();
public Element next ();
public void remove ();
}
In my code, I have a private class called EntryIterator. It extends an AbstractIterator, but implements the Iterator above.
My current implementation is as follows:
private class EntryIterator<Element> extends AbstractIterator<Element>
implements Iterator<Element>
{
protected Iterator<Key> keyIterator;
protected Dictionary<Key,Value> dictionary;
public EntryIterator(Dictionary<Key,Value> dictionary)
{
keyIterator = keys.iterator();
this.dictionary = dictionary;
}
public void reset()
{ keyIterator = keys.iterator(); }
/**
* #Requrie !this.done()
*/
public void advance()
{ keyIterator.advance(); }
public boolean done()
{ return keyIterator.done(); }
// public Entry<Key,Value> get()
// Violates initial Interface: Results in compile error.
// Return type must be "Element"
public Element get()
{
Key key = keyIterator.get();
Value value = dictionary.get(keyIterator.get());
return (Element) new Entry<Key,Value>(key, value);
}
public boolean traverses(Object container)
{
// TODO Iterator traverses
return false;
}
public void setEqualTo(Iterator<Element> other)
{
this.keyIterator = ((EntryIterator<Element>) other).keyIterator;
this.dictionary = ((EntryIterator<Element>) other).dictionary;
}
}
I have done multiple varieties of this class regarding its types, but none of them seem to be compatible with my Dictionary. Should I keep the formatting as is above, I get an error on my Dictionary's iterator() function:
public Iterator<Entry<Key,Value>> iterator()
{
return new EntryIterator<Entry<Key,Value>>(this);
}
The error states it is "The return type is incompatible for Dictionary.iterator()"
Should I change the type of the EntryIterator class' type to:
private class EntryIterator<eEntry<Key,Value>> extends AbstractIterator<Element>
implements Iterator<Element>
I simply get an error saying "Syntax error expected on token '<'" as well as another incompatibility error on my Dictionary.Iterator() function.
Can someone point me in the right direction as to how I can link up all of these different types to get them to return what my contract for Dictionary demands?
I have attempted asking my question during the class, via email to the instructor, as well as one on one merely to be avoided. Any help would be much appreciated.
So, the problem was actually with my class instantiation... Here for everyone with similar issues:
private class EntryIterator extends AbstractIterator<Entry<Key,Value>> implements
nhUtilities.containers2.Iterator<Entry<Key, Value>>