0

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 :)

akapulko2020
  • 1,079
  • 2
  • 22
  • 36
  • 1
    what do you mean by returning new objects one by one? you can return from a method only once.. – keshav84 Sep 19 '10 at 14:11
  • *In Java*, you can only return once. Other languages have the concept of "generators" or "coroutines" that allow code to "yield" (return) a value, and resume right from that point when they're called again. For example, Ruby and (recently) C# have this ability. – cHao Sep 19 '10 at 14:14
  • isnt it same as delegates or passing anonymous classes to a method. but yeilding to a block still does not mean returning multiple times – keshav84 Sep 19 '10 at 14:22
  • No, it's not the same -- various state (including the location in the function!) would need to be preserved between calls. Delegates alone can't do that. An iterator-type object could do something sorta similar, maybe, if you don't have an algorithm with a half dozen steps, each of which can return one of the values wanted. Yielding (in the context of coroutines) actually pauses the function, passing the yielded value back as a return value. When the function's called again, it resumes from the point where it yielded, instead of having to start over. – cHao Sep 19 '10 at 14:27
  • not sure if mean the same thing as the answer i posted below – keshav84 Sep 19 '10 at 14:32

8 Answers8

4
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
  • 4,165
  • 7
  • 37
  • 56
  • 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 Sep 19 '10 at 20:08
3

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
  • 21,974
  • 5
  • 38
  • 51
  • It should be Iterator extends Object> or just Iterator>. Just to let you know, Iterator is not an Iterator. However, it is an Iterator extends Object>. If you say Iterator, it MUST be Object inside the iterator, not anything. – Leo Izen Sep 20 '10 at 22:50
  • 1
    @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 Sep 21 '10 at 07:32
  • I meant that it says Iterator as one of the parameters. You can't pass that an Iterator. If you declared Iterator> in the method declaration (Instead of Iterator) then you could pass it an Iterator. – Leo Izen Sep 23 '10 at 22:42
2

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);
    }
}
Turing
  • 778
  • 4
  • 17
  • Thanks, this seems to be the direction I was searching. – akapulko2020 Sep 19 '10 at 20:10
  • 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 Sep 19 '10 at 20:13
1

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 :

Community
  • 1
  • 1
Colin Hebert
  • 91,525
  • 15
  • 160
  • 151
0

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;
    }

}
keshav84
  • 2,291
  • 5
  • 25
  • 34
0

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);
        }
    }

}
Abhinav Sarkar
  • 23,534
  • 11
  • 81
  • 97
0

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
  • 33,375
  • 8
  • 89
  • 89
-2

Return a list of the new objects.

Steve McLeod
  • 51,737
  • 47
  • 128
  • 184