As you notice this is yet another recursive algorithm. I notice several of you aren't comfortable with writing recursive code so I've made a new method for the upcoming jAlbum version that gathers all included descendants of an album object into a collection. All album objects can now be easily iterated. Here are some examples:
Print names of all album objects:

I'm very excited about this new getDescendants() call. It has the potential to allow parallel processing to significantly speed up lengthy operations on multiple album objects. I'll return with more examples when I've polished performance on this implementation further.

Thanks for testing guys. Now I'll optimize the internals a bit (and hopefully not break things) and rewrite some jAlbum External Tools and other internal jAlbum logic to use this API instead. There is really no downside to using this API compared to recursive code. It doesn't gather the whole list of all album objects in RAM. Instead, it walks the tree iteratively.

Most developers will probably appreciate the straight forward syntax. Here's a JavaScript example that prints all album object names:

for each(ao in rootFolder.getDescendants()) {
print(ao);
}

Here is the same code in Java/BeanShell:

for (ao : rootFolder.getDescendants()) {
System.out.println(ao);
}

You can also use the new cool Stream API of Java 8 to efficiently filter and perform various tasks on album objects using callback functions (aka "lambdas"). Here's a sample that prints the camera dates on all images (expensive operation as it needs to open each file):

The Stream API now splits the work of filtering images and gathering camera dates to multiple CPU cores / threads. This can have a significant impact on performance. If your source images resides on a network drive, you may expect performance gains of several hundred percent without having to manually dabble with thread coding.

In plain compiled Java, the equivalent code looks like this. Notice the short syntax:

davidekholm wrote:
If you want to use these callback methods in BeanShell you have to resort to using anonymous inner classes....

... which might wipe out the time saving. BeanShell's handling of anonymous inner classes is awful.

In a single-use case like this you might not run into any problems. But if you make extensive use of anonymous inner classes in onload.bsh, for example, skin loading takes forever. This is something TomCee and I discovered many years ago, when I started cleaning up the Matrix UI. Compiled? No problem. Interpreted BeanShell with anonymous inner classes? Skin loading was running over 30 seconds.