aspose file tools*
The moose likes Beginning Java and the fly likes compare variables of an object Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Java 8 in Action this week in the Java 8 forum!
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "compare variables of an object" Watch "compare variables of an object" New topic
Author

compare variables of an object

eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
Hello,

I am working on a program for school. I am required to have the methods that are in my program. I also need to add three comparison methods to it. I just want to make sure I am on the right track before I attempt the comparison methods.
Thanks,
Eric

Here is what I have so far.
Mike Gershman
Ranch Hand

Joined: Mar 13, 2004
Posts: 1272
At a glance, your program looks technically correct, but your declaration of round() is misleading. If you are going to always operate on tempValue, change the method to:


Also, when you get a bad value, it's easier to test your program if you set the default value rather than calling System.exit().

Were you told to reject negative temperatures? That prevents the most inteesting test cases, like -459.67F = -273.15C = absolute zero.

Generally, nice work so far.
[ March 06, 2005: Message edited by: Mike Gershman ]

Mike Gershman
SCJP 1.4, SCWCD in process
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70

At a glance, your program looks technically correct, but your declaration of round() is misleading.

I'm not sure I know what you mean here.



Also, when you get a bad value, it's easier to test your program if you set the default value rather than calling System.exit().

Great idea. That makes more sense than having the user start the program over again.



Were you told to reject negative temperatures? That prevents the most inteesting test cases, like -459.67F = -273.15C = absolute zero.

No, I was using another example in my textbook when I wrote this. I am changing it to allow negative values. Thanks for catching that for me.

I appreciate all of this, it's encouraging to get some good advice.

Thanks!
Eric
[ March 06, 2005: Message edited by: eric elysia ]
Mike Gershman
Ranch Hand

Joined: Mar 13, 2004
Posts: 1272
Your declaration of round() has a formal argument and a return value, but you actually ignore the formal argument roundTempValue and instead use the instance variable tempValue. You return a result, but you also create a "side effect" by directly changing the instance variable tempValue within the method.

If you called round() with a different argument or assigned the method's result to a different variable, the result would not be what the method's header promises. Your code should always stick to the contract implied by the method header. If you can only understand what a method does by reading the implementation, that is bad object oriented design.

The reason your code works is that you call round() using the argument tempValue and you do not assign the returned value. Change how you use round() and you get a bug.
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
Your declaration of round() has a formal argument and a return value, but you actually ignore the formal argument roundTempValue and instead use the instance variable tempValue. You return a result, but you also create a "side effect" by directly changing the instance variable tempValue within the method.

A formal argument, meaning a parameter that is used in a method definition as a stand-in for a value that will be plugged in when the method is called.

If you called round() with a different argument or assigned the method's result to a different variable, the result would not be what the method's header promises. Your code should always stick to the contract implied by the method header. If you can only understand what a method does by reading the implementation, that is bad object oriented design.[/QUOITE]
That makes sense. The method and header should match up.

The reason your code works is that you call round() using the argument tempValue and you do not assign the returned value. Change how you use round() and you get a bug.

OK, I think I understand now. Since I am not using the returned value, my program is not giving me any errors.

Now, I am trying to implement three comparison methods. I am not quite sure if I am doing it right, because when I test for equality, the two values are always equal. Maybe I am just not writing the driver (main) correctly. Here is my code:



Thanks,
Eric
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Why return 0 when the temperature scale asked for is the same as the temperature? Why is that an error?

How did you fix the round() function? Looking at the constructors, it seems the rounded value is ignored.
Originally posted by eric elysia:
What happens if "this" is a fahrenheit temperature?
Why are you setting the values when you're passed them into the constructor?

Finally, since double's are approximate decimal values, you usually want to avoid testing with == but rather to see that the difference between them is "small enough" to consider them equal.

In any case, I don't immediately see what the problem is. I'd recommend addressing these issues before trying to figure it out, though.
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
Why return 0 when the temperature scale asked for is the same as the temperature? Why is that an error?

I understand. Like for getF(), I should be returning tempValue instead of 0 and an error.



How did you fix the round() function? Looking at the constructors, it seems the rounded value is ignored.

I'm not sure I understand what you mean about the round() function being ignored in the constructors.



What happens if "this" is a fahrenheit temperature?

I was not sure how to compare the two temperatures.



Why are you setting the values when you're passed them into the constructor?

I wasn't sure which way I should do it.



Finally, since double's are approximate decimal values, you usually want to avoid testing with == but rather to see that the difference between them is "small enough" to consider them equal.

Can I compare them for equality then? Should I use floats instead of doubles?

Any suggestions from here?

Thank you,
Eric
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
David Harkness,

I now know what you mean about the round() function being ignored in the constructors. I have made these changes:



Thanks,
Eric
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
OK, I think I have everything working. I still have some touching up to do, but overall, it is doing what I need it to do. If anything else looks odd, please let me know. Any comments or suggestions are appreciated.

Thanks,
Eric
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
The first and third constructors still have an error, but since you're using values that are already rounded, you don't see it.This rounds tempValue (initialized to zero by the JVM) and then assigns the parameter initialTempValue to tempValue, overwriting the rounded 0.
I was not sure how to compare the two temperatures.
If both temperatures are using the same scale, no conversion is necessary. Otherwise, convert one of them to the other's scale (doesn't matter which one you pick). Your code assumes that the temperature receiving the method call is Celcius and the parameter passed in is in Fahrenheit.

Also, I just noticed that your getF() and getC() methods switch the temperature to the requested scale. This is what's called an unexpected side effect. Typically, getFoo() methods are expected not to change the object.
Can I compare them for equality then? Should I use floats instead of doubles?
You may find that these simple values can be represented exactly, but both the float and double types are binary approximations of decimal values (google for IEEE 754 for more information).
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
The first and third constructors still have an error, but since you're using values that are already rounded, you don't see it.
This rounds tempValue (initialized to zero by the JVM) and then assigns the parameter initialTempValue to tempValue, overwriting the rounded 0.
The reason I use round here is because when I create a new object (using new), I am intentionally using a tempValue parameter that has more than 1 digit after the decimal.
Please let me know if you mean something else.
If both temperatures are using the same scale, no conversion is necessary. Otherwise, convert one of them to the other's scale (doesn't matter which one you pick). Your code assumes that the temperature receiving the method call is Celcius and the parameter passed in is in Fahrenheit.
I will need if statements to achieve this. The if statements will need to be in the comparison methods. I am just not sure how to write them.
Also, I just noticed that your getF() and getC() methods switch the temperature to the requested scale. This is what's called an unexpected side effect. Typically, getFoo() methods are expected not to change the object.
So I shouldn't change the scale inside the method? Where is the best place to change the scale?
You may find that these simple values can be represented exactly, but both the float and double types are binary approximations of decimal values (google for IEEE 754 for more information).
Since the double types are working in my equality tests, I will use them.

Thank you,
Eric
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Originally posted by eric elysia:
The reason I use round here is because when I create a new object (using new), I am intentionally using a tempValue parameter that has more than 1 digit after the decimal.
I understand that, but look at the constructors again. On the first line you round the instance variable tempValue which has not been assigned a value yet. On the second line you overwrite tempValue with the non-rounded parameter initialTempValue.

Here is the output for these two lines:As you can see, this isn't rounded.
I will need if statements to achieve this. The if statements will need to be in the comparison methods. I am just not sure how to write them.
True, but they're very similar to the if statements you have in the getF() and getC() methods. Give it a try, post what you come up with, and I'll help you. I cannot simply give you the code.
So I shouldn't change the scale inside the method? Where is the best place to change the scale?
No, if you are going to change the scale, add a method like switchScale() or have setScale(scale) convert tempValue if the requested scale is different. But my the real question before doing that is: Do you need to change the scale of the TempTest object, or is it sufficient to calculate and return the converted value?
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
As you can see, this isn't rounded.

Ah ha, that makes more sense now. OK, I moved the calls to round() after tempValue = initialTempValue.

True, but they're very similar to the if statements you have in the getF() and getC() methods. Give it a try, post what you come up with, and I'll help you. I cannot simply give you the code.

Yes, I understand that. I will see if I can write them and then I will post them.

No, if you are going to change the scale, add a method like switchScale() or have setScale(scale) convert tempValue if the requested scale is different. But my the real question before doing that is: Do you need to change the scale of the TempTest object, or is it sufficient to calculate and return the converted value?

If I am converting a temperature from F to C, then don't I want to change the F to C along with the actual temperature value? I am just trying to keep the two variables of the object together.

Thank you,
Eric
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Originally posted by eric elysia:
If I am converting a temperature from F to C, then don't I want to change the F to C along with the actual temperature value? I am just trying to keep the two variables of the object together.
I'm saying change neither value of the fields belonging to Temperature. Instead, convert a copy of tempValue and return it. To do this you'll need to add a second round() method that takes a temperature and returns it rounded to one decimal instead of rounding and returning tempValue.

As another developer, I would expect getF() to return the value of the Temperature in degrees Fahrenheit without changing itself. I would expect convertToF() to modify the TempTest.

For the programI would expect the following output.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Here's a pointer about constructors: you can have one call another one as its first line. If you find you have constructors that do all the work of another constructor but supply some default values, you can rewrite it.

Here's an example.This way you don't have to duplicate the work of validating the units in both constructors. This is good when you find a bug in how you're validating but forget to fix it in both places.
[ March 07, 2005: Message edited by: David Harkness ]
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
The two comments two posts before this one should say "convert to C", but I cannot edit the post without chopping off the top half.
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
Thank you for the tip on constructors.
I moved the round() method calls below the lines where initialTempValue is assigned to tempValue.
I have created a switchTempScale() method. It looks like this:

I have also created an if method to allow either temperature scale to be compared. I am not sure if this is right.


Thank you,
Eric
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
OK, now for the Weight class example, I don't see what you mean. It looks like Weight(String units) calls Weight(double value, String units). Is that correct?
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
As another developer, I would expect getF() to return the value of the Temperature in degrees Fahrenheit without changing itself. I would expect convertToF() to modify the TempTest.


You're right, it would be better to have it like this:


Eric
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
I'm saying change neither value of the fields belonging to Temperature. Instead, convert a copy of tempValue and return it. To do this you'll need to add a second round() method that takes a temperature and returns it rounded to one decimal instead of rounding and returning tempValue.


Do you mean like this?



Eric
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
Please let me know if this is wrong, but here is what my get and convert methods now look like:


Thanks,
Eric
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Okay, let me try to catch up.
It looks like Weight(String units) calls Weight(double value, String units). Is that correct?
That's exactly what is happening. The other way would be to have the first constructor validate the units String before setting this.value to 0 and this.units to units. But as you can see, the second constructor is already doing that, so you're duplicating code. Having one constructor call another reuses the code you've already written. I just want to make the point that while it does save typing, it will help you avoid creating bugs in the future.

About switchTempScale() and convertToF/C(): they should maintain the integrity of the object. If you change only tempScale and not tempValue, you are changing the actual value of the Temperature. I don't see a need for switchTempScale() as it's written, as I think it makes more sense to simply set the scale inside the conversion methods (those that convert the Temperature directly).

The getF/C() methods should still return the value in the correct units, but they should convert a copy instead of the original value, just as you've done in temporaryRound(). Copy the value to a local variable, convert it, and return it.

You need a round() method that will take a parameter to be rounded instead of rounding tempValue. Here's psuedocode for getF() and convertF() as I see them.As you can see, sometimes you are rounding tempValue and other times you're rounding some other local variable.

Finally, regarding comparisons, it should be sufficient to get their values in the same scale (either F or C) and compare those. No need for if tests since getF() returns tempValue if tempScale is already F.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
I fear I may have led you astray by talking about the convertToF() method. Your classes do not need the convertToF/C() methods as I described them. I only meant to recommend that getF/C() not modify the Temperature.tempValue instance field. They should convert a copy of it to the appropriate temp scale and return that modified copy.

The only difference I was suggesting was to operate on a copy inside the get methods, not to have you do work you weren't required to do. Granted, I think the convertToF/C() methods would be useful for a Temperature class, and I'd write them as I said, but they aren't needed here.

If you want to keep them, getF() still needs to convert and round the local variable tempF if the scale is C. See, "double tempF = tempValue" doesn't make sense if the scale is C. Look at my psuedocode and let me know if you understand it. It's often hard to give hints without writing the code.
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
You need a round() method that will take a parameter to be rounded instead of rounding tempValue. Here's psuedocode for getF() and convertF() as I see them.



I don't understand how convertToF() will only convert temporaryTempScale.


Eric
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
Finally, regarding comparisons, it should be sufficient to get their values in the same scale (either F or C) and compare those. No need for if tests since getF() returns tempValue if tempScale is already F.


I don't understand why an if is not needed at all. I thought that is what you were saying that the method would need.




Eric
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Originally posted by eric elysia:
I don't understand how convertToF() will only convert temporaryTempScale.
What I'm saying is that getF() should look as it did when you started.Now, forgetting about convertToF() entirely (pretend we never talked about it), change this method so it converts, rounds, and returns a copy of tempValue. It should not assign any values to tempValue or tempScale or call any other method that modifies them.

I'm going to be a little naughty and show you the round(double) method I'm suggesting you add since I need to head off to bed.Notice there is no reference to tempValue. It rounds the value it is given as a parameter and returns it.
I don't understand why an if is not needed at all. I thought that is what you were saying that the method would need.
I did say that originally, and you could write it that way.Another way to write it, though, is to choose one scale to use for comparison -- F or C -- and compare the temps using values in that single scale.By using getC/F() in the above methods and fixing getC/F() so they don't modify the Temperature itself, you will free yourself of unintended side effects.
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
One more quick question before you go...


Should I call a method after the Error?

Thanks,
Eric
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Originally posted by eric elysia:
System.out.println("Error: Must be C or F.");
//This should take the user to...?
Java has an exception mechanism for just such errors, but you probably haven't covered it yet. Normally you'd throw an IllegalArgumentException with a nice message for the caller to handle. If the caller doesn't handle it, the JVM will exit when it catches it.

If you want to see what happens, change the above two lines to this:Then feed it a bad value.

What this allows is for the caller to catch the error and possibly take some action to correct it. In this case, it could prompt for input in a loop until the user gave it a good value.
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
But since I haven't covered exceptions yet, should I call a method?
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Originally posted by eric elysia:
But since I haven't covered exceptions yet, should I call a method?
Either return without doing anything or call System.exit(1). Sorry, I forget that it's better not to give too many options at the early stages of learning, but I'm learning!

[ And it's best not to give advice when you're really tired. I'll continue tomorrow... ]
[ March 07, 2005: Message edited by: David Harkness ]
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
Thank you so much for all of your time. You have helped me to understand some of the "lack of control" that I had in my code.

In the equals() example that you posted, is the first return supposed to return(this and t have the same scale)? Is there a way to use this line in my driver program? I will rewrite the driver code to see if I can figure it out.

Thanks again for everything. I'm learning too!

Eric
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
I cannot figure out how to properly test my comparison methods. I have been trying to find a better way to either write the test code or change what the first if statement returns. I am going in circles here. Can anyone lend some advice or at least try to push me in the direction I need to go? I'm all ears.

Here is one of my comparison methods:



Originally, I had my driver (test) code like this:



Thanks,
Eric
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
Anyone?
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
You're so close! Change the return statement inside the first if block as I had it (for equals). What that if test is saying is "If both temperatures are in the same scale, compare their values directly." The other two blocks take care of the cases where their scales are different and conversion is necessary.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
To make your testing easier, I'd recommend following another Java standard: define a toString() method that takes no parameters and returns a short String representation of the object.

The problem with the writeOutput() method is that it has limited usefulness. It can't be sent to a file or used to build a longer String. In short, it's inflexible.

Since Object declares the toString() method, all objects inherit it. When you add an object onto a String, the Java compiler automatically calls toString() on the object. With a proper toString() method, say one that returns Strings in the form of "37.3 C" and "102.2 F", you could write your test code like this:In the println() call, the JVM will call toString() on t26 and t27 to build the full String to display.

The next piece that you could add would be to have your test driver program actually verify the answers instead of making you verify them each time. If you know what the expected answer is, you could test that the returned result meats the expectation and print an error if it doesn't.It's much easier to scan your output for "Error" lines rather than validate the true/false results every time.
eric elysia
Ranch Hand

Joined: Mar 06, 2005
Posts: 70
Unfortunately, my assignment was due 2 days ago. I am going to have to turn in what I have. I will continue to improve my code. I will continue to post as I have questions.

Thank you for all of the tips,
Eric
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
I'm very glad to help. Let me know if you have questions along the way. I'll try to give you some more tips without inundating you with details you don't need yet.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: compare variables of an object
 
Similar Threads
Can't Update Record ?
The INSERT INTO statement contains the following unknown field name: 'OPANo'.
illegal start of expression
comparison methods
Can't Update Record ?