2

I am reading a tutorial form this site.http://tutorials.jenkov.com/java-unit-testing/matchers.html The author I believe is very experienced. I saw the code like this. I also saw someone else always like to assign the parameter of a method to a variable then use it inside the method. This one here is this line. protected Object theExpected = expected;

Can anyone please tell me, what is the benefit of this coding style? Is this trying to avoid the object status being changed or something?

What if the parameter is not an Object but a primitive variable.

And what if it is a immutable Object like String. Thank you.

public static Matcher matches(final Object expected){

    return new BaseMatcher() {

        protected Object theExpected = expected;

        public boolean matches(Object o) {
            return theExpected.equals(o);
        }

        public void describeTo(Description description) {
            description.appendText(theExpected.toString());
        }
    };
}

Here is the update

I just did another test, to see if this parameter still accessible after we got the object.

package myTest;


public class ParameterAssignTest {

    public static void main(String[] args) {
        MyInterface myClass = GetMyClass("Here we go");
        System.out.println(myClass.getValue());
        System.out.println(myClass.getParameter());
    }

    public static MyInterface GetMyClass(final String myString){

        return new MyInterface() {

            protected String stringInside  = myString;

            @Override
            public String getValue() {
                return stringInside;
            }

            @Override
            public String getParameter() {
                return myString;
            }
        };
    }
}

Output:

Here we go
Here we go

So does this mean that even we do assign this parameter to the a local variable it still works?

Tech Noob
  • 510
  • 1
  • 9
  • 33

3 Answers3

2

I do not believe assigning to theExpected achieves anything.

As expected is final it can be accessed within the anonymous class. If it were used directly in describeTo the object would not be GC'd and the reference would remain valid when the local scope in which expected was declared was left.

Possibly the author of the post you link to believes this explicit style is more readable.

henry
  • 5,923
  • 29
  • 46
1

It doesn't matter if theExpected is primitive or Object (though in this example it's an Object), and whether it's mutable or not.

The matches method returns an instance of an anonymous class that extends BaseMatcher (and implements the Matcher interface, assuming that's an interface).

Once it returns the instance, the local variable - expected - that was passed to it is out of scope, but the theExpected member, containing the same value as that local variable, stays within the instance, and can be used by the methods of that instance.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • Thank you for the explanation. I got this now. What if this has nothing to do with the Matcher or inner class, it it is just a normal public method inside a normal class. Shall we still do the same? Thank you. – Tech Noob Feb 11 '15 at 15:09
  • @TechNoob well, there are setter methods that are used to modify members of the class, so in that case you would still assign the passed parameter to the instance variable. On the other hand, other methods use their argument once, and don't store it (for example, see the `o` parameter of the `matches` method in your code). – Eran Feb 11 '15 at 15:13
  • @Eran Although expected moves out of scope, the object it points to remains and it will still be valid to access `expected` from within the anonymous class. I do not believe assigning to theExpected serves any functional purpose - expected could be used directly. – henry Feb 11 '15 at 15:23
  • @LuiggiMendoza How does it aid debugging? – henry Feb 11 '15 at 15:36
  • Hi @Eran, can you check my update, does this mean the parameter can be kept after the class is created even we don't assign it to a local variable? Thank you. – Tech Noob Feb 11 '15 at 15:58
1

If you want/need to use a local variable in an inner class (in this case, an anonymous local class), the variable must be declared as final regardless if it's primitive or a reference type. This is better explained here: Why Java inner classes require "final" outer instance variables?. Quoting the best explanation IMO:

The reason the language insists on that is that it cheats in order to provide your inner class functions access to the local variables they crave. The runtime makes a copy of the local execution context (and etc. as appropriate), and thus it insists that you make everything final so it can keep things honest.

If it didn't do that, then code that changed the value of a local variable after your object was constructed but before the inner class function runs might be confusing and weird.

In this case, seems like the author want to keep a copy of the parameter sent to the method in the reference of the anonymous class generated for further evaluation. Once the method finishes its execution, the parameter Object expected isn't available anymore, so if you want/need to keep it then you must assign it into a field of your class.

Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • But the parameter is declared final. I think the question is "why not just write `expected.equals(o)`? – RealSkeptic Feb 11 '15 at 15:01
  • @RealSkeptic I was still writing the answer. I tend to write something, post it, and then edit to add more info. – Luiggi Mendoza Feb 11 '15 at 15:05
  • Thank you for the explanation. I got this now. And @RealSkeptic has a good point here, I would like to hear your opinion on this too. What if this has nothing to do with the inner class, it it is just a normal public method inside a normal class. Thank you. – Tech Noob Feb 11 '15 at 15:08
  • @TechNoob *What if this has nothing to do with the inner class, it is just a normal public method inside a normal class* then there's no need to have `protected Object theExpected = expected;` in the first place, you will directly assign the object into a field in the class (if needed) and it would seems more like a setter method, or you will use the object directly rather than assign it into a temp variable. But this seems more like a separate question. – Luiggi Mendoza Feb 11 '15 at 15:09
  • I would also like to add that it seems suspicious that `protected` is used here - there is no way to inherit from an anonymous class. – RealSkeptic Feb 11 '15 at 15:31
  • @RealSkeptic yes, I would declare that field with default scope, not even private. – Luiggi Mendoza Feb 11 '15 at 15:32
  • Hi @LuiggiMendoza, can you check my update, does this mean the parameter can be kept after the class is created even we don't assign it to a local variable? Thank you. – Tech Noob Feb 11 '15 at 15:57