[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 267
  • Last Modified:

General visiblity question

Could somebody please clarify each of the following questions (?? … ??) for me - i'll use some code as an example! :)

private void addTimeSpan(Element from, Element to)
    {
      int type = -1, period = -1, day = -1, less = -1;
      Date date = null;
      long dateEpoch = -1; // form date has been saved in XML file
      MomentInTime fromMoment, toMoment;
     
      /** FROM **/
      // get all these variable values as strings
      String typeStr = from.getAttributeValue("type"),
      periodStr = from.getAttributeValue("period"),
      dayStr = from.getAttributeValue("day"),
      lessStr = from.getAttributeValue("less"),
      dateStr = from.getAttributeValue("date");
     
      if(typeStr != null)
        type = Integer.parseInt(typeStr.trim());
      if(periodStr != null)
        period = Integer.parseInt(periodStr.trim());
      if(dayStr != null)
        day = Integer.parseInt(dayStr.trim());
      if(lessStr != null)
        less = Integer.parseInt(lessStr.trim());
      if(dateStr != null)
        date = new Date(Long.parseLong(dateStr.trim()));
     
      fromMoment = new MomentInTime(type, period, day, less, date);
    }

So now I have to repeat for:
/** TO **/

suppose I made a method:
private void setAttributes(Element e, String period, String day …)

for /** FROM **/
call   setAttributes(from, periodStr, dayStr …)
?? will these strings now be set correctly in the addTimeSpan method ??
then   fromMoment = new MomentInTime(type, period, day, less, date);

for /** TO **/
call   setAttributes(to, periodStr, dayStr …)
?? will the fromMoment object now be altered (because using same String objects) ??

Also am I correct in saying if my method was:
private void setAttributes(Element e, int period, int day …)
?? then the values will NOT be set in addTimeSpan because types are primitive ??

And does the date object pose any similar problems.

I suppose an excellent and much appreciated answer to this wordy question would be the code re-written as efficiently as possible with an explanation of why things will or will not work a certain way!

Kindest regards,
Cathal.
0
cathalmchale
Asked:
cathalmchale
  • 7
  • 2
  • 2
3 Solutions
 
imladrisCommented:
The variable typeStr is declared in the addTimeSpan method. This means that typeStr is a reference to a String object. The call to getAttributeValue returns a reference to a String object which is then assigned to typeStr and all is well.

However, if you were to use a setAttributes call you would be facing a difficulty. The difficulty lies with the way that arguments are passed to methods. In Java (and most modern languages) arguments are passed "by value". This means that a *copy* of the argument is put on the stack, and the method uses this copy as the argument. The advantage of this tactic is that the callers variables are "safe" from sideeffects caused by the method. When you're reading the code, and you see a method being called, you cannot see what might be happening in the method. Calling by value helps the reader by encouraging that indeed, usually, nothing *does* happen.
So, since a copy goes to the method, assigning some value to that copy inside the method will not change the value of the variable you passed in.

This is true for Objects (String's in this case) as well as primitives.
0
 
imladrisCommented:
The main dodge to this (there's always a dodge) is as follows.

If you pass a reference to an object into a method, and the method changes the *object*, then the caller will see the changed object as well.

Why?

Well, if you have an object Foo, and pass a reference to it, a *copy* of the reference is passed into the method on the stack. But that copied reference is pointing to the *same* object. So if the method changes the object (calls some method of the object that changes its internal state, or, perhaps, directly changes one of its member variables), then the caller (still having a reference to that same object) will see that object in its new state.

On the other hand, remember that this does *not* work for Strings. Strings are immutable. A String object can't be changed; by anybody. You can only create new ones.
0
 
zzynxSoftware engineerCommented:
>> am I correct in saying if my method was:
>> private void setAttributes(Element e, int period, int day …)
>> ?? then the values will NOT be set in addTimeSpan because types are primitive ??
Yes.

>> for /** FROM **/
>> call   setAttributes(from, periodStr, dayStr …)
>> ?? will these strings now be set correctly in the addTimeSpan method ?
No, since String is an immutable object


>> And does the date object pose any similar problems
No. You can alter a Date or any other object (cf. MyData in what follows)


Run this little demo app:

/*
 * RefDemo.java
 *
 */

/**
 *
 * @author  zzynx
 */

public class RefDemo {
   
    public RefDemo() {
    }
   
    public void setString(MyData inputData, String key) {
        key = inputData.getKey();
    }

    public void setKeyOfMyData(MyData inputData, String key) {
        inputData.setKey(key);
    }

   
    public static void main(String arg[]) {
        RefDemo d = new RefDemo();
       
        String key = "First content";
        System.out.println("Key = " + key);
        d.setString( new MyData("2nd Key", "value 2"), key);
        System.out.println("Key = " + key);
       
        MyData data = new MyData("Key", "value");
        System.out.println("Data = " + data.toString());
        d.setKeyOfMyData(data, "new Key");
        System.out.println("Data = " + data.toString());
    }
   
    public static class MyData {
        private String key;
        private String value;
        public MyData(String key, String value) {
            this.key = key;
            this.value = value;
        }
        public String getKey() { return key; }
        public String getValue() { return value; }
        public void setKey(String key) {
            this.key = key;
        }
        public void setValue(String value) {
            this.value = value;
        }
        public String toString() {
            return "key =" + key + " - value = " + value;
        }
    }
}

Output:

Key = First content
Key = First content                                // <<< the String is not altered
Data = key =Key - value = value
Data = key =new Key - value = value   // <<< the MyData object IS altered
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
zzynxSoftware engineerCommented:
So, what could you do?

Make a

public class MyData {

      private int type = -1;
      private int period = -1;
      private int day = -1;
      private int less = -1;
      private Date date = null;

      // constructor(s)
      ...

      // setters
      ...

      // getters
      ...
}

private void addTimeSpan(Element from, Element to) {

    MyData data = new MyData();

    /** FROM **/
    setAttributes(from, data);  // This alters the fields of the MyData object 'data'
    fromMoment = new MomentInTime(data.getType(), data.getPeriod(), data.getDay(), data.getLess(), data.getDate());

    /** TO **/
    setAttributes(to, data);  // This alters the fields of the MyData object 'data' again
    toMoment = new MomentInTime(data.getType(), data.getPeriod(), data.getDay(), data.getLess(), data.getDate());
}
0
 
zzynxSoftware engineerCommented:
Even better
(since more object oriented; it's the MyData object that "imports" the data from an Element object)
is this:


public class MyData {

      private int type = -1;
      private int period = -1;
      private int day = -1;
      private int less = -1;
      private Date date = null;

      // constructor(s)
      ...

      // setters
      ...

      // getters
      ...

     public void importData(Element e) {
           String typeStr = from.getAttributeValue("type"),
           String periodStr = from.getAttributeValue("period"),
           String dayStr = from.getAttributeValue("day"),
           String lessStr = from.getAttributeValue("less"),
           String dateStr = from.getAttributeValue("date");
     
           if(typeStr != null)
               type = Integer.parseInt(typeStr.trim());
           if(periodStr != null)
              period = Integer.parseInt(periodStr.trim());
          if(dayStr != null)
              day = Integer.parseInt(dayStr.trim());
          if(lessStr != null)
              less = Integer.parseInt(lessStr.trim());
          if(dateStr != null)
             date = new Date(Long.parseLong(dateStr.trim()));
     }
}

private void addTimeSpan(Element from, Element to) {

    MyData data = new MyData();

    /** FROM **/
    data.importData(from);  // This alters the fields of the MyData object 'data'
    fromMoment = new MomentInTime(data.getType(), data.getPeriod(), data.getDay(), data.getLess(), data.getDate());

    /** TO **/
    data.import(to);  // This alters the fields of the MyData object 'data' again
    toMoment = new MomentInTime(data.getType(), data.getPeriod(), data.getDay(), data.getLess(), data.getDate());

}
0
 
zzynxSoftware engineerCommented:
Typo: in the importData() function replace all occurrences of 'from' into 'e'


      public void importData(Element e) {
           String typeStr = e.getAttributeValue("type"),
           String periodStr = e.getAttributeValue("period"),
           String dayStr = e.getAttributeValue("day"),
           String lessStr = e.getAttributeValue("less"),
           String dateStr = e.getAttributeValue("date");
     
           if(typeStr != null)
               type = Integer.parseInt(typeStr.trim());
           if(periodStr != null)
              period = Integer.parseInt(periodStr.trim());
          if(dayStr != null)
              day = Integer.parseInt(dayStr.trim());
          if(lessStr != null)
              less = Integer.parseInt(lessStr.trim());
          if(dateStr != null)
             date = new Date(Long.parseLong(dateStr.trim()));
     }
0
 
cathalmchaleAuthor Commented:
Thanks for the info guys, its good to know exactly whats going on so I hopefully wont make the same mistakes again and again ... and again.
I guess the only problem with such a solution zzynx is that it adds to the lines of code greatly - and if your class is already quite full...!
Perhaps here is an alternative:  (again thanks, ill accept now)

/**
     * @param from Element to be converted to MomentInTime
     * @param to Element to be converted to MomentInTime
     */
    private void addTimeSpan(Element from, Element to)
    {
      MomentInTime fromMoment = createMoment(from);
      MomentInTime toMoment = createMoment(to);
     
      timeSpans.add(new TimeSpan(fromMoment, toMoment));
    }


    /** Helper method for addTimeSpan
     * @param e Element to be converted to MomentInTime
     * @return the initialised MomentInTime object
     */
    private MomentInTime createMoment(Element e)
    {
      MomentInTime moment = new MomentInTime();
      int type = -1, period = -1, day = -1, less = -1;
      Date date = null;
     
      // get all these variable values as strings
      String typeStr = e.getAttributeValue("type"),
      periodStr = e.getAttributeValue("period"),
      dayStr = e.getAttributeValue("day"),
      lessStr = e.getAttributeValue("less"),
      dateStr = e.getAttributeValue("date");
      // initialise variables with these values
      if(typeStr != null)
        type = Integer.parseInt(typeStr.trim());
      if(periodStr != null)
        period = Integer.parseInt(periodStr.trim());
      if(dayStr != null)
        day = Integer.parseInt(dayStr.trim());
      if(lessStr != null)
        less = Integer.parseInt(lessStr.trim());
      if(dateStr != null)
        date = new Date(Long.parseLong(dateStr.trim()));
       
      // return the MomentInTime object
      moment.setMoment(type, period, day, less, date);
      return moment;
    }
0
 
zzynxSoftware engineerCommented:
Thanks for accepting

>> the only problem with such a solution zzynx is that it adds to the lines of code greatly
I definitely disagree on that!
Java is all about lots of small classes. What's the problem with one extra MyData class?

>> and if your class is already quite full...!
...then it's time to rethink the design and split it up in smaller parts
0
 
zzynxSoftware engineerCommented:
>> Perhaps here is an alternative
Mmmm.
Only wonder why you don't make a MomentInTime constructor that accepts Element as parameter.
A function that is called createXXXX() begs for being replaced by a constructor, no?
0
 
cathalmchaleAuthor Commented:
>> and if your class is already quite full...!
...then it's time to rethink the design and split it up in smaller parts


yea sometimes but when your working on a complex swing gui - panels, models etc. can grow rapidly - its nice to use inner classes so that belonging units are contained but this can sometimes reduce readability greatly etc. bla bla...
0
 
zzynxSoftware engineerCommented:
>> yea sometimes but when your working on a complex swing gui
I do
>> its nice to use inner classes
I don't ;°)
>> so that belonging units are contained
I try to use sub packages with clear names: models, renderers, decorators, ...
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

  • 7
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now