Win a copy of Production-Ready Serverless (Operational Best Practices) this week in the Cloud/Virtualization forum!
    Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Junilu Lacar
  • Paul Clapham
  • Knute Snortum
Saloon Keepers:
  • Stephan van Hulst
  • Ron McLeod
  • Tim Moores
  • salvin francis
  • Carey Brown
Bartenders:
  • Tim Holloway
  • Frits Walraven
  • Vijitha Kumara

Why are beginners not familiar with Streams?  RSS feed

 
Marshal
Posts: 63777
209
  • Likes 3
  • Mark post as helpful
  • send pies
  • Report post to moderator
Why do people think the Streams API is only suitable for advanced people? Think how easy that would be:-
 
Sheriff
Posts: 13343
221
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Report post to moderator
I don't know, Campbell, but yours is a great example of the power of Streams and functional style programming in Java.

You also chose better expressive names in your example.
 
Rancher
Posts: 3109
110
  • Likes 6
  • Mark post as helpful
  • send pies
  • Report post to moderator

Campbell Ritchie wrote:Why do people think the Streams API is only suitable for advanced people? Think how easy that would be:-


Please explain why this should be easy for beginners. My experience is that getting acquainted with streams and lambda's and method references is not easy at all.
 
Rancher
Posts: 3983
47
  • Likes 2
  • Mark post as helpful
  • send pies
  • Report post to moderator
I would suggest it's not necessarily "easy" for someone who has started learning and already knows about iterating over things (and so already has a picture of how this sort of thing works), but I suspect for someone truly new to the whole thing that streams is no harder than loops.

To describe Campbell's code:
Get a stream for the array
filter it on this criteria
get the name from the filtered values
Turn them into an array.

That strikes me as (if anything) less complex to get your head around than trying to describe how various types of loop work.
 
Junilu Lacar
Sheriff
Posts: 13343
221
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Report post to moderator
One guess is as good as any, I suppose, since none of us (everyone who has contributed to the discussion so far, that is) are really beginners. Only true beginners can say whether or not it's easy for them to grok. I suspect that would also depend a lot on how the concepts were explained to them. I can see it going either way.

One could explain it visually, which I think would be my approach. It could probably be explained in mathematical terms, too. After all, it is functional style programming. I don't know if it helps to have an idea of how iteration with loops works or not either. Again, knowing how loops work could facilitate or impede learning, depending on how your brain processes the new information about streams and pipes.

It certainly would be an interesting subject for further research and experimentation though.
 
Saloon Keeper
Posts: 9979
206
  • Likes 1
  • Mark post as helpful
  • send pies
  • Report post to moderator
Agree with Campbell. Functional approaches are much more natural for data transformations, and we only think of streams as hard, because we're so used to imperative programming.

For some purposes, imperative programming is easier. This is often the case when timing of operations is important, as in I/O. Functional programming purists will tout their monads, but have no qualms writing what's essentially imperative code in do-notation.

The fact is, neither approach is inherently more difficult. They're just better suited at some jobs.
 
Junilu Lacar
Sheriff
Posts: 13343
221
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 2
  • Mark post as helpful
  • send pies
  • Report post to moderator

Stephan van Hulst wrote:Agree with Campbell. Functional approaches are much more natural for data transformations, and we only think of streams as hard, because we're so used to imperative programming.


I was introduced to functional style programming through Scala. Honestly, I could almost literally feel my mind bending as I struggled to break free from the bounds of imperative style thinking. It makes me think of the backwards brain bicycle again and wonder whether it might have been easier for me to wrap my head around those new concepts had my brain not already been used to imperative style thinking and problem solving.

Thinking back on own experience, the shift from procedural programming to object-oriented programming seemed much more natural to me. Going from imperative to functional seemed much more difficult. One colleague of mine likens it to trying to learn how to snowboard when you already know how to ski well. I guess a lot of skiers have a hard time making the shift. I wouldn't know because I don't know how to do either of them.
 
Stephan van Hulst
Saloon Keeper
Posts: 9979
206
  • Mark post as helpful
  • send pies
  • Report post to moderator
That's a nice analogy. I'm a fairly okay skier now, but it took me a lot of falling down to get there. Then I tried snowboarding a few times and I really had a hard time with it.

What's funny for me is that when I had my first class in functional programming, I immediately grokked it for some reason. I had a much MUCH harder time learning object oriented programming, because I really didn't understand what made objects different from records, and constructors different from procedures.
 
Campbell Ritchie
Marshal
Posts: 63777
209
  • Likes 2
  • Mark post as helpful
  • send pies
  • Report post to moderator
First things first: thank you for the cow whoever it was

Then, I thought we had such a big digression from the original threa‍d's topic that I ought to split much of this thre‍ad.

I seem to have stirred things up a bit, but I'm not worrying. You get better discussions like that. This is how I was taught to populate an int[]:- [edit]This was before Streams[/edit]Nowadays I would have no hesitation in saying you do it like this:-Five lines cut down to two, and the resultant array is exactly the right size without anybody needing to take care about a loop.

I can think of various reasons why people are not taught Streams early:-
  • 1: The teachers aren't familiar with Streams.
  • 2: Seeing them in scary advanced books like Part II of Cay Horstmann's Big Core Java Book makes them look more difficult than they really are.
  • 3: Loops are considered a basic control structure, so it is necessary to teach people about loops.
  • Five years ago, I wasn't a beginner in Streams. In fact I hadn't heard about that sort of Stream. I had only used λs in theory and in Forth (we have a version of Forth which not only supports reversibility, but also supports a few functional features). I thought a method reference was something you see in C with *foo(...) in, and I couldn't remember how to write such pointers. I had to learn from a few Devoxx talks, books like Urma Fusco and Mycroft, and fights with the compiler . Then I went to my supervisor's Programming Club on Thursday afternoons and met 2nd year undergraduates who could write IntStream.generate(...) as quickly as they could write for (int i = 0; i < something; i++) ... That tells me that it is quite possible to teach students at least the basics of using Threads. But, as Piet says, it takes time. If AY's teachers considered Streams a basic programming tool, just as they considers Lists a basic tool, she might be able to think of a Stream as a solution.

    Yes, there are some people who can grasp OO programming or functional programming really quickly, and some for whom learning paradigm A is a real hindrance to learning paradigm B. Also, if this website is supposed to be teaching beginners, we ought to show them Streams as an alternative. And Piet is right if he means we should start with things simple.
     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator

    Half an hour ago, I wrote:. . .  it is quite possible to teach students at least the basics of using Threads. . . .

    T-h-r-e-a-d-s?? That is the worst spelling of Streams I have ever seen. But it still has the three middle letters right
     
    lowercase baba
    Posts: 12734
    51
    Chrome Java Linux
    • Likes 2
    • Mark post as helpful
    • send pies
    • Report post to moderator

    Campbell Ritchie wrote:


    what about this?

    Five lines cut down to two.

    Besides, didn't we realize years ago that measuring by lines of code is not the right way to go?

     
    Junilu Lacar
    Sheriff
    Posts: 13343
    221
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Report post to moderator
    It's true though, it's not so much about the number of lines of code as it is the level of abstraction. In the imperative code, all the nitty-gritty implementation details are there in your face. It's like those engines that have portions of the block cut away so you can see what's going on with the pistons and the valves. With the functional style code, you just see the car going from point A to point C via point B. It's implementation vs. intent.
     
    Junilu Lacar
    Sheriff
    Posts: 13343
    221
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Report post to moderator
    I think part of it is also us being used to and comfortable with certain idioms. When I see "from 0 to 100" the first thing that comes to mind is still a for-loop. I'd have to consciously retrain myself to think of the functional style idiom of stream.range(0, 100) instead. It's a matter of practice, really, and doing that so it becomes your new intuition.
     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Mark post as helpful
    • send pies
    • Report post to moderator

    Junilu Lacar wrote:. . . . When I see "from 0 to 100" the first thing that comes to mind is still a for-loop. . . .

    Remembering that it is really 0...<100; both IntStream.range() and the standard idiom of a for loop would run up to 99 inclusive. otherwise you get Fred's off‑by‑error.
    Get yourselves a copy of “A Practical Theory of Programming” by Eric Hehner; he thinks along the lines of 0...<100; and even has his Preface called Chapter 0.
     
    Saloon Keeper
    Posts: 5326
    143
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator
    Getting back to the original question, I think a large part of it is the lack of elapsed time since streams were introduced. Good learning resources must be created, teachers need to learn it, syllabuses need to be adapted and then adopted, etc.

    People still ask questions here about applets which they got from their teachers. Care to take a guess when streams might be standard in a Java beginner's curriculum?
     
    Junilu Lacar
    Sheriff
    Posts: 13343
    221
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Report post to moderator
    And that's the problem: there seem to be fewer teachers who stay up to date with new development than those who don't. I don't know if there's a simple answer to this problem though. It could be that there are too many hoops to jump through in order to make drastic changes to course designs and lesson plans. We could be cynical and fall back on the old "Those who can.. those who can't" adage but that's not helpful. I'm really for the idea of getting academia to collaborate more with industry. I think that would move the needle towards narrowing the gap.
     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Mark post as helpful
    • send pies
    • Report post to moderator

    Junilu Lacar wrote:. . . "Those who can.. those who can't" adage . . .

    Who said that originally? It is horribly inaccurate; teaching is just as much a skill as “doing”.

    getting academia to collaborate more with industry. I think that would move the needle towards narrowing the gap.

    We have had some bad experiences here; you are liable to fnd companies saying, “We want graduates who can use XYZ,” so teaching proper computer sciences has taken second place to teaching XYZ. I think that sort of thing will vary from place to place doubtless other people have had no such problems at all.
     
    Junilu Lacar
    Sheriff
    Posts: 13343
    221
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator
    I think there have already been others in the past who have pointed out that we should be careful not to conflate Computer Science with learning how to program. Programming is certainly a skill that is essential to learn about CS but it's just one of many skills. We should also differentiate between CS and the discipline and practice of software development.
     
    Junilu Lacar
    Sheriff
    Posts: 13343
    221
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Report post to moderator

    Campbell Ritchie wrote:

    Junilu Lacar wrote:. . . "Those who can.. those who can't" adage . . .

    Who said that originally? It is horribly inaccurate; teaching is just as much a skill as “doing”


    I agree it shouldn't be used as a general characterization because that would be unfair to many, including quite a few people who frequent this site and contribute. On the other hand, if we're being honest, there are certainly cases where it's true.
     
    Author
    Posts: 18
    10
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator
    Campbell,
    Thanks for starting this thread!
    While writing my Get Programming with Java book for Manning, I wasn't sure where to include Streams.  I think Lambda and Streams are a great addition to Java, but I also agree with some of the other comments that they can be intimidating, they don't look like other Java statements (they do look like Scala   )

    Personally, I think learning how to write statements without Stream and then introducing it later, allows readers to benefit from the understanding of the underlying process that is taking place.   It reminds me of how much my students love to learn the shortcut in NetBeans for typing the print statement.  They learn to type out: , but not everyone has good typing skills, and since Java is case sensitive, it can cause some irritation until they learn to type followed by tab key and it automatically expands.  

    So, I have Streams in my TOC but it is later in the book.  

    Thanks again!
    Peg
     
    Saloon Keeper
    Posts: 2177
    92
    Eclipse IDE Google Web Toolkit Java
    • Likes 3
    • Mark post as helpful
    • send pies
    • Report post to moderator
    Let me look at this from a complete fresher's point of view:

    Specifically line 3:
    For a fresher to understand this statement, he/she need to be clear about the following concepts:
  • Method Chaining: i.e. How stream(), filter(), map() are working in unison here
  • What kind of input filter() method takes? What's a predicate ?  
  • Inheritance: Why cant we simply write .filter(new Predicate()) here
  • Generics
  • What's an anonymous class ?
  • That arrow "->" shows that it's a lambda expression, what a lambda expression ?
  • Code blocks: Why is it possible to omit braces in "p.getPrice() < 100.00"
  • Whats a functional interface ?
  • Whats an interface ?


  • Additionally, "Phone::getName" is a method reference because of the "::", this too requires the above list as well as how method references work. The fact that one can create an object using new, call a static method, call a method directly using method references is sometimes confusion to a fresher.

    Many freshers are not fully aware of how anonymous class work.
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 9979
    206
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator
    These concepts are not difficult if you learn them as idioms first, before learning how they work internally. For instance, when you start learning imperative programming, do you ask yourself how an if-statement works internally, or do you just accept it for what it is and run with it?

    Just like how a beginner doesn't need to know that an if-statement is implemented through jump operations, they don't need to know that evaluation of a lambda expression yields an object that implements a functional interface. Just accept the idiom.

    The reason why it seems more difficult, is because you're looking at it from the perspective of an experienced Java developer. I can tell you that mathematicians have a much harder time understanding if- and for-statements than they have understanding map and filter operations. The whole concept of a statement is simply more difficult to them than the concept of an operation.
     
    Junilu Lacar
    Sheriff
    Posts: 13343
    221
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator
    Precisely what Stephan said.

    Here's how I would use an intent-based approach to teach the use of Streams.

    Start with an image of a bucket with some things in it, say some marbles. Imagine we're able to attach a hose to the bottom of the bucket and start letting the marbles stream out through the hose, one at a time. Let's suppose the diameter of the hose is just big enough to fit one marble and that the marbles are frictionless so they don't get stuck in the hose and just freely flow through it. Keep this image in mind because Streams of objects behave a lot like this.

    Consider this code:

    This is how you would create a stream of numbers. Here, numbers is a stream of Integer objects that is created by the IntStream.of() method. Right now, this stream just sits there waiting for us to do something with it, much like a bucket that we have just filled with marbles.

    Now let's do something with this bucket, er, stream of Integers. Let's print out its contents.

    Here's how you'd do that:

    The easiest way to actually see how this works is to run these commands in JShell.

    Here's what it looks like when I run them in JShell on my machine:

    (explain how the forEach() method and the System.out::println method reference works ...)

    Now, can you guess what happens if we try to run the last command again? Do you think we'll see the same output?

    Let's see what happens when we try:

    This error message is basically telling you, "Hey, you already emptied all the Integers out of this stream; there's nothing in it anymore!"

    This is pretty much like a bucket of marbles, right? You can't attach another hose to the bucket and expect more marbles to stream out when you've already streamed them out before!

    ... and so on

    You can keep going with this, adding on filter, map, etc., and introducing each concept incrementally, building on what they have already learned.
     
    Piet Souris
    Rancher
    Posts: 3109
    110
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator
    Many replies make it clear that streams are powerfull, and I agree. But what I meant with my remark that it is not easy at all is this:

    if you look at the original topic, and the image of OP's code, you see that OP uses a very natural way to get the requested result:

    1) determine the number of elements that meet the requirement
    2) create an array of that size
    3) put the matching elelemnts into that array

    Absolutely nothing wrong with this, and easy to follow and implement. Nevertheless the question was whether we can help OP getting the mistakes out and maybe rewriting the code. Now, if this is already giving some problems, then using Campbells Stream is much more difficult, because of the different way of thinking that is required, and that the syntax is very different from what a beginner has learnt. In this respect I fuly agree with Campbell and Peggy: it takes time and practice (but it is time and effort very well spent).

    But simple Streams like this are not that difficult. I agree with Stephan that it is the collect part that is pretty demanding, not helped by a hard to read API.

    Anyway, to see if it IS that simple, why not get both groups for the price of one:
    Is this simple? If not, then where is the border between easy and difficult?

     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Mark post as helpful
    • send pies
    • Report post to moderator

    Peggy Fisher wrote:Campbell,
    Thanks for starting this thread!  . . .

    That's a pleasure (), but I didn't really start this thre‍ad. There was something in Ana Yo's thre‍ad which looked like a candidate for a Stream solution, so I posted it, and next thing I knew, there were all these replies. So I split part of the discussion off.

    If I were teaching, I might say that the old way to populate an array is with a loop, but the current way uses Streams. Introduce my code with IntStream#range() early, and condense it to one line to keep Fred quiet I'd explain that a Stream has a source of information, and it processes it; this is a special case where the Stream interface provides its own sources of data. I'd say that the toArray() method consumes the Stream and it then cannot be used again. I'd say that IntStream's toArray() method is specially easy to work with because there is no need to specify the type of resultant array: this can only be an int[]. Then I'd say that there is more about Streams on page 56789.
    They still need to know about loops; I shall leave it to you whether you use those irritating programs to draw triangles of *s to teach loops with.
     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Mark post as helpful
    • send pies
    • Report post to moderator

    salvin francis wrote:Let me look at this from a complete fresher's point of view: . . .

    All good points, Salvin. But why aren't students taught those things? Start with populating an int[], which is just about the simplest Stream application I can think of, and later add more details. Even something daft like this can be used for useful teaching:-You might not write such code in real life, but you can use that to teach method chaining and lazy execution. Build up the use of Streams and λs gradually.
     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Mark post as helpful
    • send pies
    • Report post to moderator

    Tim Moores wrote:. . . lack of elapsed time since streams were introduced. . . .

    Nearly five years.
     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Mark post as helpful
    • send pies
    • Report post to moderator
    I waited until AY had handed in her exercise before posting anything with Streams.

    Piet Souris wrote:. . .
    1) determine the number of elements that meet the requirement
    2) create an array of that size
    3) put the matching elelemnts into that array
    . . .

    If you really are going to create an array of the same size, you would have to iterate the phones array twice, once to count the matching elements and once to collect them. A Stream does the counting for you, and produces the right size of array without needing more instructions. You could do the same with a List, but AY has to create an array.
    No, I don't think partitioningBy() is difficult to use, but it takes a bit of thought that you get your cheap List<Phone> with phonesSplitBy100.get(false)! As Stephan says, you have to get used to that particular idiom.
     
    Dave Tolls
    Rancher
    Posts: 3983
    47
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator

    Campbell Ritchie wrote:

    Tim Moores wrote:. . . lack of elapsed time since streams were introduced. . . .

    Nearly five years.



    A drop in the ocean when talking about people teaching in colleges.
    Hell, there are companies that have only recently taken to 8...
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 9979
    206
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator
    Honestly, companies have better reasons not to switch. It's not only easier to update a programming course, but there's also little excuse to pass knowledge to students that's already out of date when they go out into the real world.
     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Mark post as helpful
    • send pies
    • Report post to moderator
    The more I see on this forum, the more reason I have to be grateful to peole like Elizabeth Norval who taught me, and who were actually up to date. She taught me applets, which were still considered current 15 years ago.
     
    salvin francis
    Saloon Keeper
    Posts: 2177
    92
    Eclipse IDE Google Web Toolkit Java
    • Mark post as helpful
    • send pies
    • Report post to moderator
    Idioms are good, they enable one to conceptualize what is happening. If an idiom is strong enough to hold true for all use-cases, then they should definitely be used to learn the concepts.

    Having said that, an idiom can help a programmer understand the behavior, they don't give them structural in-sight about code. A fresher who understood the idiom can also write our above code as :
    and then keep trying to figure out why it's not working. This is where semantics and language structure comes into place.

    In https://docs.oracle.com/javase/tutorial/java/javaOO/index.html, I see that Lambdas are covered under "Classes and Objects". This is covered after the programmer has understood: Methods, Constructors, Anonymous class, etc..
    Streams demonstrated are a part of the "Aggregate Operations" under "Collections" which is way ahead.

    I was surprised to see that "Interfaces and Inheritance " was introduced a bit later in the trail.

    This leads to my original point: There are a lot of concepts that one should learn before diving into streams.
     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Likes 1
    • Mark post as helpful
    • send pies
    • Report post to moderator

    salvin francis wrote:. . . There are a lot of concepts that one should learn before diving into streams.

    But you can paddle in streams before learning all those concepts.
     
    Campbell Ritchie
    Marshal
    Posts: 63777
    209
    • Likes 2
    • Mark post as helpful
    • send pies
    • Report post to moderator

    A few minutes ago, I wrote:. . . But you can paddle in streams before learning all those concepts.

    Start with simple things like what I showed on Thursday (this post in this thre‍ad); explain that you need a source of information, that unusually here the Stream is providing its own source of information, that you mustn't alter that source nor use the same Stream twice, that Stream methods might produce a new Stream or something else, and that there is lots more to learn about Streams but it is too early to go into all the details yet.
    When you introduce loops, you can point out that Streams make many loops redundant; in real‑life programming you can replace maybe ⅔ of loops by Streams. Because a Stream instance is an object, you are introducing a new kind of object before a new control structure.
     
    WHAT is your favorite color? Blue, no yellow, ahhhhhhh! Tiny ad:
    global solutions you can do in your home or backyard
    https://coderanch.com/t/708587/global-solutions-home-backyard
      Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!