I'm learning design patterns from 'Head First' series. The book is a bit outdated (no generic types ), so I'm trying to rewrite some of it. I'm supposed to write Wrapper on Iterator to work like Enumerator methods and test it with ArrayList.
The "original" version looked like this(below). I've tried to make it generic class such as <E> or even <T<E>>, but it didn't work. I want to be also sure that it will work for any kind of iterator, not only ArrayList like ArrayList<T>. What is the proper way to implement this ?
public class IteratorWrapper implements Enumeration {
Iterator iterator;
public IteratorWrapper(Iterator iterator){
this.iterator = iterator;
}
public boolean hasMoreElements(){
return iterator.hasNext();
}
//Return generic Type T
public Object nextElement(){
return iterator.next();
}
}
Test class
public class WrapperTest {
public static void main(String[] args){
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("element1");
arrayList.add("element2");
//This part will be rewritten when wrapper will work
IteratorWrapper iteratorWrapper = new IteratorWrapper(arrayList.iterator());
while(iteratorWrapper.hasMoreElements()){
System.out.println(iteratorWrapper.nextElement());
}
}
}
You can add a generic parameter like this:
public class IteratorWrapper<T> implements Enumeration<T> {
Iterator<T> iterator;
public IteratorWrapper(Iterator<T> iterator){
this.iterator = iterator;
}
public boolean hasMoreElements(){
return iterator.hasNext();
}
public T nextElement(){
return iterator.next();
}
}
Then, your initialization will look like this:
IteratorWrapper<String> iteratorWrapper = new IteratorWrapper<String>(arrayList.iterator());
Related
I'm trying to learn different design patterns in OOP and the current one I'm learning is iterator pattern. Therefore I have made two own interfaces (Iterable and Iterator).
I'm trying to iterate over List<Person> friends. But the row: for (Person p : p1) gives the following compiler error:
foreach not applicable to type 'com.company.Person'
Which to me makes no sense since I've implemented Iterable and overrided the iterator() method as far as I can see.
Can someone tell me what I'm missing?
Here is my code:
Main class:
Person p1 = new Person("Erik");
p1.addFriend("Lars");
p1.addFriend("Jenny");
p1.addFriend("Janne");
for (Person p : p1) {
System.out.println(p.name);
}
Iterator:
public interface Iterator<T> {
boolean hasNext();
T next();
void remove();
}
Iterable:
public interface Iterable<T> {
Iterator<T> iterator();
}
Person:
public class Person implements Iterable<Person>{
private List<Person> friends = new ArrayList<>();
String name;
int index = 0;
public Person(String name){
this.name = name;
}
public void addFriend(String name){
friends.add(new Person(name));
}
#Override
public Iterator<Person> iterator(){
return new Iterator<Person>() {
//int index = 0;
#Override
public boolean hasNext() {
System.out.println(index);
return index < friends.size();
}
#Override
public Person next() {
if(hasNext()){
return friends.get(index++);
}
else{
return null;
}
}
#Override
public void remove() {
if(index<=0) {
friends.remove(index--);
}
}
};
}
}
It looks like you have defined your own Iterator and Iterable interfaces. That's not how the foreach loop works in Java.
For a class to be a viable target for a foreach loop, it must implement the built-in Iterable, seen at java.lang.Iterable. Remove your own Iterator and Iterable interfaces, and implement the built-in Iterable (and use the built-in Iterator as well).
Additionally, as far as your semantics goes, it may not make much sense to have the Person class be Iterable. The collection of the person's friends should be the Iterable. Instead, you may want to expose the collection of friends via a getFriends() method that would return an unmodifiable view of that list (Collections.unmodifiableList(friends)). The list is already Iterable, saving you the need to implement it in the first place.
Iterable<Position<Integer>> iterable = list.positions();
Iterator<Position<Integer>> iter = iterable.iterator();
while (iter.hasNext()) {
System.out.println(iter.next().getData());
}
The above code works with no issues. list is just an instance of a List class that I wrote. It contains elements of the Integer type.
for (Position<Integer> pos : iterable) {
}
This code fails at the part past the colon. This should be equivalent to the first piece of code, the one with the while loop. So I don't understand why the for-each loop has an error. The error says: "Can only iterate over an array or an instance of java.lang.Iterable" - but iterable already is Iterable, isn't it? What am I missing here?
the following is the full code implementing the aforementioned methods and types.
private class PositionIterator implements Iterator<Position<E>> {
private Position<E> cursor = first();
private Position<E> current = null;
public boolean hasNext() {
return cursor.getData() != null;
}
public Position<E> next() {
if (cursor == null) throw new NoSuchElementException("reached the end of the list");
current = cursor;
cursor = after(cursor);
return current;
}
}
private class PositionIterable implements Iterable<Position<E>> {
public Iterator<Position<E>> iterator() {
return new PositionIterator();
}
}
public Iterable<Position<E>> positions() {
return new PositionIterable();
}
these are nested classes within another class called PositionalList<E>. In the interest of keeping this post compact, I decided to omit the outside class. It's just a bunch of getter and setter methods that are typical for a List class.
public interface Iterable<E> {
public Iterator<E> iterator();
}
^that's the Iterable interface being implemented by PositionIterable
public interface Iterator<E> {
boolean hasNext();
E next();
}
^And that's the Iterator interface.
The enhanced for loop accepts an Iterable, not an Iterator. iter is an Iterator.
Therefore :
for (Position<Integer> pos : iter)
Should be :
for (Position<Integer> pos : iterable)
EDIT : Based on the comments, your problem must be hiding java.lang.Iterable by your custom Iterable interface. If your iterable variable is of the type of your custom Iterable interface, it can't be used by the enhanced for loop, which accepts java.lang.Iterable.
You shouldn't have any issues running that code. Here's my local test code
public static void main(String[] args)
{
Iterable<String> iterable = Arrays.asList("foo",
"bar");
for (String anIterable : iterable)
{
System.out.println(anIterable);
}
}
If you have created a local class or interface called Iterable, that's the only reason I could think why this wouldn't work. If you have done that, delete it and then maybe go back and review the purpose of interfaces too.
I want to use ArrayList for example but besides only keeping an entry I want to store additional information: "write-in" time, some flag maybe. I could extend the class I am going to store but I want it to be the list feater. I thought maybe to do something like
public class PropertirizedArrayList<E> implements List<E> {
private static class TupleContainer<E>{
public E mainValue;
public Long hidingTime;
public Boolean flag;
}
private ArrayList<TupleContainer<E>> list = new ArrayList<>();
private ArrayList<TupleContainer<E>> delegate(){
return list;
}
//etc...
}
but I think it would be a great problem to reimplement all the List interface methods.
You can simply use List<TupleContainer<SomeType>>. I don't see a need to wrap the List with PropertirizedArrayList.
And if you do have some good reason to use a wrapper class (such a reason would be additional features that your wrapped list implements), you don't have to re-implement the existing List methods.
You have a List member contained within your class, so you can delegate each method of your class to the list.
For example :
public TupleContainer<E> get (int index)
{
return list.get (index);
}
Or if you don't want to expose TupleContainer :
public E get (int index)
{
return list.get (index).mainValue;
}
try this ...
private class TupleContainer<E>{
public E mainValue;
public Long hidingTime;
public Boolean flag;
}
List<TupleContainer<YourType>> list=new ArrayList<TupleContainer<YourType>>();
TupleContainer<YourType> tc=new TupleContainer<YourType>();
tc.mainValue=value;
tc.hidingTime=value;
tc.flag=value;
list.add(tc);
I wanted to create an Iterator for a generic class which worked fine. I thought the iterator would try to iterate using the TypeParameter of the generic class, but apparently that's not the case because Eclipse tells me that an Object is expected.
If someone knows what I've done wrong, I would be very happy.
public class GenericClass<T extends OtherClass> implements Comparable, Iterable
{
private ArrayList<T> list = new ArrayList<T>();
[...]
#Override
public Iterator<T> iterator()
{
Iterator<T> iter = list .iterator();
return iter;
}
[...]
}
public class Main
{
public static void main(String[] args)
{
GenericClass<InstanceOfOtherClass> gen = new GenericClass<InstanceOfOtherClass>("Aius");
for(InstanceOfOtherClass listElement : gen) // This is the problem line; gen is underlined and listElement is expected to be an Object
{
System.out.println(listElement.getName());
}
}
}
implements Comparable, Iterable
You need to specify the generic parameters of your base interfaces.
Otherwise, you'll be implementing Iterable non-generically, and the type parameter will become Object.
If you want to make your class generic like GenericClass<T extends OtherClass> then you should be implementing Comparable<T> and Iterable<T>, the T in both cases is the same T declared by GenericClass.
That way when you do a generic type instantiation as follows -
GenericClass<InstanceOfOtherClass> //...
The effect would be that it is implementing Comparable<InstanceOfOtherClass> and Iterable<InstanceOfOtherClass>, which makes the method signatures match.
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>>