综合编程

Method Parameters Marked Final: Good Approach?

微信扫一扫,分享到朋友圈

Method Parameters Marked Final: Good Approach?
0 0

On a recent project, we started to employ CheckStyle
to help enforce good code quality and standards. I added the CheckStyle plugin to my IntelliJ IDEA client and introduce the  checkstyle.xml
 
from another client's project and ran the analysis.

I wasn't completely sure what to expect, since the API had been created before I started the project. As it turns out, the results were not all that bad. Making sure spacing was standardized, setting private class constructors for utility classes, and removing the public prefix on interface classes were common items that needed to be fixed.

But then, I saw a bunch of recommended changes stating that method parameters should be marked final
.

CheckStyle documentation states:

Check that parameters for methods, constructors, and catch blocks are final. Interface, abstract, and native methods are not checked: the final keyword does not make sense for interface, abstract, and native method parameters as there is no code that could modify the parameter.

The Spirit of the Rule

The CheckStyle documentation goes on to include the following information:

Changing the value of parameters during the execution of the method's algorithm can be confusing and should be avoided. A great way to let the Java compiler prevent this coding style is to declare parameters final.

I understand the recommendation that method parameters should be marked as final. When passing objects as parameters, Java allows objects to be updated in a method, which might lead to confusion.

Consider this example:

DoSomething.java

public class DoSomething {
    public static Long compute(ObjectA objectA, ObjectB objectB) {
       Long valueFromA = objectA.getAttributeA();

        if (objectA.getSomething().equals(Constant.SOME_THING_IS_TRUE)) {
            objectA.setSomeBoolean(true);
            valueFromA = objectA.getAttributeB();
        }

        return Long.valueOf(valueFromA * objectB.getSomething());
    }
}

In the simple example above, when the value of the something attribute for ObjectA
 
is equal to a constant, the  someBoolean
 
attribute is set to true.

Developers using the DoSomething.compute()
 
function, while expecting a  java.lang.Long
 
value to be returned, may not realize that the  ObjectA
 
will be updated as a result of the computation. The recommendation to mark the  objectA
 
and  objectB
 
params as  final
 
is a way to avoid the objects from changing.

The Exception to the Rule

Consider an example where the goal is to use Java to process and transform attributes, in order to maintain a java.util.Map
used across the Java class.

DoSomethingElse.java

public class DoSomethingElse {
    // Java Doc goes here ...
    public static List<AThirdObject> doProcessing() {
       List<Long> idList = ... call to get data
       List<SomeObject> someObjects = ... call to get data
       List<AnotherObject> anotherObjects = ... call to get data

       Map<Integer, List<AThirdObject>> map = buildMap(idList);
       processDataForMap(map, someObjects, anotherObjects);

       return buildReturnList(map); 
    }

    // Java Doc goes here ...
    private static Map<Integer, List<AThirdObject>> buildMap(List<Long> idList) {
        Map<Integer, List<SomeObject>> map = new HashMap<>();
        // Use idList and business rules to identify structure of map
        return map;
    }

    /**
    * This method will update a given 
    * {@link Map}<{@link Integer}, {@link List}<{@link AThirdObject}>> map 
    * based upon the attributes in the provided 
    * {@link List}<{@link SomeObject}> someObjects and 
    * {@link List}<{@link AnotherObject}> anotherObjects.
    *
    * @param map {@link Map}<{@link Integer}, {@link List}<{@link AThirdObject}>>
    * @param someObjects {@link List}<{@link SomeObject}>
    * @param anotherObjects {@link List}<{@link AnotherObject}>
    */
    private static void processDataForMap(Map<Integer, List<AThirdObject>> map, 
                                      List<SomeObject> someObjects, 
                                      List<AnotherObject> anotherObjects) {
        // Use someObjects and anotherObjects to further update the provided map.
        // This is a void method, so nothing is returned.
    }

    // Java Doc goes here ...
    private static List<AThirdObject> buildReturnList<Map<Integer, List<SomeObject>> map) {
       List<AThirdObject> returnList = new ArrayList<>();
       // Process map to build List<AThirdObject>
       // More business logic could occur here
       return returnList;
    }
}

In the DoSomethingElse class example, a java.util.Map
 
is being created by the  buildMap()
 
method. Once created, that map is passed to both the  processDataForMap()
 
and  buildReturnList()
 
methods in order to return the expected List
. The key here is that the   processDataForMap()
 
method is expected to change the map, so making the map parameter  final
 
in the   processDataForMap()
 
method would not be an option.

I have employed this approach occasionally over the years, leveraging Java's ability to do this and keep from consuming more memory by:

a) returning a new map in the processDataForMap()
  
method, or

b) setting a private map at the class level.

As shown above, I always use Java Docs to make it clear when the parameter values will be updated from use of a given method. I also use a void return type to avoid returning something and also modifying something that has been sent.

When I saw the rule in CheckStyle wanting to set method params as final
 
, it began to make me wonder if my approach is a valid approach.

Questions to the Community

I really enjoy reading the comments within the Java community at DZone. If you are willing to take a few minutes, I would like to pose the following questions:

  1. Is my approach (in DoSomethingElse.java) something you utilize?

  2. Do you tend to set method params as final
     
    during development?

  3. What alternatives exist, given this kind of situation?

As always, I certainly appreciate your thoughts.

Have a really great day!

DZone
感谢您的支持!

    Question: How should DateDiffNoWeekends work?

    上一篇

    Zig Is Great

    下一篇

    您也可能喜欢

    评论已经被关闭。

    插入图片

    热门分类