Overloading Java function with List<> parameter
Asked Answered
E

7

20

I have 2 classes

public class Customer{
  ...
  public String getCustomerNumber();
  ...
}

public class Applicant{
   ....
   private Customer c;
   public Customer getCustomer(){ return c; }
   ...
}

When presented with a list of customers or applicants I want a function which iterates the list and does something with the CustomerNumber.

I've tried overloading the function

public void processCustomerNumbers(List<Customer> custList)
...

public void processCustomerNumbers(List<Applicant> appList)
...

but these are seen as duplicate methods... is there a nice way of doing this rather than just having 2 differently named functions?

Elohist answered 11/2, 2010 at 0:55 Comment(0)
P
21

If you make both classes implement a common interface,

interface CustomerNumber {
    String getCustomerNumber();
}

public class Customer implements CustomerNumber {
  ...
  public String getCustomerNumber();
  ...
}

public class Applicant implements CustomerNumber {
   ....
   private Customer c;
   public Customer getCustomer() { return c; }
   public String getCustomerNumber() { return getCustomer().getCustomerNumber(); }
   ...
}

then you might be able to do what you want with just a single method:

public void processCustomerNumbers(List<? extends CustomerNumber> appList) {
    for (Customer c: appList) {
        processCustomerNumber(c.getCustomerNumber());
    }
}
Pappy answered 11/2, 2010 at 1:16 Comment(0)
O
18

The thing about generics in Java is that generic types are erased at runtime, so both of these methods compile to the same signature. You will need to have separate method names, or check the type of the list elements at runtime.

Ordain answered 11/2, 2010 at 0:56 Comment(3)
Java did not always have generics; when they were added, the resulting bytecode was not changed.Soares
Yes, that's the reason for using type erasure - to avoid breaking backward compatibility with pre-generics code.Ordain
The type are erased at runtime. Method overload selection is done at compile time. Therefore, there is enough information for the compiler to decide, even with erasure. However, there are binary representation and compatibility issues if this language change was to happen.Ai
N
7

One way to workaround this issue would be to define custom list types like this:

class CustomerList extends ArrayList<Customer> {
    ...
}

class ApplicantList extends ArrayList<Applicant> {
    ...
}

Then the following overloading would be legal:

public void processCustomerNumbers(CustomerList custList)

public void processCustomerNumbers(ApplicantList appList)

However, I don't think that this would be a good idea. For a start, it hardwires particular implementation classes into your application's APIs.

A better approach is to define a common interface for Customer and Applicant that allows you to process them with one processCustomerNumbers method. (As described at length in other answers.)

Norbertonorbie answered 11/2, 2010 at 4:50 Comment(0)
L
6

Generics have what is known as type erasure - List<Customer> and List<Applicant> are the same type, the compiler just places compile-time restrictions on what you can do with them.

You could check the type of the first object in the list and call a (differently-named) internal method based on that.

Lesotho answered 11/2, 2010 at 0:58 Comment(3)
Yeah, that was something I started looking at, checking the class and altering behaviour. Came to SO hoping there was an more elegant solution, if nothing comes up I'll continue down this route.Elohist
As other question, override selection is done at compile time so erasure does not rule it out.Ai
In my opinion this kind of code could be classified as "spaghetti code". I prefer https://mcmap.net/q/612316/-overloading-java-function-with-list-lt-gt-parameter because force you to implement object oriented code.Addie
T
1

Use array instead.

public void processCustomerNumbers(Customer[] custList)
...

public void processCustomerNumbers(Applicant[] appList)
...

When you try to call these methods with a list, convert the list to array:

List<Customer> customers;
List<Applicant> applicants;
...
processCustomerNumbers(customers.toArray(new Customer[]{});
processCustomerNumbers(applicants.toArray(new Applicant[]{});
Tetanus answered 31/7, 2017 at 14:50 Comment(0)
B
0

I have found one easiest workaround for this problem with least modifications in code. You can use List and Collection in the parameter like this:

public void processCustomerNumbers(List<Customer> custList)
...

public void processCustomerNumbers(Collection<Applicant> appList)
...
Buckler answered 17/8, 2023 at 6:47 Comment(0)
C
-1

Before coming into the method names , the class hierarchy is little bit confusing...

public class Customer{          
  ...          
  public String getCustomerNumber();          
  ...          
}          

public class Applicant{          
   ....          
   private Customer c;          
   public Customer getCustomer(){ return c; }          
   ...          
}    

Why should applicant and Customer be different objects ? Can you tell the relation between these objects ?

Crumpet answered 11/2, 2010 at 3:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.