开发者

What is the use of Method Overloading in Java when it is achieved by changing the sequence of parameters in the argument list? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.

Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.

Closed 5 years ago.

开发者_StackOverflow社区 Improve this question

I was reading a Java training manual and it said that Method Overloading in Java can be achieved by having a different argument list. It also said that the argument list could differ in

(i). Number of parameters

(ii). Datatype of parameters

(iii). Sequence of parameters

My concern is about (iii).

What is the use of trying to overload a method just by changing the sequence of parameters? I am unable to think of any benefits by this way.


(iii) is just a special case of (ii).

"int, long, String" and "String, int, long" are (ii) = different datatypes, but just happen to be the same set of types.

But yeah, promiscuous overloading leads to confusing code.


Method overloading is useless if your intent is solely parameter sequence, because IMHO, you're just encouraging boilerplate code (repeating identical code), and if the parameters are all of the same data type, you'll receive a compilation error because the method signatures are ambiguous.

I do a lot of method overloading in APIs for convenience purposes when a parameter can exist as multiple data types:

public class Client {

   public Status get(String request) {
      return get(new Request(request));
   }

   public Status get(Request request) {
      // do stuff
   }

}

If you have a lot of parameters, and many of them are optional, I would suggest looking into the Builder pattern. The intent of the builder pattern is to create an immutable object constructed of optional parameters. For instance:

public String get(String arg0, String arg1, String arg2) {
   // do stuff
}

public String get(String arg0, String arg1) {
   return method(arg0, arg1, null);
}

public String method(String arg0) {
   return method(arg0, null, null);
}

can probably be improved with a builder:

class Request {

    final String arg0;
    final String arg1;
    final String arg2;

    private Request(Builder b) {
        this.arg0 = b.arg0;
        this.arg1 = b.arg1;
        this.arg2 = b.arg2;
    }

    // getter methods

    public static class Builder {
        String arg0, arg1, arg2;

        public Builder arg0(String arg) {
            this.arg0 = arg;
            return this;
        }

        public Builder arg1(String arg) {
            this.arg1 = arg;
            return this;
        }

        public Builder arg2(String arg) {
            this.arg2 = arg;
            return this;
        }

        public Request build() {
            return new Request(this);
        }

    }

}

class Client {
    public String get(Request request) { }
}

new Client().get(Request.Builder().arg0("arg0").arg1("arg1").arg2("arg2").build());

Another overload that I do a lot is when a method can accept parameters of varying data types:

public String lookup(String variant) {
   return lookup(Integer.parseInt(variant));
}

public String lookup(int ordinal) {
   // logic
}


Ah! Makes sense! I was thinking in the lines of -

public String buildUrl(String protocol, String host, int port){
    return protocol + "://" + host + ":" + port;
}

public String buildUrl(String protocol, int port, String host){
    return protocol + "://" + host + ":" + port;
}

So, I was thinking that this was useless. But there might be a case like this (took a long time to come up with it :-)) -

public int countTotalTruckWheels(boolean hasSpare, int numberOfTrucks){
    if(hasSpare){
        return (numberOfTrucks+1)*4;
    } else{
        return numberOfTrucks*4;
    }
}

public int countTotalTruckWheels(int numberOfAxlesInTruck, boolean strongAxle){
    if(strongAxle){
        //each axle can hold 4 wheels
        return numberOfAxlesInTruck*4;
    } else {
        return numberOfAxlesInTruck*2;
    }
}

Here the datatypes of the parameters are not just re-ordered, but the entire meaning of the parameters has been changed.

I understood this based on many answers above. I am unable to choose one particular answer. Also, I wanted to add this as a comment, but it was too big to be a comment. Hence added it here.


It also said that the argument list could differ in
(iii). Sequence of parameters

(iii) is simply wrong. You can't change overload by simply changing the order of the parameters. Take this example:

int add(int x, int y)
int add(int y, int x)

This is not a legal overloading. Now consider this example:

int fill(int number, char c)
int fill(char c, int number)

Remember the parameter names don't matter, so really, it looks like this to the compiler:

int pad(int, char)
int pad(char, int)

This is valid overloading, but not because you changed the order of the parameters, but rather because the types of one or more of the parameters changed. The two methods differ because the type of the 1st parameter is different between the methods (as is the type of the 2nd parameter).


What is the use of trying to overload a method just by changing the sequence of parameters?

There is no use. The text is NOT saying you "SHOULD" do method overloading by changing the sequence of parameters, the text is only saying that its possible (as long as the reordering creates a unique parameter signature). This is simply a consequence (a side-effect) of how overloading works - I feel certain in saying that it is not an use case that the language designers were trying to support. Put another way:

Just because you can do it, doesn't mean you should.


There are not many reasons to do that sort of overloading, but I can think of a couple.

Your API goes public, and all your method signatures but one for a fairly common (but uninherited) method are the same. Say they're all myFunct(String,int) and one of them happens to be myFunct(int,String) by accident. You will want to keep that function for backwards compatibility, but you'll also probably make that one class also have myFunct(String,int) to keep it consistent.

Another reason (even if it is a poor one) is that you may have people used to them in one order, perhaps from a different library, or maybe they're just dyslexic... but you might overload it to swap parameters if it's convenient to do so. Obviously, this can be tricky, because if you have (String,int,int) You probably don't want to do (int,int,String) or (int,String,int) ALSO. Best to keep it to just one.


You are right, iii does not make a strong cases usually. Typically, it is necessary to keep things strongly typed as show below

void save(String key, int value);
void save(String key, float value);
void save(String key, byte value);

etc.


It may seem somewhat pointless and in a lot of cases I can see why some people may simply shuffle parameter sequences around simply to support overloading where really they just have poorly designed code. However, it in some circumstances it make perfect sense.

Most programmers will choose certain parameter sequences based on a notion that such parameters make more sense in a particular order or because order is in-fact fundamentally important to the outcome of some calculation. Take these overloaded methods as an example:

int raise(int i, String n);
int raise(String i, int n);

As you learned very early on in math class, raising one value by another is a non-commutative operation (i.e. 2^3 != 3^2).

So in this example, each method will raise some numeric value by another. The first parameter is always the value that is intended to be raised by the value given as second parameter (order is important). However, as you can see, each argument to the parameter list may be represented by a String or an int type. The semantics of the operation however remains the same.

raise("12", 2);
raise(12, "2");

Of course this is a very contrived example for obvious reasons, but you can see how in principle it is reasonable.

I'm sure if i gave it a bit more though I could come up with a better example where the parameters are of some special type where this sort of thing makes even more sense.


Parameter lists are determined by the number and types of the parameters. So if your parameters have different types, re-ordering the parameters gives a different overload because the compiler sees different types in different slots.

f(int a, String b)

f(String b, int a)

Both functions have two parameters but the types don't match so they are valid overloads.

As to why you might want to do this, it is often the case that the order of the parameters matters. In the codebase I maintain we have Exceptions that potentially have a cause, a message, and other parameters. So the following two calls are not the same:

Exception cause;
String msgFormat = "An error occurred while processing {0}";
String recordName = "abc123";

throw new ABCException(cause, message, recordName);

throw new ABCException(message, cause, recordName);

throw new ABCException(message, recordName);

throw new ABCException(recordName, message);

In the first case cause is the cause of the exception, message is the message to display, and record is the parameter for the message. In the second case both cause and recordName are interpreted as parameters for the message. In the third case there is no cause and in the fourth case there is no cause and furthermore the message argument is in the wrong position and won't be processed properly.

This is accomplished by having several useful overloads of the ABCException constructor (though in this case we are using varargs to support unlimited numbers of parameters).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜