• Post Reply Bookmark Topic Watch Topic
  • New Topic

What does this line mean?  RSS feed

 
Max Ho
Greenhorn
Posts: 17
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi all,

I am going through an Android Tutorial. I am asking it here because it's a relatively simple question, and it has more to do with Java than Android.

The entire code is found here - http://www.newthinktank.com/2014/07/make-android-apps-8/



Questions
1. Why is the class Quantity used as the method type?
2. Can someone explain how line 3 works? From my understanding, the Quantity class takes 2 arguments as seen in the constructor. But how is it that the fromBaseUnit and toBaseUnit can be accessed via newUnit and oldUnit as shown?
 
Campbell Ritchie
Marshal
Posts: 56570
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That looks like a factory method. I am very surprised it isn't marked static because you often need to call factory methods before you have any instances of the class.
You can read about factory methods in Effective Java™ by Joshua Bloch (2nd edition page 5-10). I haven't seen factory methods called to; I have seen lots called getInstance newInstance valueOf or of. Some classes e.g. this one don't have public constructors and use factory methods instead; look for the of method.

What happens is that you create an instance of Quantity. You would have to look at the rest of the code, but it appears the old unit and the new unit are both fields of the new Quantity instance. Then you return a reference to the new Quantity.

I may be wrong about two fields. Maybe that constructor does something like work out their difference, but you can't tell that from the code you posted.
 
Max Ho
Greenhorn
Posts: 17
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for your reply.

I haven come across a factory method, but I doubt it because the person would have mentioned it on his video.

I followed the rest of the code, and was stuck at that line.

Basically, I am not sure why the to method is created with Quantity class type, and how fromBaseUnit and toBaseUnit can be called in that manner. Haven come across anything like that!

Below is the entire code for this section.

 
Campbell Ritchie
Marshal
Posts: 56570
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It still looks like a factory method. You have a quantity in an old unit and convert it to a quantity in a new unit. Note that values like 0.0057d
  • 1: Are imprecise. They should have used more than two sig fig.
  • 2: Don't need the letter d because that format of number defaults to a double anyway.
  •  
    Junilu Lacar
    Sheriff
    Posts: 11494
    180
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Likes 2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    It's not a factory method. The method converts value, which is a field in the current object, into a quantity in another unit.

    Answers:

    1. The obvious: the method's return type is Quantity because it returns a reference to a Quantity object. This method makes most sense if it were in the Quantity class itself, which it is. This means that the Quantity class is immutable: once one is created it cannot be changed, much like the Integer, Long, and String classes in the standard library. Conversions of one quantity into another are not done in place, i.e. affecting the same object, but rather you get another object. Here's a comparison:

    Line 9 will display "1.0000 quart is equivalent to 2.0000 pint" or something close to it for the pints value.

    The Quantity class could override the equals() method so that with the above example, the expression quarts.equals(pints) would return true. Quantity does not override equals, however, so you can't really compare two Quantity objects for equivalence with the code as it is.

    2. The fromBaseUnit and toBaseUnit can be accessed because they are declared as public methods of the Unit enum. Methods that are declared public can be accessed by anything from anywhere.
     
    Junilu Lacar
    Sheriff
    Posts: 11494
    180
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Note that while the design of the Quantity class is pretty good—making Quantity objects immutable is similar to the approach used in Martin Fowler's Money class (see also http://verraes.net/2011/04/fowler-money-pattern-in-php/ for an example in PHP)—the implementation of the to(Unit) method could be made better. The second question about using the Unit enum methods in the Quantity.to() method actually hints at a code smell.

    The to method does most of its work by calling the methods in the Unit enum. This could be made better by moving those method calls into a method in the Unit enum. Then you would get the static method that Campbell is expecting. It still wouldn't be a factory method though.

    After moving the calls to fromBaseUnit and toBaseUnit from Quantity back to Unit, you can declare those two methods as private. You might also decide to make the convert() method public instead after you make the other two methods private.

    The comment for the to() method also hints at the code smell. Notice that is says "from tsp" and "to the desired unit type"? These two phrases make the comment misleading. It should really say "from the current unit". Here's a better comment for that method.

     
    Junilu Lacar
    Sheriff
    Posts: 11494
    180
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Here's more refactoring of the Unit enum:

    You only really need one method to calculate a conversion factor. I think these changes make the semantics of conversion simpler, more natural, and straightforward -- see Line 12 and how straightforward it is now.

    Quantity will still have the to() method as before. I made toString() use String.format instead.
     
    Max Ho
    Greenhorn
    Posts: 17
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Junilu,

    Sorry for my late reply. Got busy with something else, and hadn't had time to sit down to read through your replies.
    What you had explained makes sense to me.

    I have two more questions if you don't mind.

    1st Question - How is it that the object pints is created without the new keyword?


    2nd Question - Why is super(); invoked here when there isn't a parent constructor?


    Thank you!
     
    Campbell Ritchie
    Marshal
    Posts: 56570
    172
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Don't say parent, say superclass.

    But there is a constructor in the superclass. There is no such thing as a class without a constructor. Look in the Java® Language Specification (=JLS), where it tells you the compiler adds a default constructor if you don't write your own constructor. Beware: the JLS can be difficult to read. The super(); call exactly matches the default constructor in your superclass.

    The new keyword is used to create the pints object. But it is in the to(...) method. Look at line 2 of the 2nd code block in Junilu's latest post.
     
    Max Ho
    Greenhorn
    Posts: 17
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Campbell,

    Thanks for your reply.

    Isn't public Quantity(double value, Unit unit) the constructor for Quantity class? Which is the superclass?



    Got the second part, thanks!
     
    Campbell Ritchie
    Marshal
    Posts: 56570
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    No superclass is named, so the immediate superclass is .....

    All Java® programmers should know that.
     
    Tim Holloway
    Saloon Keeper
    Posts: 18799
    74
    Android Eclipse IDE Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Junilu Lacar wrote:It's not a factory method. The method converts value, which is a field in the current object, into a quantity in another unit.


    Actually, it is a factory. It's not converting value, it's creating a whole new instance of type Quantity, just scaled to a different unit type. For example, you submit a Quantity of 4 pounds and the factory produces and returns a Quantity of 8.8 kilograms. The original Quantity object remains unaffected.

    I have come across unit-conversion classes whose methods were non-static for various reasons, but yes, it would be more common for a static method to be used.
     
    Junilu Lacar
    Sheriff
    Posts: 11494
    180
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Tim Holloway wrote:
    Junilu Lacar wrote:It's not a factory method. The method converts value, which is a field in the current object, into a quantity in another unit.

    Actually, it is a factory. It's not converting value, it's creating a whole new instance of type Quantity, just scaled to a different unit type. For example, you submit a Quantity of 4 pounds and the factory produces and returns a Quantity of 8.8 kilograms. The original Quantity object remains unaffected.

    Then you are using a different definition of "factory" than I do. Logically, it is a conversion. The new Quantity object returned by the to(Unit) method is based on the current Quantity. You don't submit anything; you ask the Quantity for its equivalent in the new Unit and it gives back an appropriate representation as a different Quantity. Another thing, too, is that if you have Quantity objects that are not logically equal to each other, i.e., they represent different values/units, then passing the same argument to their to(Unit) methods would give you Quantity objects that are not equal either.

    The quantities represented by inQts1 and inQts2 are not equivalent, even though they were both created by the same to(quart) call. This disqualifies it as a factory method, IMO.

    I say that this is not a factory method for the same reason that asList is not a factory method: http://www.coderanch.com/t/640354/java-programmer-SCJP/certification/java-util-Arrays-asList-factory. But then again, as with the discussion in that thread, this case may be in a gray area.

    Edit:
    Think about though: if this to(Unit) method is a factory method, then by the same token, methods like String.toLowerCase() and String.toUpperCase() would also be factory methods. But are they? I don't consider them as factory methods but rather conversions.
     
    Max Ho
    Greenhorn
    Posts: 17
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    superclass is the object class.

    I've not come across classes that invoke the object class constructor. There isn't arguments in the object class, so I am wondering why the need to explicitly call super() in the Quantity constructor.

    Campbell Ritchie wrote:No superclass is named, so the immediate superclass is .....

    All Java® programmers should know that.


    EDIT: I found an answer from you from 4 years back - http://www.coderanch.com/t/535754/java/java/subclass-call-constructor-super-class

    The details are in the Java™ Language Specification. But it is reluctant to open for me.

    Simply: yes. You must initialise all the fields, so as to create your instance in a consistent state, ie fulfilling its class invariants. The only instance where you can get away without a super(...); call is if the superclass has an accessible no-arguments constructor. One must presume that constructor will put the superclass object into a consistent state.
    I think the only state in which case it is good design not to initialise the fields in the superclass is when the superclass hasn't got any fields!
     
    Junilu Lacar
    Sheriff
    Posts: 11494
    180
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Max Ho wrote:so I am wondering why the need to explicitly call super() in the Quantity constructor.

    There's no need. If you don't call it explicitly, it will be called implicitly anyway.
     
    Max Ho
    Greenhorn
    Posts: 17
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Ah yes, that's what I thought after going through google. Thanks!

    Junilu Lacar wrote:
    Max Ho wrote:so I am wondering why the need to explicitly call super() in the Quantity constructor.

    There's no need. If you don't call it explicitly, it will be called implicitly anyway.
     
    Campbell Ritchie
    Marshal
    Posts: 56570
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Max Ho wrote: . . . EDIT: I found an answer from you from 4 years back - http://www.coderanch.com/t/535754/java/java/subclass-call-constructor-super-class . . .
    Sounds like one of mine. This would appear to be the JLS section wanted.
     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!