4

Lets say I have an array movies = get_movies()

In ruby I often do movies.map {|movie| movie.poster_image_url } or somesuch.

What can I do that is similar in Java? And by similarly elegant and terse and readable. I know there are a bazillion ways I can do this but if there's a nice way to do this that will make me not want to use Groovy or something let me know. I'm sure Java has some awesome ways to do things like this.

This is my Java code so far using TheMovieDB API Java wrapper from https://github.com/holgerbrandl/themoviedbapi/.

        TmdbMovies movies = new TmdbApi(BuildConfig.MOVIEDB_API_KEY).getMovies();
        MovieResultsPage results = movies.getPopularMovieList("en", 1);
        // The following line is RubyJava and needs to your help!
        results.getResults().map {|e| e.getPosterPath() };
        // or ... more RubyJava results.getResults().map(&:getPosterPath()); 

A little more about #map/#collect in Ruby in case you know a lot of Java, but aren't familiar with ruby. http://ruby-doc.org/core-1.9.3/Array.html#method-i-collect

Closest thing I've seen to answering this from some quick browsing so far... https://planet.jboss.org/post/java_developers_should_learn_ruby

These look close, too. http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

So many options: Functional Programming in Java

This is Android as well... Anything good things that are available for Android devs out of the box and make this kind of programming easy? This is a functional programming style, right?

--

After getting replies with really good insights like: 'there is nothing wrong with a for loop' and (basically) 'syntax isn't everything', I am deciding that I will not try to make all my Java look like Ruby! I read this and then imagined an alternate future where 'future me' made a whole bunch of bad style decisions: https://github.com/google/guava/wiki/FunctionalExplained. <-- (A good read. TL;DR 'when you go to preposterous lengths to make your code "a one-liner," the Guava team weeps')

Community
  • 1
  • 1
David West
  • 2,256
  • 6
  • 32
  • 62
  • 1
    You're looking for Java 8's java.util.stream, via something like `results.getResults().stream().map(MovieResult::getPosterPath).collect(Collectors.toList());`. It works best if you're doing a long chain of operations to amortize the .stream()/.collect(), or if you're going parallel with `.parallel()`. But really, there's nothing wrong with a for loop... – Jeffrey Bosboom Dec 20 '15 at 02:49

2 Answers2

5

There's the map method on streams which takes a method argument.

collection.stream()
  .map(obj -> obj.someMethod())
  .collect(Collectors.toList()));

map returns another stream so in order to retrieve the list you have call the collect method.

Too much to explain in a post, but you can visit this link which helped me out a lot:

http://winterbe.com/posts/2014/03/16/java-8-tutorial/

Quy
  • 1,343
  • 9
  • 11
  • can I condense that further? In ruby you can do `movies.map{|movie| movie.link}` or `movies.map(&:link)`. Something similar available? – David West Dec 20 '15 at 02:52
  • 1
    Unfortunately, that's as far as it goes. The only reason I was able to condense the lambda expression down that much was because I only had one argument and one statement. Otherwise, it would have looked like this: `(obj1, obj2,...objn) -> { statements; }` Java 8 somewhat makes methods or functions first class citizens by allowing you to pass methods around. You can also try that if you find the lambda expression too verbose, but it's trivial at that point – Quy Dec 20 '15 at 02:56
  • Thanks. It's still very nice. – David West Dec 20 '15 at 02:59
  • 2
    you could make this comparable to `%:link` with a function reference like `YourObject::someMethod`. @David: the whole stream thing is significantly better than what Ruby or Groovy will do (due to lazy eval), focusing on syntax is not the most important thing. – Nathan Hughes Dec 20 '15 at 03:00
  • 2
    Util.Stream is only since java 1.8 (Java8) and you won't get this on Android (until next google IO at the very earliest, _IF_ they add support for java8 to Android then) https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html – mawalker Dec 20 '15 at 03:09
  • Apologies, didn't see his edit. @mawalker is right. There's libraries that are kind of hacky like the one mentioned from mawalker. – Quy Dec 20 '15 at 04:04
0

I think (a collections class).foreach() is what you want, requires java8, and often makes use of lambda expressions to implement the class that fulfills the required input for the 'foreach()' method.

http://www.mkyong.com/java8/java-8-foreach-examples/


To address your change to that this is Android, then NO, you WILL NOT get java8 class changes such as .foreach(), you CAN get lambda expressions by making use of the retrolambda android variant. But this only gives you some Java8 'syntax' not 'classes', you won't get access to the Streams classes either.

mawalker
  • 2,072
  • 2
  • 22
  • 34
  • sounds good. Is there anything like forEach that returns the processed collection? Hope my question makes sense. I don't know enough Java yet to ask a good question probably. But what I like about the ruby methods #map and #collect are that they return the processed collection. – David West Dec 20 '15 at 02:48
  • 1
    Read my edit that addresses this being on android (spoiler: sorry for you, lol) – mawalker Dec 20 '15 at 02:50
  • 1
    foreach() makes use of the Iterable/Iterator interface/class, As such it can modify the collection in place, but it doesn't return anything. https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html – mawalker Dec 20 '15 at 02:53
  • are there worthwhile libraries I can add to my Gradle config? Google Guava was one I heard mentioned as good for fp type stuff... Reading more about retrolambda... – David West Dec 20 '15 at 02:54
  • I don't know about that, I don't use functional too much. It is in vogue, but Java8's implementation doesn't allow for the features I've seen shown off in "Functional" languages where you don't even know the 2nd or 3rd parameter for an argument until after its processed, etc. (I might be 'slightly' off with that explanation, since I've never written it myself). Java8's "functional" programming is mainly just syntax sugar – mawalker Dec 20 '15 at 03:00
  • And reading more about Guava. Glad I did! http://stackoverflow.com/questions/14978699/is-it-a-good-idea-to-use-google-guava-library-for-android-development – David West Dec 20 '15 at 03:02