Win a copy of Practical SVG this week in the HTML/CSS/JavaScript forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Stream question

 
Paul Peterson
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I need help creating a stream to retrieve data from an ArrayList of objects.  For example there is an ArrayList of sales tax rates per state.  I am trying to find a stream that will extract the tax rate.  The state name is passed into the method as one of the parameters when the method is called.

Simplified class:

public State {
  String name;
  double taxRate;
}

The data for each state is stored in an ArrayList called stateInfo.

I am not very good with streams, but trying to figure them out.
 
Jeanne Boyarsky
author & internet detective
Marshal
Posts: 35752
412
Eclipse IDE Java VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul,
Remember that you need to have a source and terminal operation at a minimum. And you can have zero or more intermediate operations. You'll need one of those here.

Now try each piece.
1) Do you know how to turn your ArrayList<State> into a Stream<State>
2) Do you know how to *map* it into a Stream<Double>
3) Do you know how to turn the Stream<Double> into List<Double>
 
Paul Peterson
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My starting point was

double taxRate = stateInfo.stream().map

That's where I got messed up.  I tried to follow some of netBeans hints but only got more turned around.
 
Jeanne Boyarsky
author & internet detective
Marshal
Posts: 35752
412
Eclipse IDE Java VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul,
That's a good starting point. You have step 1 correct. For step 2, you have two choices

If you don't have a getter:


If you add a getter:


Either one maps a State to the tax rate.
 
Paul Peterson
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I do have a getter.  Will the state in the stream correspond to the value passed in as a parameter of the method?
 
Jeanne Boyarsky
author & internet detective
Marshal
Posts: 35752
412
Eclipse IDE Java VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes. The map method is called for each element in the stream in your example.
 
Carey Brown
Bartender
Posts: 2265
28
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Why streams? Seems like a HashMap would be much better.
 
Paul Peterson
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you.  I will work with this in the morning.  Had to get away from the computer.  I've been perched in front of it for more than 10 hrs today.
 
Campbell Ritchie
Marshal
Posts: 52621
119
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There are tutorials in the Java™ Tutorials; maybe the section about the List interface will tell you something. You can also see some examples in the Stream documentation. But you will find out a lot more if you get your hands on a book like Mastering Lambdas by Maurice Naftalin or Java 8 for the Really Impatient by Cay Horstmann or Java 8 in Action by Urma Fusco and Mycroft. Beware: Horstmann has written two different books with similar titles. Make sure to get the one which describes Streams.
Basically, there are all sorts of things which can create a Stream. Some classes have stream() methods. The Collection interface has this, which means your List has the same method. Other examples: for CharSequence (or String), for BufferedReader and one of many for Random, and for Arrays there are also several methods. The interfaces also have methods called of or similar which are factory methods.
I suggest you use Eclipse or some other IDE with help about methods. What you do is write some incomplete code like this:-
myList.stream();
which will probably compile but won't do anything useful. Then you hover your mouse on the name of the method and Eclipse will show you the details. You are probably particularly interested in the return type, which will be something like Stream<State>. You can do the same for every method call and see what sort of Stream you are creating.

You should design your State class along proper OO lines and give it get methods for each of the fields. Also a constructor. Now with generous use of the final keyword, you can make that class immutable.

Follow each call with .peek(System.out::println); you will see what values are passing through the Streams and when they are being handled. You will see that nothing goes into the top end of a Stream until the Stream at the bottom is ready to use it; Stream use lazy execution.
As an alternative to the map call try mapToDouble(myState::getTaxRate). See what happens.

Note that each method in a Stream is called an intermediate operation or a terminal operation. You can find out more by clicking the links of those names in the method documentation, but basically an intermediate operation returns another Stream and a terminal operation returns something else (or is void). You will probably find nothing actually happens until you try running a terminal operation, because of lazy execution.
 
Paul Peterson
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for all of your help and guidance.  I think I am closer now.  Or at least NetBeans stopped screaming at me.  I am still struggling with the stream, but found one way that returns the results.  I just need to convert this to a stream.



I tried writing the stream like this, but kept getting that lovely little red !
 
Carey Brown
Bartender
Posts: 2265
28
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Using a Map there is no iteration required.
 
Paul Peterson
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for that suggestion.  That will work for this instance.  The reason I used an ArrayList of objects is that I have another similar search that needs two data elements from the object.  For example, I have another collection of Product objects in an ArrayList.  I need the unit and labor prices associated with that object.  Could I use the getters in the object's class using the method you described?
 
Carey Brown
Bartender
Posts: 2265
28
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"Value" here is now "State" instead of "Double".
 
Campbell Ritchie
Marshal
Posts: 52621
119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Peterson wrote:. . . I tried writing the stream like this, but kept getting that lovely little red !
Start by indenting your code for Streams differently. Every method call goes on a new line and indent it so all the . operators align vertically. So your code will readDon't write all the code until you are more experienced. Write it bit by bit and compile after every line. As I said earlier, use an IDE to give you information about the resultant type of the expression on every line. If you hover the mouse on the words stream filter and map, you will get a popup box or tooltip with details of the method and the current return type.

Why are you using filter? That requires a Predicate as its argument, so you will only find that proportion of the Stream which matches that Predicate. You cannot get -> getTaxRate() to match that, because it is a double, not a boolean. I suspect you may not want filter() at all. Also why are you using t? That is a variable independent of the Stream, and I think it is not relevant.
If you ever get as far as the map call, hover your mouse over the map call and see what it says in the IDE. Probably Stream<Double> and all sorts of details about the map method, maybe copied from the documentation for that same method. Now you can see that you cannot turn a Stream<Double> into a double however hard you try. What do you actually want to do? There are all sorts of things you can do with this Stream, like putting the Doubles into a List, calculating the max/min/average (better done with mapToDouble), printing all rates, etc., but one thing you cannot do is turn it into a single double. You will have to think again if you want a single double.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!