Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / First Aid / January 2007

Tip: Looking for answers? Try searching our database.

How do you change all elements in a Collection at the same time?

Thread view: 
phillip.s.powell@gmail.com - 12 Jan 2007 20:04 GMT
In my native language, PHP, we have a function called array_walk()
http://www.php.net/manual/en/function.array-walk.php

That will walk through an array and perform change on every element in
the array.

I've studied the Collections within Java so far and this seems like the
right way to do it (Collections.replaceAll(List list, Object oldVal,
Object newVal)):
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html#replaceAll(ja
va.util.List,%20java.lang.Object,%20java.lang.Object
)

But looking at the API does not tell me how to do a function-based
"array_walk" like we can so easily do in PHP:

<?
  $array = array(1, 2, 3, 4, 5);
  @array_walk($array, create_function('&$a', 'return ($a + 1);')); //
WILL RETURN (2, 3, 4, 5, 6)
?>

So how do I do this in Java?

Thanx
Phil
Paul Hamaker - 12 Jan 2007 20:21 GMT
As of Java5 :
for ( SomeClass c : somecoll )
{ //do something with (each) c in somecoll, like :
c.change(somearg);
}
--
http://javalessons.com  Paul Hamaker, SEMM
Teaching ICT since 1987
phillip.s.powell@gmail.com - 12 Jan 2007 20:41 GMT
> As of Java5 :
> for ( SomeClass c : somecoll )
> { //do something with (each) c in somecoll, like :
>  c.change(somearg);

But what if you won't know what "change()" will be? That is, I could be
doing any kind of uniform change to the collection; I could be adding
by 1, rearranging strings, converting Objects, literally anything at
all (except removing them)

Here is where I can't find the Java equivalent of "eval()", something
in PHP that's normal to me.

Phil

> }
> --
> http://javalessons.com  Paul Hamaker, SEMM
> Teaching ICT since 1987
Rogan Dawes - 12 Jan 2007 21:27 GMT
>> As of Java5 :
>> for ( SomeClass c : somecoll )
[quoted text clipped - 10 lines]
>
> Phil

Java is not an interpreted language. Hence it does not have "eval",
since the classes and methods may not actually be present on the classpath.

If you REALLY need "eval" functionality, and cannot achieve what you
need using sub-classes and/or interfaces, you may want to take a look at
BeanShell, which is an interpreted version of Java.

Regards,

Rogan
phillip.s.powell@gmail.com - 12 Jan 2007 21:37 GMT
> >> As of Java5 :
> >> for ( SomeClass c : somecoll )
[quoted text clipped - 17 lines]
> need using sub-classes and/or interfaces, you may want to take a look at
> BeanShell, which is an interpreted version of Java.

Thanx I'll look into it.  I don't however see how BeanShell will do
what I need to do within classes for a Java application to do what PHP
can do with eval() and array_walk() more easily. :(

Phil

> Regards,
>
> Rogan
Patricia Shanahan - 12 Jan 2007 23:14 GMT
>> As of Java5 :
>> for ( SomeClass c : somecoll )
[quoted text clipped - 5 lines]
> by 1, rearranging strings, converting Objects, literally anything at
> all (except removing them)

The suggested code is not an implementation of array_walk, but a
replacement for it. Use it at the point in the code where you decide to
do a specific thing to every element of a collection. Replace
c.change(somearg) with whatever operation, or combination of operations,
you want.

> Here is where I can't find the Java equivalent of "eval()", something
> in PHP that's normal to me.

If you consider "eval()" to be essential for whatever you are doing, you
should use an interpreted language, such as PHP.

Patricia
Mark Rafn - 12 Jan 2007 23:14 GMT
>> As of Java5 :
>> for ( SomeClass c : somecoll )
>> { //do something with (each) c in somecoll, like :
>>  c.change(somearg);

>But what if you won't know what "change()" will be? That is, I could be
>doing any kind of uniform change to the collection; I could be adding
>by 1, rearranging strings, converting Objects, literally anything at
>all (except removing them)

Define an interface like
 public interface SomeClassProcessor { void process(SomeClass c); }
and have the caller (whoever it is that DOES know what to do with each
element) pass you an instance of SomeClassProcessor.  Call process(c) on each
element.

>Here is where I can't find the Java equivalent of "eval()", something
>in PHP that's normal to me.

eval() is misspelled.  Change the a to an i.  It completely breaks any sort of
compile-time analysis, and cannot be optimized in any reasonable way.
--
Mark Rafn    dagon@dagon.net    <http://www.dagon.net/>
Eric Sosman - 13 Jan 2007 03:03 GMT
>> As of Java5 :
>> for ( SomeClass c : somecoll )
>> { //do something with (each) c in somecoll, like :
>>  c.change(somearg);
>
> But what if you won't know what "change()" will be? [...]

    Then you don't know whether the "change" will preserve
the collection's invariants.  Imagine traversing a HashSet
and applying a transformation that changed the hashCodes(),
or a TreeSet() and changing the outcome of compareTo() ...

    Unrestricted change on a structured collection is not
a Good Thing.  If you want mapcar, you know where to find it.

Signature

Eric Sosman
esosman@acm-dot-org.invalid

phillip.s.powell@gmail.com - 14 Jan 2007 08:50 GMT
> >> As of Java5 :
> >> for ( SomeClass c : somecoll )
[quoted text clipped - 10 lines]
>      Unrestricted change on a structured collection is not
> a Good Thing.  If you want mapcar, you know where to find it.

But what does a Lisp function have to do with Java?
Hendrik Maryns - 15 Jan 2007 11:11 GMT
phillip.s.powell@gmail.com schreef:
>>>> As of Java5 :
>>>> for ( SomeClass c : somecoll )
[quoted text clipped - 10 lines]
>
> But what does a Lisp function have to do with Java?

Nothing.  Read the above comment as: if you want Lisp functionality, use
Lisp.

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
John Ersatznom - 15 Jan 2007 16:36 GMT
> Nothing.  Read the above comment as: if you want Lisp functionality, use
> Lisp.

Lisp functionality? Lisp functionality is to tell you you have
unbalanced parentheses and leave you to find a needle in a haystack.
What he was looking for is myCollection collect: [:foo | foo + 1] which
is in a far nicer looking language. (But also a far slower one than
Java, unsuited for performing any serious work, last time I checked.)
Eric Sosman - 15 Jan 2007 18:49 GMT
>> Nothing.  Read the above comment as: if you want Lisp functionality, use
>> Lisp.
[quoted text clipped - 4 lines]
> is in a far nicer looking language. (But also a far slower one than
> Java, unsuited for performing any serious work, last time I checked.)

    "The above comment" (snipped; it was "If you want mapcar, you
know where to find it") was about the nature of collections.  Java
offers several kinds, some of which rely on characteristics of the
objects they contain: invariant hashCode(), consistent behavior of
compareTo() and so on.  These structured collections cannot tolerate
arbitrary and uncontrolled changes to their contained objects (the
O.P. asked "what if you won't know what `change()' will be?").

    Lisp's mapcar operator applies to a List, a kind of collection
whose structure does not rely on the nature of its contents but
only on their order of appearance.  By bringing it up, I intended
two things: to appear clever (lost cause) by paraphrasing a well-
known flippancy, but also to provoke the O.P. to think about what
makes a Lisp List different from, say, a Java SortedSet.  Java's
List is a reasonably close (albeit imperfect) analogue of Lisp's,
and a method that applies an arbitrary transformation to the contents
might make sense.  (Note that Java does not prevent the programmer
from extending List's supplied implementations, nor from rolling his
own.)  However, the O.P. asked for a much more general operation
that would apply to every kind of Collection -- and it was this goal
I wanted to call into question.

Signature

Eric Sosman
esosman@acm-dot-org.invalid

John Ersatznom - 16 Jan 2007 15:10 GMT
> However, the O.P. asked for a much more general operation
> that would apply to every kind of Collection -- and it was this goal
> I wanted to call into question.

Yes. Even aCollection collect: aBlock creates a new one rather than
doing in-place modification. In Java you want to use ListIterator for
this as was already pointed out in greater detail elsewhere.

If you want an unordered collection you can either use a list (and not
care about the ordering) or use a map, iterate over the keys, and change
the values (or iterate over the entry objects and change the values).
Map doesn't care if values mutate or are replaced.
phillip.s.powell@gmail.com - 16 Jan 2007 22:34 GMT
I'm sorry but all of you completely lost me. :(

Phil

> > However, the O.P. asked for a much more general operation
> > that would apply to every kind of Collection -- and it was this goal
[quoted text clipped - 8 lines]
> the values (or iterate over the entry objects and change the values).
> Map doesn't care if values mutate or are replaced.
Lew - 16 Jan 2007 23:15 GMT
> I'm sorry but all of you completely lost me. :(

Rather than bore you here, I will send you to Sun for boredom.

Er, wisdom.

<http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collection.html>
<http://java.sun.com/j2se/1.5.0/docs/api/java/util/Iterator.html>
<http://java.sun.com/j2se/1.5.0/docs/api/java/util/ListIterator.html>
and related java.util interfaces and classes.

<http://java.sun.com/docs/books/tutorial/collections/index.html>
for the tutorial.

Our friends had wandered down a back alley of nuances that differentiate
collection types. In your case, they were saying you needed a ListIterator for
various reasons that will make more sense after you have read the above links
then re-read the posts in this thread.

- Lew
Tom Hawtin - 12 Jan 2007 20:58 GMT
> That will walk through an array and perform change on every element in
> the array.

>    $array = array(1, 2, 3, 4, 5);
>    @array_walk($array, create_function('&$a', 'return ($a + 1);')); //
> WILL RETURN (2, 3, 4, 5, 6)

For a one off, you could write it explicitly as:

        List<Integer> values = Arrays.asList(new Integer[] {
                1, 2, 3, 4, 5
        });
        for (
            ListIterator<Integer> iter = values.listIterator();
            Integer value = iter.next();
        ) {
            iter.set(value + 1);
        }
        System.out.println(values);

To abstract the 'array walking' takes a bit more work:

public interface Transform<T> {
    T transform(T value);
}
...
    public <T> static void transform(
        List<T> values, Transform<T> transform
    ) {
        for (
            ListIterator<T> iter = values.listIterator();
            T value = iter.next();
        ) {
            iter.set(transform.transform(value));
        }
    }
...
        List<Integer> values = Arrays.asList(new Integer[] {
                1, 2, 3, 4, 5
        });
        transform(values, new Transform<Integer>() {
                public Integer transform(Integer value) {
                    return value+1;
                }
        });
        System.out.println(values);

I have used List instead of Collection, because Collection doesn't
provide a ListIterator and it's not an entirely sensible operation to
perform on a set anyway.

As you can see, abstracting loops is not a particularly natural thing to
do in Java. After splitting the method, my example is only one line
shorter and indents three levels instead of one. The inner class can
only reference final variables of the enclosing method. So it isn't done
very often in Java, at the moment.

There are various proposals to make things simpler in Java 7. These will
allow something like:

        // BGGA
        transform(values) {
            Integer value => value+1
        }

        transform(values, { Integer value => value+1 });

        // CICE (possibly without the <Integer>).
        transform(values, Transform<Integer>(Integer value) {
                return value+1;
        });

        // My favourite:
        transform(values, new()(Integer value) {
                return value+1;
        });

Tom Hawtin
Daniel Pitts - 13 Jan 2007 01:28 GMT
> In my native language, PHP, we have a function called array_walk()
> http://www.php.net/manual/en/function.array-walk.php
[quoted text clipped - 20 lines]
> Thanx
> Phil
Java doesn't exactly have closures, so its hard to do stuff like what
your asking.. However, what you really want is:

Replacing "doChange" with whatever is appropriate.

You COULD make a utility class that does this for you:

public interface Transformer {
   Object transform(Object o);
}

public class ListWalker {
 public static void walk(List myList, Transformer transformer) {
   ListIterator iterator = myList.listIterator();
   while (iterator.hasNext()) {
       iterator.set( transformer.transform(iterator.next()) );
   }
}

Now you can call:
ListWalker.walk(myList, new Transformer() {
   public Object transform(Object o) {
        return new Integer(((Integer)o).intValue() + 1);
   }
});

Ick... Did I just write that?
Well, you can't do little "tricks" with Java like you can in PHP, but
don't worry about that too much.
RedGrittyBrick - 13 Jan 2007 12:51 GMT
>> In my native language, PHP, we have a function called array_walk()
>> That will walk through an array and perform change on every element in
[quoted text clipped - 19 lines]
>
> Ick... Did I just write that?

It might be less icky using generics?

interface Transformer<T> {
    T transform(T o);
}

ListWalker.walk(myList, new Transformer<Integer>() {
    public Integer transform(Integer i) { return i+1; }
});
Lew - 13 Jan 2007 17:15 GMT
As so many on this thread have pointed out, Java can do what closures do, you
just have to think in terms of object-orientation and polymorphism instead of
interpreted, loosey-goosey self-rewriting code.

Many have argued for closures in Java. I am against them for the moment, since
there are already idioms that accomplish the same thing without the conceptual
mindtwist. Once again, that would be polymorphism, possibly with inner or
anonymous classes, combined with generics to provide compile-time safety.

Java is a professional language, not a script-kiddie hack language. Things
like program invariants, compile-time safety and maintainability carry weight
here.

- Lew
Arne Vajhøj - 14 Jan 2007 01:46 GMT
> As so many on this thread have pointed out, Java can do what closures
> do, you just have to think in terms of object-orientation and
[quoted text clipped - 9 lines]
> Things like program invariants, compile-time safety and maintainability
> carry weight here.

I do not think it is fair to call closures a "script-kiddie
hack language" feature.

It is a language feature with some merits.

Arne

PS: I am also against adding closures to Java, but that
    is strictly to keep the size of the Java language
    down.
Lew - 14 Jan 2007 02:58 GMT
(followup set to clj.programmer, as we proceed into a little more theoretical
domain.)

> I do not think it is fair to call closures a "script-kiddie
> hack language" feature.
>
> It is a language feature with some merits.

You are right. However, when something like "eval" (or "evil", per Mark Rafn)
combines with dynamic typing and a few other things that interpreted languages
sport, you start to see some tangled code.

Anyhow, my invective aside, you can accomplish the same effect, more or less,
as closures using polymorphism over an interface, as suggested by Tom Hawtin
for example. I believe the formal term is a "functor" class.

- Lew
Daniel Pitts - 14 Jan 2007 17:37 GMT
> As so many on this thread have pointed out, Java can do what closures do, you
> just have to think in terms of object-orientation and polymorphism instead of
[quoted text clipped - 10 lines]
>
> - Lew

True, but what would be the harm in having an interface:

public interface Closure<R, P> {
   R execute(P);
}

and a new language feature:

public <T> void methodWhichTakesClosure(Closure<T, T> closure);
...
methodWhichTakesClosure(closure<Integer, Integer>{return arg+1; });
which would be equivalent to:
methodWhichTakesClosure(new Closure<Integer, Integer>() {
   Integer execute(Integer arg) {
     return arg + 1;
  }
});

Anything that makes the intention of the calling code clearer is a Good
Thing(TM) in my opinion, and its just as type safe.

While we're adding keywords and language features, maybe a shortcut to
"Runnable" or "Callable" would be a useful idiom as well.

SwingUtilities.invokeLater(runnable{updateGuiWith(results);});
Lew - 14 Jan 2007 19:45 GMT
> True, but what would be the harm in having an interface:
>
> public interface Closure<R, P> {
>     R execute(P);
> }

This already exists.

> and a new language feature:
>
[quoted text clipped - 7 lines]
>    }
> });

This just looks like syntactic sugar, much like the enhanced for-loop. If you
think

closure<Integer, Integer> { return arg+1; }

which to my eye lacks any resemblance to a method signature that can be
enforce, is clearer than

new Closure<Integer, Integer>()
{
   Integer execute(Integer arg)
   {
     return arg + 1;
   }
}

than I see why you favor it. To me, the latter form is much more explicit and
plenty easy to understand, and leaves less to guess than the first format.

> Anything that makes the intention of the calling code clearer is a Good
> Thing(TM) in my opinion, and its [sic] just as type safe.

I agree that clearer is better, but not that your closure form is clearer.

> While we're adding keywords and language features, maybe a shortcut to
> "Runnable" or "Callable" would be a useful idiom as well.
>
> SwingUtilities.invokeLater(runnable{updateGuiWith(results);});

I have the same objections. I cannot tell how the syntax here tells me what
exactly is happening, whereas the "new Runnable() { public void run(){...} }"
syntax reveals all and hides nothing. To me, the existing Java syntax is
clearer, and therefore by our common principle of "clearer is a Good Thing" we
should stick with what we've got.

- Lew
Arne Vajhøj - 14 Jan 2007 20:31 GMT
 >> and a new language feature:

>> public <T> void methodWhichTakesClosure(Closure<T, T> closure);
>> ...
[quoted text clipped - 7 lines]
>
> This just looks like syntactic sugar, much like the enhanced for-loop.

Ofcourse.

In the end the entire Java language is syntactic sugar
over the instruction set on the system you run your app on.

The question is: does the code become sufficient easier to
write & read and will it be used frequently enough to warrant
an extension to the language.

It is not free to make he language bigger and more complex.
We know how PL/I and Ada ended up.

I doubth it is worth it for closures.

Arne
Lasse Reichstein Nielsen - 14 Jan 2007 23:54 GMT
> As so many on this thread have pointed out, Java can do what closures
> do, you just have to think in terms of object-orientation and
> polymorphism instead of interpreted, loosey-goosey self-rewriting code.

Having closures in a language is completely unrelated to being
interpreted, loosely typed, or otherwise "unproffessionel".  Take a
language like Haskel, which has a very string, but also powerful, type
system. It's functional though, which is where closures typically
occour.

> Many have argued for closures in Java. I am against them for the
> moment, since there are already idioms that accomplish the same thing
> without the conceptual mindtwist.

For someone used to programming in functional languages, the
conceptual mindtwist comes when you try to express a perfectly simple
anonymous function value as an object of some unnecessary class or
interface. It's just syntactic wrapping necessary to live in a language
where only objects (and primitives) are expressible and denotable objects.

The argument for closures isn't really about functionality, which
is there already, but about syntax. Just as enums were added to provide
simpler syntax for a commonly occuring programming construct, simpler
syntax could be provided for function values.

Simpler syntax, like for enums, provides nothing but readability. It
makes it easier to express the programmers intent and easier to
recognize it for a reader. The more unnecessary syntax is wrapped
around the essential idea, the less accessible it is.

What is easier to read:

myCollection.foreach(new Callable<Integer>() {
   void call(Integer v) {
      sum += v;
   }
});

or

myCollection.foreach(fn(Integer v) { sum += v; });

> Once again, that would be polymorphism, possibly with inner or
> anonymous classes, combined with generics to provide compile-time
> safety.

It's quite possible. It's just so ... wordy.

> Java is a professional language, not a script-kiddie hack
> language. Things like program invariants, compile-time safety and
> maintainability carry weight here.

Which is why generics was a good addition (collections were untyped
before). And why syntactic sugar making often used idioms were made
easier to express: enums, iterations over iterables and arrays,
boxing and unboxing.
I happen to think that easier syntax for delegates, which is essentially
what is needed, would be great. Real closures capturing local variables
might not be necessary, but it would be nice.

/L
Signature

Lasse Reichstein Nielsen  -  lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
 'Faith without judgement merely degrades the spirit divine.'

gafter - 15 Jan 2007 01:12 GMT
> As so many on this thread have pointed out, Java can do what closures do...
>
> Many have argued for closures in Java. I am against them for the moment, since
> there are already idioms that accomplish the same thing without the conceptual
> mindtwist...

Actually, you can't do without closures what you can do with them; they
actualy reduce the conceptual mindtwist.  Admittedly, you may have to
learn something.

See
http://www.bejug.org/confluenceBeJUG/display/PARLEYS/Closures+for+Java
pkriens - 15 Jan 2007 06:51 GMT
Right! programming should be hard so only real men can do it! All this
sissy stuff of auto-boxing and foreach loops.

Kind regards,

   Peter Kriens

> As so many on this thread have pointed out, Java can do what closures do, you
> just have to think in terms of object-orientation and polymorphism instead of
[quoted text clipped - 10 lines]
>
> - Lew
Kai Schwebke - 14 Jan 2007 14:06 GMT
phillip.s.powell@gmail.com schrieb:
> <?
>    $array = array(1, 2, 3, 4, 5);
[quoted text clipped - 3 lines]
>
> So how do I do this in Java?

As some have already pointed out this could be achieved
(quite verbose) using a callback-like anonymous class
implementing some interface.

Another option would be heading towards Groovy, a dynamic
language which runs on and interfaces well with the
Java platform.

Here comes a Groovy implementation of your PHP code:
--------------
array = [1, 2, 3, 4, 5]

array.collect {
  it = it+1
}
// returns [2, 3, 4, 5]
--------------

Or even shorter using a range:
--------------
(1..5).collect {
  it = it+1
}
// returns [2, 3, 4, 5]
--------------

Kai


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.