London Lambdas Hackday: Developer Practices
Brian Goetz
brian.goetz at oracle.com
Tue Jul 3 23:09:52 PDT 2012
For those that like to debug with printf, a "tee()" method in the chain
can help:
list.filter(...)
.tee(System.out::println)
.map(...)
On 7/4/2012 1:49 AM, Howard Lovatt wrote:
> Re. Chaining
>
> I personally like the chaining style (particularly with the dots lined
> up). However, I have found it a pain with the Netbeans debugger because
> you can't see the intermediate results. This has often caused me to
> introduce variables for all the steps and to return the final
> array separately (so I can see what is happening).
>
> Any idea if IDEs and the underlying connection to the JVM will be
> updated to support seeing intermediates?
>
> On 4 July 2012 01:13, Brian Goetz <brian.goetz at oracle.com
> <mailto:brian.goetz at oracle.com>> wrote:
>
> > 1. addAll vs into
> >
> > A developer had an interable that he wanted to put all the values
> from
> > into a collection. He tried to use addAll, but it works over a
> > collection, not an iterable. He could have used into and flipped
> > dispatch object with the argument, but it wasn't obvious to do that.
> > This might be just a case of 'old habits die hard' but it might also
> > be
>
> Whatever we do here will change when streams are more Iterator-like and
> less Iterable-like. (This is a big theme for the next round of API
> design, currently in progress in a branch, which should be rolled out
> hopefully soon.) Would a Stream.concat(otherStream) method do what you
> were thinking of?
>
> > 3. Some feedback from Martijn:
> >
> > I noticed that I happily started using a chaining idiom in my
> code, e.g.
> >
> > return students.filter(student -> student.getAge() > 18).into(new
> > ArrayList<>());
> >
> > Given my lack of recent functional programming expertise, I think
> this
> > is a good thing. But I'm a little concerned that the chaining idiom
> > becomes hard to read for non-functional programmers, some education
> > might be required. Perhaps in the educational material, samples are
> > laid out like so (each 'chained' method is lined up with the method
> > before it):
> >
> > return students.filter(student -> student.getAge() > 18)
> > .into(new ArrayList<>());
>
> Absolutely. In all our sample code, we use one method per line, with
> the dots lining up. IDEs mostly support this.
>
> > You might also find Java developers wanting to pull everything back
> > into a local variable, e.g.:
> >
> > List<Student> filteredStudents = new ArrayList<>()
> > return students.filter(student -> student.getAge() >
> 18).into(filteredStudents);
>
> This is a common first impulse of Java developers -- give everything a
> name -- but will probably be overused until people get comfortable with
> chaining. A major design goal for these libraries has been to enable
> getting rid of the "garbage intermediate variables". The farther
> between their declaration and use (say, if the chain in the above
> example were longer), the more problematic the garbage variables become.
>
> > Another example pulling the Predicate in locally:
> >
> > Predicate<Student> isLegal = (Student student) ->
> student.getAge() > 18;
> > return students.filter(isLegal).into(new ArrayList<Student>());
>
> If people want to do this for readability or reuse, that's fine. (If
> they think there is any performance benefit to it, they're mistaken;
> stateless lambda captures are optimized into constant loads.)
>
> > One other (unecessary?) idiom they might use is assigning back to a
> > collection that is the result of the filter/reduce/map/whatever,
> e.g.:
> >
> > List<Student> legalStudents = new ArrayList<>();
> > Predicate<Student> isLegal = (Student student) ->
> student.getAge() > 18;
> > legalStudents = students.filter(isLegal).into(legalStudents);
> > return legalStudents;
> > // as opposed to
> > // return students.filter(isLegal).into(legalStudents);
>
> Right. These will be hard habits for people to break.
>
> > 4. Type inference
> >
> > IDE or compiler support might be needed to teach developers that Java
> > is smarter than they think with regards to Type inference. For
> > example a refactor to do the following:
> >
> > // Predicate<Student> isAdult = (Student student) ->
> student.getAge() > 18;
> > // Can be written as:
> > Predicate<Student> isAdult = student -> student.getAge() > 18;
> >
> > Perhaps a -lint option on javac for this kind of thing would be
> > useful? I guess it ultimately depends on how the expected idiom for
> > writing this code works.
>
> I expect IDEs will auto-suggest for this.
>
> > 5. Function Composition
> >
> > There was a genuine desire from people to have function composition.
> > This was somewhat driven by people with experience of functional
> > programming in other languages, but there were still scenarios where
> > it seemed like the cleanest idiom. The lack of function types seems
> > to make it hard to introduce function composition in the general
> case,
> > but is there an expectation that composition methods will be provided
> > for all the functional core library interfaces?
>
> There is some very limited type-specific composition, such as
> Mapper.compose or Predicate.{and,or}. But I suspect whatever we might
> do in the area of general-purpose composition would be deeply
> disappointing to functies. So we're unlikely to do much here.
>
>
>
>
>
>
>
> --
> -- Howard.
>
More information about the lambda-dev
mailing list