views:

141

answers:

8

I'm obviously missing something here, as this sound basic enough but yet...
I have a collection of objects . I need to use each one of them as parameter in constructor for a new object and return each new object to the caller method, one by one.

But -if I loop over the collection obviously the loop only runs once, and only returns the 1st object.

Edit : Returning the whole collection or some new collection will not work because :

The caller method [not mine to change] runs inside a start() method of a Runnable ThingProvider, which returns a single Thing whenever a request is submitted to it. So, returning List is not possible.

Thanks :)

A: 

Return a list of the new objects.

Steve McLeod
+1  A: 

In java you can return only once. So if you want to get some informations from your methods either you wrap them into a "Big" Object (here a List) or you give to the method the means to put informations in your parameters.

You could have something like this :

public static void main(String... args){
    List<Parameter> parameters = methodToGetParameters();
    List<Result> results = generateObjectsFromList(parameters);
    for(Result result : results){
        handleAResult(result);
    }
}

public List<Result> generateObjectsFromList(List<Parameter> parameters){
    List<Result> results = new ArrayList<Result>();

    for(Parameter parameter : parameters){
        results.add(new Result(parameter));
    }

    return results;
}

Or like this :

public static void main(String... args){
    List<Parameter> parameters = methodToGetParameters();
    List<Result> results = new ArrayList<Result>();
    generateObjectsFromList(parameters, results);
    for(Result result : results){
        handleAResult(result);
    }
}

public void generateObjectsFromList(List<Parameter> parameters, List<Result> results){        
    for(Parameter parameter : parameters){
        results.add(new Result(parameter));
    }        
}

A third way to do this would be to use fields, but it's not really good to have a lot of fields if they're not really used (or only by one method).


On the same topic :

Colin Hebert
+4  A: 
public List<T> loop(Collection<? extends U> coll) {
    List<T> a = new ArrayList<T>();
    for (U u : coll){
         a.add(new T(u));
    }
    return a;
}
Leo Izen
This is not what I meant -since, obviously, if I can iterate over the collection, I could have easily returned it as well, **if it was feasible given the caller method**...
akapulko2020
+2  A: 

This is a poorly worded question and I think as others have noted, just returning a new list of the objects is fine. But if you really want to process them one at a time while you're looping through it, you can use the command pattern.

public interface Command {
    void execute(NewType object);
}

Now in your caller method, you can do the following:

public void doSomething() {
    processList(myList, new Command() {
        void execute(NewType object) {
            // Do whatever you want with this object
        }
    });
}

And, in the method that will actually go through the list:

public void processList(Iterable<OldType> values, Command command) {
    for(OldType v : values) {
        NewType newType = new NewType(v);
        command.execute(newType);
    }
}
mangoDrunk
Thanks, this seems to be the direction I was searching.
akapulko2020
BTW, returning a list of new objects could have been fine if it was possible - but it isn't :)The caller method [not mine to change] is part of an existing library, where the said method runs inside a start() method of a Runnable ThingProvider, which returns a single Thing whenever a request is submitted to the ThingProvider .
akapulko2020
A: 

do you mean using of delegates something like below

public class Test {

    private static class Person{
        private final String name;

        Person(String name){
            this.name = name;
        }

        @Override
        public String toString() {
            return return name;
        }
    }

    private interface Printer {
        void print(Object object);
    }

    public static void main(String[] args) {
        final String[] names = {"one", "two", "three"};
        final ArrayList<Person> people = construct(names, new Printer() {

            @Override
            public void print(Object object) {
                System.out.println(object.toString());
            }
        });
    }

    private static ArrayList<Person> construct(String[] names, Printer printer) {
        ArrayList<Person> people = new ArrayList<Person>();
        for (String name : names) {
            printer.print(new Person(name));
        }
        return people;
    }

}
keshav.veerapaneni
+3  A: 

Return a custom Iterator. Assumming your new objects are of class MyObject and the constructor accepts an Object:

public Iterator<MyObject> myObjectsIterator(final Iterator<? extends Object> it) {
    return new Iterator<MyObject>() {
        public boolean hasNext() {
            return it.hasNext();
        }

        public MyObject next() {
            return new MyObject(it.next());
        }

        public void remove() {
            it.remove();
        }
    };
}

And you would call it like this:

...
Iterator<MyObject> myIt = myObjectsIterator(myListOfObjects.iterator());
// Now you can pass myIt around as a normal object. It will remember
// which one is the next Object with which to construct a MyObject
// and will generate it on the fly
...
while (myIt.hasNext()) { // is there any MyObject remaining?
    MyObject myObj = myIt.next(); // gets the next MyObject
    // do something with myObj
}
...
gpeche
It should be Iterator<? extends Object> or just Iterator<?>. Just to let you know, Iterator<String> is not an Iterator<Object>. However, it is an Iterator<? extends Object>. If you say Iterator<Object>, it MUST be Object inside the iterator, not anything.
Leo Izen
@Leo Izen Well I am creating a `MyObject` inside the `Iterator`, so I am pretty sure that it iterates over objects of the exact class `MyObject`.
gpeche
I meant that it says Iterator<Object> as one of the parameters. You can't pass that an Iterator<String>. If you declared Iterator<?> in the method declaration (Instead of Iterator<Object>) then you could pass it an Iterator<String>.
Leo Izen
@Leo Izen ah ok, I corrected it, thanks!
gpeche
A: 

Return a collection from the method and in the collection implement a custom iterator to transform the input collection to the new collection. The following code shows how to do it using the Google Guava library:

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;

public class Test {

    static class Person {
        public final String name;
        public Person(String name) {
            this.name = name;
        }
    }

    public static Collection<Person> peopleFromNames(Collection<String> names) {
        return Collections2.transform(names, new Function<String, Person>() {
            public Person apply(String name) {
                return new Person(name);
            }});
    }

    public static void main(String[] args) {
        List<String> names = Arrays.asList("Brian", "Albert", "Roger");
        for (Person person : peopleFromNames(names)) {
            System.out.println(person.name);
        }
    }

}
abhin4v
A: 

It's Possible.

Check these Project for Java-yield , yield4Java, infomancers

If you're using this just once in your entire code, You're better off choosing a method from the other answers.

st0le