Effective parameter declarations for Java-Methods

Source: Internet
Author: User
Tags instance method

It is common to add a limit to the parameters of a method, such as a parameter that represents an index that cannot be negative, a reference to a key object cannot be null, or some processing, such as throwing the corresponding exception information.

For these parameter limits, the provider of the method must indicate in the document and examine the parameters at the beginning of the method and provide clear information in case of failure:

Detect errors as soon as possible after they occur

This will be a big guarantee for accurate positioning errors.

If this is not done, the best case scenario is that the method fails in the process and throws an inexplicable exception, the source of the error becomes difficult to locate, but this is the best case.
Worse is the way the method executes, without any errors, but the results are completely inconsistent with the description of the method, and finally the strange data in a critical part of the story is not over.


For arguments that violate the validity of the exception class used, we usually throw IllegalArgumentException , IndexOutOfBoundsException NullPointerException .
For exception types thrown when a constraint is violated, it needs to be described with the Javadoc @throws tag.
Also, not all parameter checks need to be done this far.
If the method or constructor is not exported externally, it can be used simply assert to guarantee the validity of the parameter.
such as Java.util.collections$copieslist:

private static class CopiesList<E>        extends AbstractList<E>        implements RandomAccess, Serializable{        //...        CopiesList(int n, E e) {            assert n >= 0;            this.n = n;            element = e;        }        //...}


However, the validity check is not all simple, and the cost of this operation can be very large or impractical, so some operations directly imply that the parameter check is implicit in the calculation process.
For example, the elements of a list are, of java.util.Collections sort() course, comparable, and the method does not check for validity at the beginning, but throws an exception when a problem is encountered in the calculation.
In comparison with this approach, it does not make sense to check validity in advance.
But it is necessary to consider the validity of the parameters in the calculation, that is, the atomicity of the method.


Say that the parameters have to be said method overloading, first of all an example:

  Import Java.math.biginteger;import java.util.arraylist;import java.util.collection;import Java.util.hashmap;import Java.util.hashset;import Java.util.list;import Java.util.set;public class    Collectionclassifier {public static String classify (set<?> s) {return "Set";    } public static String classify (list<?> lst) {return "List";    } public static String classify (collection<?> c) {return "Unknown Collection";                } public static void Main (string[] args) {collection<?>[] collections = {New Hashset<string> (),        New Arraylist<biginteger> (), New hashmap<string, string> (). values ()};    for (collection<?> c:collections) System.out.println (classify (c)); }}


Very common pen question, will output three times "Unknown Collection", compile time has decided the method that will call.
Static selection with overloaded methods (why did you design overloading like this? Overriding is the norm and overloading are the exception, no one seems to want this approach) relative to the coverage method, overridden methods The selection is dynamic.


That is, the selection method is performed at run time, and the subclass overwrites the method of the ancestor class with the same method signature, and if the method is an instance method, it is called on the instance of the child class.
For example, the compile-time type of an instance has no effect on it:

class Wine {    String name() {        return "wine";    }}class SparklingWine extends Wine {    @Override    String name() {        return "sparkling wine";    }}class Champagne extends SparklingWine {    @Override    String name() {        return "champagne";    }}public class Overriding {    public static void main(String[] args) {        Wine[] wines = { new Wine(), new SparklingWine(), new Champagne() };        for (Wine wine : wines)            System.out.println(wine.name());    }}


Given this characteristic of overloaded methods, and the language itself has no particular limitations, the authors suggest that < do not provide overloaded methods with the same number of parameters, while for mutable parameters do not consider overloading.
A good example of this suggestion is ObjectOutputStream, for its write method, the designer does not provide overloads of the same number of parameters, but provides methods such as Writeint,writeboolean,writelong, And the Read method is also symmetric with write.
This approach does not apply to constructors, we cannot name constructors, but we can privatize constructors and export static factories.
However, it is not necessary to strictly abide by this rule, for example, to fetchSalaryInfo() provide two method overloads, the int uid and the user userInfo, it is difficult to imagine the situation where the call error occurs.


Destroy < do not provide overloaded methods with the same number of parameters > This rule is not just when you are exporting a method, it is possible to update an existing class.
For example, the string class has a since 1.4 contentequals (StringBuffer), plus a since 1.5 contentequals (charsequence).
(The Charsequence interface is added in Java version 1.5 and acts as a public interface for classes such as stringbuffer,stringbuilder,charbuffer,string) but it does not pose a hazard, Because the behavior of the two overloaded methods in this example is exactly the same.


There are some interesting things about generics:

import java.util.ArrayList;import java.util.List;import java.util.Set;import java.util.TreeSet;public class SetList {    public static void main(String[] args) {        Set<Integer> set = new TreeSet<Integer>();        List<Integer> list = new ArrayList<Integer>();        for (int i = -3; i < 3; i++) {            set.add(i);            list.add(i);        }        for (int i = 0; i < 3; i++) {            set.remove(i);            list.remove(i);        }        System.out.println(set + " " + list);    }}


Slot: is the parameter in remove the index or element?
The execution result is [ -3,-2,-1][-2,0,2], which means that the parameter in List.remove is index, not automatically boxed.
It should be said that the root cause of the problem is the list is provided at the same time? remove(int) remove(E)
But as a user of the API, all we can do is take a more cautious approach to this big feature of Java 5.

Effective parameter declarations for Java-Methods

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.