Java - Implementing a custom Iterable without using an inner-iterator class - java

I have the follow code
public class SBag<Item> implements BagInterface<Item>, Iterable<Item> {
And when I try to compile I get
SBag.java:12: error: SBag is not abstract and does not override abstract method
iterator() in Iterable
public class SBag<Item> implements BagInterface<Item>, Iterable<Item>{
^
where Item is a type-variable:
Item extends Object declared in class SBag
My task is to implement Iterable without using an inner-iterator class, but I am unsure of how to do this because I get that error when compiling. I have the followin methods add(), isFull(), toArray(), isEmpty(), getCurrentSize(), remove(), clear(), and toString(). The overall goal is to be able to use a for-each loop, but I am unsure of how to proceed from here.

An Iterator as an inner class would look like this:
class MyIterable implements Iterable {
public Iterator iterator() {
return new Iterator() {
public boolean hasNext() {...}
public Object next() {...}
void remove();
}
}
}
In contrast, an Iterator that's not an inner class might look more like:
class MyIterable implements Iterable {
public Iterator iterator() {
return new MyIterator();
}
}
class MyIterator {
public boolean hasNext() {...}
public Object next() {...}
void remove();
}
This is another way that's technically speaking not an inner class, but some people will look at you funny if you say that:
class MyIterable implements Iterable {
public Iterator iterator() {
return new MyIterator();
}
static class MyIterator {
public boolean hasNext() {...}
public Object next() {...}
void remove();
}
}

When you implement Iterable, you can then use for:each loop syntax:
Implementing this interface allows an object to be the target of the
"foreach" statement.
Iterable is a generic interface, you should implement the method it contains:
public class MyIterable<E> implements Iterable<E>{
public Iterator<E> iterator() { // <--- Implement me!
return new CustomIterator<E>();
}
}
And then, for example, you can do something like this:
public class CustomIterator<T> implements Iterator<T> {
public boolean hasNext() {
//...
}
public T next() {
//...
}
public void remove() {
//...
}
}

While [this answer] provides the regular syntax for Iterable implementations, an Iterator can be useful without an Iterable-implementing class. For example:
public class DoesntIterate{
public void coolMethod(){
//Do stuff
Iterator iter = getMyIterator();
while(iter.hasNext()){
//Do stuff with iter.next()
}
}
private Iterator getMyIterator(){
return new MyIterator();
}
private class MyIterator implements Iterator{
...
}
}
With this sort of paradigm, it's conceivable that you might use different iterators for different purposes all within the same class.
From an OOP perspective, you should never be making a class implement Iterable when it doesn't make sense for that to be an class on which you would iterate (i.e. if the class is not a data/storage structure).

Related

Implementation of Iterable in Java

//project.java
import MULTISET;
public class Bag<E extends Keyed> implements Iterable<E> {
//cannot find symbol. symbol: class Iterator. location: class project.Bag<E>
public Iterator<E> iterator() {
return new ArrIterator(this);
}
//same error as above
public class ArrIterator implements Iterator<E> {
Bag<E> arr;
int coun;
public ArrIterator(Bag<E> arr) {
this.arr = arr;
this.coun = 0;
}
public boolean hasNext() {
return this.coun < arr.cardinality();
}
public E next() {
if (!hasNext()) {
throw new NoItemException();
}
return arr.getArray()[coun+1];
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
//MULTISET.java
//cannot find symbol. symbol: class Iterator. location: interface MultiSet<E>
public interface MultiSet<E extends Keyed> extends Iterable<E> {
public Iterator<E> iterator();
}
I'm trying to do foreach loops on type Bag, and I get the two commented errors. I'm not too familiar with ADT, generics, or iterators, but I thought I did the correct thing.
What is missing and/or wrong here? This isn't my complete code, but everything else I've left out works. There's a problem somewhere in the above code snippet. An example I was following is more or less 1:1 with my own code, but mine doesn't seem to work.
The problem is that your inner class ArrIterator is re-defining another generic type parameter <E> when it's still in scope from your outer class, Bag. This causes the new E not to match the old E.
According to Section 6.3 of the JLS:
The scope of a class's type parameter (§8.1.2) is the type parameter section of the class declaration, the type parameter section of any superclass or superinterface of the class declaration, and the class body.
Remove the re-declaration of E in your inner class ArrIterator and let its extends clause use the E already in scope.
public class ArrIterator implements Iterator<E> {
Then your iterator() method doesn't have to return a generic ArrIterator.
public Iterator<E> iterator() {
return new ArrIterator(this);
}
Also, your hasNext method in your iterator should return boolean to match the Iterator interface.

Java: Convert between iterator types (interface / implementing class)?

In a class, I have a container:
public class MyClass implements MyClassInterface {
private LinkedList<OtherClass> list; //Need to use 'OtherClass' instead of 'OtherClassInterface here
#Override
public Iterator iterator() {
return list.iterator; //Problem!
}
}
The interface:
public interface MyClassInterface {
//Is
public Iterator iterator();
//Should be
public Iterator<OtherClassInterface>();
}
Then again, OtherClass also has an interface OtherClassInterface.
I want only the interfaces to be used by whom who works with the code.
The problem is that I want to use the full OtherClass inside MyClass but pass an iterator over LinkedList<OtherClassInterface> to the caller of MyClassInterface.iterator().
I could not cast the existing LinkedList<OtherClass> to LinkedList<OtherClassInterface> inside MyClass to return the desired iterator.
How to handle such a situation?
EDIT
Reason why I want this behaviour
For another developer, I want to provide two interfaces: The first gives him access to a higher data structure which contains a lower data structure which he should access by the second interface. In the implementing class of the higher interface I use the type of the lower data structure directly, not over the lower interface.
As mentioned, the other developer wants to use both interfaces. Over the higher one I want to provide an iterator that gives access to elements of the lower interface - but not to the class that implements the interface.
Additional needs
I also want the returned iterator to be "Iterable" i.e. so that I can use the "for each" construct. Is this also possible with *waxwing*s solution? If possible, I wouldn´t like to implement an own iterator - for me this seems not neccessary because I just want to give an iterator over elements of the interface instead of the implementing class.
You could write your own Iterator implementation that converts between the interface and the concrete implementation when returning from next()
The problem with converting List<OtherClass> to List<OtherClassInterface> is that there is no way to prevent the user of the conversion result to put something other than OtherClass objects into the list (of course those elements must implement the OtherClassInterface as well)
Can you define the interface like this?
public interface MyClassInterface {
public Iterator<? extends OtherClassInterface>();
}
list.iterator() should be a valid return value for that method, even when list is List<OtherClass>.
Can you change the interface?
public interface MyClassInterface<T> {
public Iterator<T> iterator();
}
You can always implement your own iterator :
public class MyClass implements MyClassInterface<T> {
private LinkedList<T> list;
#Override
public Iterator iterator() {
return new Iterator<T>() {
int index;
public boolean hasNext() {
return index < list.size();
}
public T next() {
return list.get(index++);
}
public void remove() {
}
};
}
}
didn't test the code
The interface can be defined like this:
public interface MyClassInterface {
public LinkedList<? extends OtherClassInterface> list();
}
Then the implementation should look like this:
#Override
public LinkedList<OtherClass> list() {
return list; //this is the container of type LinkedList<OtherClass>
}
This has the following advantages:
When calling list() by an OtherClass object you will get a LinkedList<OtherClass>
When calling list() by an OtherClassInterface object you will get a LinkedList<OtherClassInterface>
The return value of each can be used in the for-each loop
The iterator can be obtained by list().iterator()

Setting Java generics of iterators

I've noticed something funny Java does (or at least Netbeans) when I use classes implementing ArrayList and changing the generics type of the elements. I basically created an abstract class that extends ArrayList and some subclasses that are supposed to work with String objects (so something like ArrayList<String>). One of the things I did to try to achieve that was this:
public abstract class A extends ArrayList {
...
}
#Override
public abstract class B extends A {
public Iterator<String> iterator() {
return super.iterator();
}
}
Another one was this:
public abstract class A extends ArrayList {
...
}
public abstract class B<String> extends A {
#Override
public Iterator<String> iterator() {
return super.iterator();
}
}
The first one overrides successfully the iterator() method assigning a String value to it. The other one somehow cancels out the type casting. The funny thing is that none of them works when it comes to for loops. This receives type Object instead of String.
for (String s : B) {
...
}
Do you have any idea why this happens and how can I fix it without implementing my own iterator?
Not sure what you are trying to do but if I understand correctly you want a class that extends ArrayList and has a Generic type of String... Perhaps you are looking for this:
public abstract class A<T> extends ArrayList<T> {
...
}
public abstract class B extends A<String> {
...
}
Then in your code, this:
B myList = ...;
for ( String s : myList ) {
...
}
Will work just fine. Though I think you could come up with a much better solution. Do you have more specifics about your problem?
Use composition instead of Inheritance
public class A implements Iterable<String>{
List<String> myList = new ArrayList<String>();
//do operations on myList
public Iterator<String> iterator() {
return myList.iterator();
}
}
If you extend generic class you should care about generics. I mean that your declaration should look like
public abstract class A extends ArrayList<String> {
...
}
if you want to use strings or
public abstract class <T> A extends ArrayList<T> {
...
}
if you want your class to be generic.
In both cases you do not have to override iterator() method: you can invoke its from super class and it will return you "good" iterator. Your declaration is equivalent to
public abstract class A extends ArrayList<Object> {
...
}
This is the reason for "strange" behavior.
BTW may I ask you why are you extending ArrayList? It really sounds strange.
OMG this is terrible:
public abstract class B<String> extends A {
#Override
public Iterator<String> iterator() {
return super.iterator();
}
}
String is not the class String, rather, you are declaring a new type variable called String (like T) that shadows the class String

Generic class implementing Iterable

I want to have a generic class that implements Iterable (let's call it ImplIterable) of type T that implements an Iterable interface over some class (that isn't of the generic class type); for example:
public class ImplIterable <T> implements Iterable<A> {
private A[] tab;
public Iterator<A> iterator() {
return new ImplIterator();
}
// doesn't work - but compiles correctly.
private class ImplIterator implements Iterator<A> {
public boolean hasNext() { return true; }
public A next() { return null; }
public void remove() {}
}
}
Where A is some class. Now, this code won't compile:
ImplIterable iable = new ImplIterable();
for (A a : iable) {
a.aStuff();
}
But this will:
Iterable<A> = new ImplIterable();
for (A a : iable) {
a.aStuff();
}
I don't understand why the latter doesn't compile and why can't I iterate over ImplIterable if it properly implements iterable. Am I doing something wrong/is there some workaround for this type of problems?
When you use a generic class without a generic parameter, all generics in that class are disabled.
Since ImplIterable is generic, and you're using it as a non-generic class, the generic parameters inside of it vanish, and it becomes an Iterable (non-generic) of Objects.

How does one change methods of an iterator?

Hey guys, I am fairly new to Java, and I have a question about collections and iterators.
In my code I have a collection (which somewhere down the road extends extends Iterable) and every object is basically a LinkedList.
I need an iterator for that collection, so I've wrote it down this way:
public class A{
LinkedList<B> BList= new LinkedList<B>();
...
public Iterator<B> iterator() {
return BList.iterator();
}
}
Now, the question is, how can I change any method of that iterator?
Or to be more specific, how can I disable the remove method of the iterator?
Thanks.
You could return an iterator of an unmodifiable list:
import java.util.Collections;
...
public class A{
LinkedList<B> BList= new LinkedList<B>();
...
public Iterator<B> iterator() {
return Collections.unmodifiableList(BList).iterator();
}
}
This will wrap your List with an implementation that disallows any changes to the list structure (like removal). You then return an iterator based on the wrapped list.
If you want an unmodifiable list, use the other answer posted here. But if you want to disable only the remove, a possible way is to create a new class that extends the Iterator interface but whose remove() method throws an exception (or simply does nothing) and forwards every other method to the original iterator object:
public class MyIterator implements Iterator {
private Iterator wrappedIterator;
public MyIterator( Iterator it ) {
wrappedIterator = it;
}
public void remove( blabla ) {
//do nothing or raise an error, whatever floats your boat
}
public void otherIteratorMethod() {
wrappedIterator.otherIteratorMethod();
}
}

Categories

Resources