I understand now how to create limitless arguments as per Java method with unlimited arguments
But I was wondering what is the syntax to extend this to two arguments, akin to printf?
I want to create unlimited String, int pairs.
The goal would be to display String1 : Int1, String2: Int2 and so on. I'm just not sure what the syntax would be, let alone if it's possible.
It's not directly possible but here are some approaches:
If the strings will be unique, you can pass the data as a Map:
public void method(Map<String,Integer> pairs) {
...
}
You can use two separate arrays:
public void method(String[] strings, int[] ints) {
if (strings.length != ints.length) throw new IllegalArgumentException();
...
}
Call as:
method(new String[] { "a", "b", "c" }, new int[] { 1, 2, 3 });
Use Object for everything and sort it out later. This suffers from ugly internals and a lack of compile-time type checking but it has the shortest calling syntax:
public void method(Object... args) {
if (args.length % 2 != 0) throw new IllegalArgumentException();
for (int i = 0; i < args.length; i += 2) {
String s = (String)args[i + 0];
int i = (Integer)args[i + 1];
...
}
}
Use a builder-style object:
public Pairs method() {
return new Pairs();
}
// make the names here meaningful for what your method actually does
public static class Pairs {
private static class Pair {
String s;
int i;
}
private final List<Pair> pairs = new ArrayList<>();
private Pairs() {}
public Pairs add(String s, int i) {
Pair p = new Pair();
p.s = s;
p.i = i;
pairs.add(p);
return this;
}
public void run() {
for (Pair p : pairs) {
... do method's work here ...
}
}
}
Depending on what you want to achieve this might be over-complicating it, but it gives a quite pleasant and fully type-checked syntax for the caller:
method()
.add("a", 1)
.add("b", 2)
.add("c", 3)
.run();
Well, firstly, you can't do this:
public void foo(String... strings, int... ints) {
Since you'll get an error that the varargs parameter strings needs to be the last one.
So you'll likely want to make a small wrapper class, say StringWithInt and then do like so:
public void foo(StringWithInt... values) {
I hope this helps!
Make the argument one Object argument, which has its own problems...
public void foo(Object... things)
But probably the best idea is to use a generic list for each argument type :
public void foo(List<String> strings, List<Integer> integers) {}
If the method specifically requires matchigng pairs a Map<String, Integer> could also be used.
(no you can't to original question)
hmmm why don't you just mapping instead?
Something like this
public void foo(Map<String,Integer> map){
}
Or maybe instead of String and int, just use objects?
public void foo(Object... args){
}
Related
Let's say I have an empty class called ClsA(), and a subclass of it called ClsB() like so:
public static class ClsA {}
public static class ClsB extends ClsA {}
Supposing that we now have an ArrayList of ClsA type objects, I want to be able to count how many elements in the ArrayList are actually of type ClsA or ClsB. Based on some searching, I found out that the following function works wonders:
public static <T> int countInstances(ArrayList<?> list, Class<T> cls) {
int count = 0;
for(Object o : list) {
if(cls.isInstance(o)) {
count++;
}
}
return count;
}
Indeed, the following sample main method does give the correct output.
public static void main(String[] args) {
// write your code here
ArrayList<ClsA> test = new ArrayList<>();
test.add(new ClsA());
test.add(new ClsB());
test.add(new ClsA());
test.add(new ClsB());
int result = countInstances(test,ClsB.class);
System.out.println(result);
}
However, let's say that ClsB is now defined as followed:
public static class ClsB extends ClsA {
private final String type;
public ClsB(String type) {
this.type = type;
}
public String getType() {return type;}
}
I now want to count how many ClsB instances of a specific type are present in the given ArrayList. After checking in my countInstances() that an element is of the given class (in this example ClsB), I want to be able to also check if the type given to the method matches the type of the element. Is there any way to actually cast Object o into an instance of the given class since the compiler doesn't really know its actual type?
So far I've gotten to this point:
public static void main(String[] args) {
// write your code here
ArrayList<ClsA> test = new ArrayList<>();
test.add(new ClsA());
test.add(new ClsB("t1"));
test.add(new ClsA());
test.add(new ClsB("t2"));
int result = countInstances(test,ClsB.class,true,"t1");
System.out.println(result);
}
public static <T> int countInstances(ArrayList<?> list, Class<T> cls, boolean checkForType, String type) {
int count = 0;
for(Object o : list) {
if(cls.isInstance(o)) {
if(!checkForType) count++;
else {}// somehow cast o into the given class (?)
}
}
return count;
}
Yes, there is cls.cast(o); which will do it, and will give you a T (because the type of cls is Class<T>, and the cast(Object o) method of j.l.Class is defined to return T. It acts just like the cast operator would, in that it does nothing: It just asserts that o is in fact an instance of this class (so, created as new This() or new SomeSubtypeOfThis()). If it is, it does nothing. If it is not, it throws ClassCastException. No conversion occurs in any case.
This isn't useful; after all, T is still just object. This will not give you the power to call getType() on your o - because T has no bounds, T is not going to have any methods other than what java.lang.Object already has.
In general, what you're engaging in is structural typing: It doesn't matter what ClsB is, it just matters that it has a method named getType.
This is very bad.
It means that the one method of public interface Camera { public void shoot(Person p); } and public interface Gun { public void shoot(Person p); } are, to such a system, interchangible, and thus you will blow somebody's head off by accident.
Types (classes, interfaces, etc) are exempt from this problem because they have a namespace - a package header, which serves to make them effectively unique. A method should therefore never be considered as meaning anything whatsoever, unless that method is in context of the type it in.
Thus, what you COULD do, is something like this:
public class ClsA {
public String getType() { .... }
}
public class ClsB extends ClsA { .... }
public static int countInstances(ArrayList<?> list, Class<?> cls) {
int count = 0;
for (Object o : list) if (cls.isInstance(o)) count++;
return count;
}
The above would return '2' for a list with one instance of ClsA and one instance of ClsB, and you pass ClsA.class as second param.
After all, an instance of ClsB is also an instance of ClsA.
If you're looking for an answer of '1', you're looking for:
for (Object o : list) {
if (o != null && o.getClass() == cls) count++;
}
Then for your 'getType' method, we must link that method to an actual type, because otherwise you're shooting people in the face and that's bad. So, I put the getType() method in ClsA, and then we demand that you pass a list of things which are ClsA's:
public static int countInstancesWithType(List<? extends ClsA> list, String type) {
int count = 0;
for (ClsA o : list) {
if (type.equals(o.getType())) count++;
}
return count;
}
Note that this method can be invoked with an ArrayList<ClsA> or an ArrayList<ClsB> - either is fine. <? extends ClsA> makes that possible; the ? extends is important. Without it, new ArrayList<ClsB>() could not be passed as first parameter.
If you want to combine these two ideas, That's.. a bizarre mix of concerns and sounds like you're engaging in the concept of structural typing in java, or otherwise some hacky attempt to make dynamic typing happen. Stop doing that; java is not that kind of language, and it will hurt the whole time, and the end result will be non-idiomatic, hard to maintain, and hard to read code. Find a java-esque way to do whatever you are doing. However, and don't say I didn't warn you:
public static int countInstancesWithType(List<?> list, String type) {
int count = 0;
for (Object o : list) {
if (!(o instanceof ClsA a)) continue;
if (type.equals(a.getType())) count++;
}
return count;
}
// NB: This uses java15 features. Without java15, you'd have to
// spend an extra line or two to cast ClsA separately.
There is no point trying to generalize ClsA here, because by doing so you remove the ability for your code to be capable of realizing that ClsA instances have a getType() method.
What about this? (see the changed signature of countInstances).
public static void main(String[] args) {
// write your code here
ArrayList<ClsA> test = new ArrayList<>();
test.add(new ClsA());
test.add(new ClsB("t1"));
test.add(new ClsA());
test.add(new ClsB("t2"));
int result = countInstances(test,ClsB.class,o -> o.getType().equals("t2"));
// count all
//int result = countInstances(test,ClsB.class,o -> true);
System.out.println(result);
}
public static <T> int countInstances(ArrayList<?> list, Class<T> cls, Predicate<T> test) {
int count = 0;
for(Object o : list) {
if(cls.isInstance(o)) {
if (test.test((T)o)) count++;
}
}
return count;
}
This does not answer your post's title, but I guess it is what you are looking for.
Is there a possibility to check if an object is either an array or a collection with one clause? What I am trying to achieve:
Assuming arrays implement Iterable, and assuming the Object foo could be either an array or a collection, I'd like to use a code snippet like this:
if (foo instanceof Iterable) {
for (Object f : (Iterable) foo) {
// do something with f
}
}
Unfortunately, an array cannot be cast to Iterable. Nor does it implement Collection. Are there any other possibilities to handle both in one loop like the above? Instead of -- of course -- using an if-else if-clause and two loops (which wouldn't be nice).
Edit: In response to these answers. I am aware of the isArray() method but in this case the casting in
...
for (Object f : (Iterable) foo) {
...
will fail. That'd a pity and a code redundancy since I would have to use two loops although a foreach-loop works both with Collections and Arrays.
Regarding a condition to check if foo is either a collection or an array:
Class#isAssignableFrom may come in handy.
Class<?> fooClass = foo.getClass();
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
Object[].class.isAssignableFrom(fooClass);
I reasonably assume you won't test it on primitive arrays since you have collections which work only with the wrapper classes.
I guess you can safely replace Object[].class.isAssignableFrom(fooClass) with fooClass.isArray()
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
fooClass.isArray();
and it would also work for a primitive array class.
I've run a small "test"
class Test {
public static void main(String[] args) {
Predicate<Class<?>> p = c -> Collection.class.isAssignableFrom(c) ||
c.isArray();
System.out.println(p.test(new int[0].getClass()));
System.out.println(p.test(new Integer[0].getClass()));
System.out.println(p.test(Collections.emptyList().getClass()));
System.out.println(p.test(Collections.emptySet().getClass()));
System.out.println(p.test(Collections.emptyMap().getClass()));
}
}
which results in
true
true
true
true
false
Regarding a generic loop that would run over both arrays and
collections:
You simply can't write an accurate construction to handle this: Collection (or Iterable) and Object[] have little in common (Object as a common parent and its methods are not enough).
I think it's sensible to build own abstraction which would treat collections and arrays in the same manner. Having no particular context, I can come up with a simple idea of two subclasses, each of which defining how its source (either a collection or an array) should be iterated. Then, programming to an interface will help to manage them equally.
A very simplified example would be:
interface Abstraction<T> {
void iterate(Consumer<? super T> action);
static <T> Abstraction<T> of(Collection<T> collection) {
return new CollectionAbstraction<>(collection);
}
static <T> Abstraction<T> of(T[] array) {
return new ArrayAbstraction<>(array);
}
static IntArrayAbstraction of(int[] array) {
return new IntArrayAbstraction(array);
}
}
class CollectionAbstraction<T> implements Abstraction<T> {
Collection<T> source;
public CollectionAbstraction(Collection<T> source) {
this.source = source;
}
#Override
public void iterate(Consumer<? super T> action) {
source.forEach(action);
}
}
class ArrayAbstraction<T> implements Abstraction<T> {
T[] source;
public ArrayAbstraction(T[] source) {
this.source = source;
}
#Override
public void iterate(Consumer<? super T> action) {
for (T t : source) {
action.accept(t);
}
}
}
class IntArrayAbstraction implements Abstraction<Integer> {
int[] source;
public IntArrayAbstraction(int[] source) {
this.source = source;
}
#Override
public void iterate(Consumer<? super Integer> action) {
for (int t : source) {
action.accept(t);
}
}
}
class Test {
public static void main(String[] args) {
Abstraction.of(new Integer[] {1, 2, 3}).iterate(System.out::println);
Abstraction.of(Arrays.asList(1, 2, 3)).iterate(System.out::println);
Abstraction.of(new int[] {1, 2, 3}).iterate(System.out::println);
}
}
I believe the approach above is pretty versatile. You don't depend on how a certain source is iterated, you may selectively modify them.
The other answers are all trying hard to answer the original title question:
Is there a common interface or superclass for arrays and collections?
But your real question is in the body:
Are there any other possibilities to handle both in one loop like the above?
The answer is: No, there's no way to write a single for loop that iterates over both collections and arrays.
You could jump through a bunch of hoops to turn the arrays into lists, but you'll almost certainly end up with a bigger mess than if you just wrote two (or more) loops. Calling getClass().isArray() tells you what you have but you still can't work with it without some sort of cast. Arrays.asList() doesn't work for arrays of primitives.
Depending on what you are trying to do, you might want to implement two similar methods:
public <T> void iterateOver(List<T> list) {
// do whatever you want to do with your list
}
public <T> void iterateOver(T[] array) {
this.iterateOver(Arrays.asList(array));
}
Or maybe even have an interface for this:
interface ExtendedIterableConsumer<T> {
public void iterateOver(List<T> list);
public default void iterateOver(T[] array) {
this.iterateOver(Arrays.asList(array));
}
I am not sure if that helps you, because you seem to already have the object in question in a variable somewhere. But if you can address that problem one level higher, it might be useful.
You can check if object is array by using isArray() method from Class
if (foo != null && (foo.getClass().isArray() || foo instanceof Collection<?>)){
}
Edit:
In terms of iterating over this foo object, there is no simple solution. However you could try something like this:
private void iterate(#NotNull Object foo) {
if (foo instanceof Collection<?>) {
for (Object o : ((Collection<?>) foo)) {
chandleYourObject(o);
}
}
if (foo.getClass().isArray()) {
if (foo.getClass().isPrimitive()) {
checkPrimitiveTypes(foo);
}
if (foo instanceof Object[]) {
for (Object o : (Object[]) foo) {
chandleYourObject(o);
}
}
}
}
private void checkPrimitiveTypes(Object foo) {
if (foo instanceof int[]) {
for (int i : (int[]) foo) {
}
}
//And the rest of primitive types
}
private void chandleYourObject(Object o ){
//What you want to do with your object
}
You could write a helper method for this:
#SuppressWarnings("unchecked")
public static <E> void forEach(Object arrayOrIterable, Consumer<? super E> action) {
Objects.requireNonNull(arrayOrIterable);
if (arrayOrIterable instanceof Iterable) {
for (Object o : (Iterable<?>) arrayOrIterable) {
action.accept((E) o);
}
} else if (arrayOrIterable.getClass().isArray()) {
int length = Array.getLength(arrayOrIterable);
for (int i = 0; i < length; i++) {
action.accept((E) Array.get(arrayOrIterable, i));
}
} else {
throw new IllegalArgumentException("not an array nor iterable: " + arrayOrIterable.getClass());
}
}
The second branch makes use of the java.reflect.Array class which provides helper methods (may be slow), to get the length of an array and the element at a given index.
You may call it like this:
int[] ints = {1, 2, 3, 4};
forEach(ints, (Integer i) -> System.out.println(i));
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
forEach(ints, (Integer i) -> System.out.println(i));
Due to the nature of generics, this method may throw a ClassCastException, e.g. this call:
int[] ints = {1, 2, 3, 4};
forEach(ints, (String s) -> System.out.println(s));
Would result in:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Arrays are Objects:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html
AbstractCollections also extend Object:
https://docs.oracle.com/javase/8/docs/api/java/util/AbstractCollection.html
So yes there is a common superclass, but unfortunately this isn't really going to help you.
I would suggest your best bet is to use:
List<> someList = Arrays.asList(sourceArray)
This will convert your array into a collection that implements Iterable. You will of course need to work out if the initial object is an Array or a Collection in advance and only call the above if it is an array, here are some options for doing that:
boolean isArray = myArray.getClass().isArray();
boolean isCollection = Collection.class.isAssignableFrom(myList.getClass());
Is there a way in Java to create a method that would return the list of parameters of another method such that I am able to call
anotherMethod(method())
where anotherMethod has arbitrary arguments like
public void anotherMethod(int a, int b, String c)
And what is if the types stay the same, like with
public int add(int a, int b, int c)
If there is no such way, how could I model the list of parameters such that it would work? Is it a List or an array or something else?
If the number of parameters is fixed at the call site, you could use varargs
int add(int... numbers)
otherwise you'd use an array or collection
int add(int[] numbers)
You can then of course have another method provide the value of these parameters:
add(someOtherMethod())
Varargs
Java has a built-in feature to denote a variable length of arguments. It is called varargs (documentation) (variable arguments) and it only works if the type stays the same. The syntax for a method is like this:
public int add(int... values)
Note the int... values which denotes varargs. A caller can now call the method like
add(null) // Passing null
add(values) // Passing an int[]
add() // No arguments
add(a) // One int
add(a, b) // Two ints
add(a, b, c) // Three ints
add(a, b, c, d) // Four ints
...
Note the three special cases null, int[] and empty.
What Java does is it will convert the arguments into an array. So inside the method values will be a regular int[]. You could thus implement the method like
public int add(int... values) {
int sum = 0;
for (int value : values) {
sum += value;
}
return sum;
}
If you, as a caller, want to pass the return value of a function you just need to make sure that it returns an array like int[]. So the following would work:
public int[] valueProvider() {
int[] values = ...
return values;
}
and then call it like
int sum = add(valueProvider());
Collection, Iterable and Stream
Besides that, if you don't want to use varargs or arrays, you can use Collections (documentation). A collection may be a List or a Set and so on. For example you could declare
public int add(Collection<Integer> values)
and feed it like
Collection<Integer> values = new ArrayList<>();
values.add(1);
values.add(2);
int sum = add(values);
An Iterable<Integer>, in contrast to Collection<Integer> would even be more flexible.
Using a Stream (documentation) would also work like a charm and is probably one of the most flexible variants since the source of a stream could be anything and nearly anything of the standard library supports a stream representation.
Changing type
Now note that what you searched for in the beginning, a method that is able to feed arbitrary arguments, is not possible in Java.
The main problem is that the types may change, so you may have a method like
public void doSomething(int first, String second, File third)
and you won't be able to feed the method with varargs, Collections or any of the presented methods.
In that case you will need a wrapper class like
public class DoSomethingArguments {
private int mFirst;
private String mSecond;
private File mThird;
public DoSomethingArguments(int first; String second, File third) {
this.mFirst = first;
this.mSecond = second;
this.mThird = third;
}
// Some getters
}
(or a generic tuple class, a triple in this case)
But then you would need to change the method to
public void doSomething(DoSomethingArguments arguments)
what is probably not what you wanted since you probably intended to not change the signature of doSomething.
But unfortunately there is no way to feed a method like this in such a way.
There is nothing that works the way you wish for at compile time. As the other answers are pointing out, there are varargs. But that is just syntactical sugar. That is just the compiler implicitly creating an array of a certain type for you.
But beyond that, there is reflection. Reflection allows you to dynamically inspect classes and methods at *runtime.
In other words: you can do something like
Object whatever = ...
Class<?> someClass = whatever.getClass();
And now you can ask someClass about the methods it has. And which parameters they need.
But as said: all of that is runtime only. And it the reflection APIs are very easy to get wrong. And you only find out at runtime, when some exception is thrown.
There is not direct way to pass multiple values in the way you want. But you can use a indirect way to pass a group of values of different type. I can think of two ways but their can be more.
Firs - Use a map, just insert the values you want to pass in the collection and pass the collection to the second method.
Second - Create a bean (Java POJO) to pass as parameter to the consuming method.
A small sample code.
class Sample{
private int a;
private String b;
private int c;
Sample(int a,String b,int c){
this.a = a;
this.b = b;
this.c = c;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public int getC() {
return c;
}
public void setC(int c) {
this.c = c;
}
}
public class PassingExample {
public void consumerofInputs (Map<Integer, Object> input)/*(int a, String b, int c)*/{
System.out.println("I use three different inputs : int, string and int");
for (Map.Entry<Integer, Object> entry : input.entrySet()) {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}
}
public Map producingInput() {
Map<Integer, Object> input = new HashMap<Integer, Object>();
input.put(1, 10);
input.put(2, "input");
input.put(3, 89);
return input;
}
public Sample createClassAsInput(){
Sample input = new Sample(10,"class-input",30);
return input;
}
public void useSampleAsInput(Sample input){
System.out.println("\nUsing Class as input \nInt::"+input.getA()+"\nString::"+input.getB()+"\nInt::"+input.getC());
}
public static void main(String[] args) {
PassingExample example = new PassingExample();
example.consumerofInputs(example.producingInput());
example.useSampleAsInput(example.createClassAsInput());
}
}
Is there any way in Java to create a method, which is expecting two different varargs?
I know, with the same object kind it isn't possible because the compiler doesn't know where to start or to end. But why it also isn't possible with two different Object types?
For example:
public void doSomething(String... s, int... i){
//...
//...
}
Is there any way to create a method like this?
Thank you!
Only one vararg, sorry. But using asList() makes it almost as convenient:
public void myMethod(List<Integer> args1, List<Integer> args2) {
...
}
-----------
import static java.util.Arrays.asList;
myMethod(asList(1,2,3), asList(4,5,6));
In Java, only one varargs argument is allowed and it must be the last parameter of the signature.
But all it does it convert it to an array anyway, so you should just make your two parameters explicit arrays:
public void doSomething(String[] s, int[] i){
A possible API design in which the calling code looks like
doSomething("a", "b").with(1,2);
through "fluent" API
public Intermediary doSomething(String... strings)
{
return new Intermediary(strings);
}
class Intermediary
{
...
public void with(int... ints)
{
reallyDoSomething(strings, ints);
}
}
void reallyDoSomething(String[] strings, int[] ints)
{
...
}
The danger is if the programmer forgot to call with(...)
doSomething("a", "b"); // nothing is done
Maybe this is a little better
with("a", "b").and(1, 2).doSomething();
Only one vararg is allowed. This is because multiple vararg arguments are ambiguous. For example, what if you passed in two varargs of the same class?
public void doSomething(String...args1, String...args2);
Where does args1 end and args2 begin? Or how about something more confusing here.
class SuperClass{}
class ChildClass extends SuperClass{}
public void doSomething(SuperClass...args1, ChildClass...args2);
ChildClass extends SuperClass, and so is can legally exist in args1, or args2. This confusion is why only one varargs is allowed.
varargs must also appear at the end of a method declaration.
Just declare the specific type instead as 2 arrays.
Although this kind of thing is occasionally useful, usually if you find that you are hitting a restriction in Java you could probably redesign something and come out much better. Here are some possible other ways to look at it...
If the two lists are related at all you probably want to create a wrapper class for the two different lists and pass in the wrapper. Wrappers around collections are almost always a good idea--they give you a place to add code that relates to the collection.
If this is a way to initialize data, parse it from a string. For instance, "abc, 123:def, 456:jhi,789" is almost embarassingly easy to split up with 2 split statements and a loop (2-3 lines of code). You can even make a little custom parser class that parses a string like that into a structure you feed into your method.
Hmm--honestly asside from initializing data I don't even know why you'd want to do this anyway, any other case and I expect you'd be passing in 2 collections and wouldn't be interested in varags at all.
You can do something like this, then you can cast and add additional logic inside that method.
public void doSomething(Object... stringOrIntValues) {
...
...
}
And use this method like so:
doSomething(stringValue1, stringValue2, intValue1, intValue2,
intValue3);
This is an old thread, but I thought this would be helpful regardless.
The solution I found isn't very neat but it works. I created a separate class to handle the heavy lifting. It only has the two variables I needed and their getters. The constructor handles the set methods on its own.
I needed to pass direction objects and a respective Data object. This also solves the possible problem of uneven data pairs, but that is probably only for my usage needs.
public class DataDirectionPair{
Data dat;
Directions dir;
public DataDirectionPair(Data dat, Directions dir) {
super();
this.dat = dat;
this.dir = dir;
}
/**
* #return the node
*/
public Node getNode() {
return node;
}
/**
* #return the direction
*/
public Directions getDir() {
return dir;
}
}
I would then just pass this class as the vararg for the method
public void method(DataDirectionPair... ndPair){
for(DataDirectionPair temp : ndPair){
this.node = temp.getNode();
this.direction = temp.getDir();
//or use it however you want
}
}
It is not possible because the Java Language Specification says so (see 8.4.1. Formal Parameters):
The last formal parameter of a method or constructor is special: it
may be a variable arity parameter, indicated by an ellipsis
following the type.
Note that the ellipsis (...) is a token unto itself (ยง3.11). It is possible to put whitespace between it and the type, but this is
discouraged as a matter of style.
If the last formal parameter is a variable arity parameter, the method
is a variable arity method. Otherwise, it is a fixed arity method.
As to why only one and only the last parameter, that would be a guess, but probably because allowing that could lead to undecidable or ambiguous problems (eg consider what happens with method(String... strings, Object... objects)), and only allowing non-intersecting types would lead to complications (eg considering refactorings where previously non-intersecting types suddenly are), lack of clarity when it does or does not work, and complexity for the compiler to decide when it is applicable or not.
I just read another question about this "pattern", but it is already removed, so I would like to propose a different approach to this problem, as I didn't see here this solution.
Instead to force the developer to wrapping the inputs parameter on List or Array, it will be useful to use a "curry" approach, or better the builder pattern.
Consider the following code:
/**
* Just a trivial implementation
*/
public class JavaWithCurry {
private List<Integer> numbers = new ArrayList<Integer>();
private List<String> strings = new ArrayList<String>();
public JavaWithCurry doSomething(int n) {
numbers.add(n);
return this;
}
public JavaWithCurry doSomething(String s) {
strings.add(s);
return this;
}
public void result() {
int sum = -1;
for (int n : numbers) {
sum += n;
}
StringBuilder out = new StringBuilder();
for (String s : strings) {
out.append(s).append(" ");
}
System.out.println(out.toString() + sum);
}
public static void main(String[] args) {
JavaWithCurry jwc = new JavaWithCurry();
jwc.doSomething(1)
.doSomething(2)
.doSomething(3)
.doSomething(4)
.doSomething(5)
.doSomething("a")
.doSomething("b")
.doSomething("c")
.result();
}
}
As you can see you in this way, you could add new elements of which type you need when you need.
All the implementation is wrapped.
If you are not going to be passing a large number of Strings most of the time for the first argument you could provide a bunch of overloads that take different numbers of Strings and wrap them in an array before calling a method that takes the array as the first argument.
public void doSomething(int... i){
doSomething(new String[0], i);
}
public void doSomething(String s, int... i){
doSomething(new String[]{ s }, i);
}
public void doSomething(String s1, String s2, int... i){
doSomething(new String[]{ s1, s2 }, i);
}
public void doSomething(String s1, String s2, String s3, int... i){
doSomething(new String[]{ s1, s2, s3 }, i);
}
public void doSomething(String[] s, int... i) {
// ...
// ...
}
follwing on Lemuel Adane (cant comment on the post, due to lack of rep :))
if you use
public void f(Object... args){}
then you may loop using How to determine an object's class (in Java)?
like for instance
{
int i = 0;
while(i< args.length && args[i] instanceof String){
System.out.println((String) args[i]);
i++ ;
}
int sum = 0;
while(i< args.length){
sum += (int) args[i];
i++ ;
}
System.out.println(sum);
}
or anything you intend to do.
You can convert your varargs to arrays
public void doSomething(String[] s, int[] i) {
...
}
then with some helper methods to convert your varargs to array like this:
public static int[] intsAsArray(int... ints) {
return ints;
}
public static <T> T[] asArray(T... ts) {
return ts;
}
Then you can use those helper methods to convert your vararged parameters.
doSomething(asArray("a", "b", "c", "d"), intsAsArray(1, 2, 3));
I've got a question.
public class Jaba {
public static void main(String args[]) {
Integer i = new Integer(0);
new A(i);
System.out.println(i);
new B(i);
System.out.println(i);
int ii = 0;
new A(ii);
System.out.println(ii);
new B(ii);
System.out.println(ii);
}
}
class A {
public A(Integer i) { ++i; }
}
class B {
public B(int i) { ++i; }
}
To my mind passing an int\Integer as Integer to a function and making ++ on that reference should change the underlying object, but the output is 0 in all the cases. Why is that?
Most of the classes such as Integer that derive from Java's abstract Number class are immutable., i.e. once constructed, they can only ever contain that particular number.
A useful benefit of this is that it permits caching. If you call:
Integer i = Integer.valueOf(n);
for -128 <= n < 127 instead of:
Integer i = Integer.new(n)
you get back a cached object, rather than a new object. This saves memory and increases performance.
In the latter test case with a bare int argument, all you're seeing is how Java's variables are passed by value rather than by reference.
#Alnitak -> correct. And to add what really happens here. The ++i due to autoboxing works like that:
int val = Integer.intValue(); ++val;
and val is not stored anywhere, thus increment is lost.
As said in the other answers, Java does only call-by-value, and the ++ operator only effects a variable, not an object. If you want to simulate call-by-reference, you would need to pass a mutable object, like an array, and modify its elements.
The Java API has some specialized objects for this, like java.util.concurrent.atomic.AtomicInteger (which additionally also works over multiple threads), and org.omg.CORBA.IntHolder (used for call-by-reference for remote calls by the CORBA mechanism).
But you can also simply define your own mutable integer:
class MutableInteger {
public int value;
}
class C {
public C(int[] i) {
++i[0];
}
}
class D {
public D(MutableInteger i) {
++i.value;
}
}
class E {
public E(AtomicInteger i) {
i.incrementAndGet();
}
}
public class Jaba {
public static void main(String args[]) {
int[] iii = new int[]{ 0 };
System.out.println(iii[0]);
new C(iii);
System.out.println(iii[0]);
MutableInteger mi = new MutableInteger();
System.out.println(mi.value);
new D(mi);
System.out.println(mi.value);
MutableInteger ai = new AtomicInteger(0);
System.out.println(ai);
new E(ai);
System.out.println(ai);
}
}
If you want to use reference parameter then try this.
IntHolder
http://docs.oracle.com/javase/7/docs/api/org/omg/CORBA/IntHolder.html