I am trying to write a generic method printAll which prints an array of integer or character.
Here's the code:
public static void main(String[] args) {
char cArray[] = {'a','b','c','d'};
int iArray[] = {1,2,3,4};
printAll(iArray); // Error at this line--refer below the code
}
public static <T> void printAll(T[] t){
for(T x:t) {
System.out.println(x);
}
}
Error: Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - Erroneous tree type: <.any>
printAll(T[] t) will not accept primitive type arrays. You need to pass arrays of the respective wrapper types:
Character cArray[] = {'a','b','c','d'};
Integer iArray[] = {1,2,3,4};
But, you don't need to frame your own method. Just use the already existing - Arrays.toString() method, which is overloaded for different types of primitive arrays, and Object[] array.
Do not reinvent the wheel, use Arrays.toString or Arrays.deepToString. The former already is overloaded to support arrays of primitive (as noted in the first link that receives a char[]), the latter works only on arrays of class references objects.
You cannot use primitive types with generics. Use Integer (or the corresponding reference type)
Integer iArray[] = {1,2,3,4};
printAll(iArray);
You can always overload the printAll method for each of the primitive types.
I don't believe in doing peoples work for them, more to inform and teach how it can be done.
one easy and simple way to print arrays in java will be done through converting the array to a string then print. This works best as array lists. This can then be manipulated to print in a better format.
for example make an array list and add some values:
ArrayList<String> Array = new ArrayList<String>();
Array.add(1)
Array.add(2)
Array.add(3)
Array.add(4)
Array.add(5)
Then from here this can be printed by changing it to a string:
String str = Array.toString()
System.out.println(str);
this will print the following:
[1,2,3,4,5]
you can then change the format of this by using replaceALL on the string before you print it:
String str = Array.toString().replaceAll("[\\[\\]]","")
This will now give:
1,2,3,4,5
That is pretty much it, from here you could add extra things like System.lineSeparator which you would use to replace thhe "," with a new line.
String str = Array.toString().replaceAll("[\\[\\]]","").replaceAll(",",System.lineSeparator());
This would make it print out like:
1
2
3
4
5
class Generic {
public static<T> void printArray(T[] list) {
for(T in : list) {
System.out.println(in);
}
}
public static void main(String[] args) {
String[] lit=new String[3];
lit[0]="aiq";
lit[1]="abusov";
lit[2]="java";
printArray(lit);
}
}
Related
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));
class VarArgs {
public static void printArray(Object... args) {
for (Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
public static void main(String[] args) {
printArray( new Integer[] { 1, 2, 3 });
}
}
The console's output is:
[Ljava.lang.Integer;#1888759
just want to know what is this output. The supposed castiing was via Object[] and that gives 1,2,3 as output, but when I use Object for casting I get this output
You can use
Arrays.toString(new Integer[]{1,2,3});
to view the actual contents of the array.
Or cast new Integer[]{1,2,3} to Object[] instead of Object, i.e:
printArray((Object[])new Integer[]{1,2,3});
Explanation of what is happening in your code:
When you are calling the printArray method you are casting your array to an Object so in fact you are passing just one object (not an array).
The foreach loop in the printArray method iterates only once as only one argument has been passed to the printArray method - the Integer[] {1,2,3} array.
Therefore When your code is calling toString, the toString from the Array class is called, not the toString from the Integer class as you might expect.
Finally the result you got: [Ljava.lang.Integer;#1888759 is caused by the lack of the implementation of the toString method in the array classes in Java.
To fix the issue in your code:
Replace:
printArray((Object)new Integer[]{1,2,3});
with:
printArray((Object[])new Integer[]{1,2,3});
To print the content of an array call:
Arrays.toString(new Integer[]{1,2,3});
As Marco said, this uses the default toString method of an Object, which is its (virtual) memory address.
I would recommend using the Arrays.toString method here
With regards to your use of variable arguments - try disassembling the class file by running
javap -verbose VarArgs
to see what this compiles down into - you should see that your integer array is being passed as the single element of an array.
That is not the same as passing an array! That is the same as passing a variable length of parameters, so the method treats the array as one object, not an array of objects, hence the printout.
public static void printArray(Object[] args) {
for (Object o : args) {
System.out.println(o);
}
}
Object[] objects = new Integer[] { 1, 2, 3, 4 };
printArray(objects);
Notice that you need to use the wrapper for int, primitive types are not subclasses of object.
I have a class arrayFun with the variable
int[] _array;
I have a method setArray:
public void setArray(int [] array)
{
_array = array;
}
Is my set method implementation correct ?
2).How can I use this method in other class with main ?
I've tried some ridiculous options like:
arrayFun A = new arrayFun(some_constructor_values);
A.setArray(1,2,3,4,5);
That option of course doesn't work...
Try
A.setArray(new int[]{1,2,3,4,5});
Another way to solve this declare the argument as a "varargs" argument as follows:
public void setArray(int ... array) {
_array = array;
}
and then this will work:
A.setArray(1, 2, 3, 4, 5);
You can do the same with a constructor argument.
While I have your attention, it is important that you learn the Java naming conventions, and learn to follow them strictly.
A class name should always start with an uppercase letter
A variable name should always start with a lowercase letter ... unless it is a static final constant.
Using an underscore as a prefix generally frowned on.
For more information, read the Java Style Guidelines.
So your example class should look like this:
public class ArrayFun {
private int[] array;
public void setArray(int ... array) {
this.array = array;
}
}
and should be used like this:
ArrayFun a = new ArrayFun();
a.setArray(1, 2, 3, 4, 5);
You can use this instead
public void setArray(int... array) { _array = array; }
// later
ArrayFun a = new ArrayFun(some_constructor_values);
a.setArray(1,2,3,4,5);
Unless you take a copy of the array, you will be using the same array in the caller and callee.
What you're asking to do doesn't really make sense. Also, why use a function to "set the array", why not just set the array directly:
_array = newArray
You can also set an array's values like this:
int[] array = {1,2,3,4,5};
Your method's signature is :
public void setArray(int[] array)
So it accepts only one argument that is of type array of integers.
But in your method call, you are calling it as:
A.setArray(1,2,3,4,5);
In this you are passing 5 arguments to the method. So it does not match any method with 5 arguments. Thats why it does not work.
You should pass one array of integers.
You can do it in various ways :
int myArr[] = {1,2,3,4,5};
A.setArray(myArr);
or
A.setArray(new int[]new int[]{1,2,3,4,5});
Setting array the way you did is fine. But what you are setting from A.setArray(1,2,3,4,5); will throw you error saying "Method setArray(int,int,int,int,int) is not found".
You can do something like int[] ar = { 1, 2 };
a.setArray(ar);
I have the following code in Java:
public static<T> void doIt(Class<T> t)
{
T[] arr;
arr = (T[])Array.newInstance(t, 4);
}
I want to be able to use doIt using both primitive type such as double and using class objects such as String.
I could do it by using (code compiles):
doIt(double.class);
doIt(String.class);
However, I am worried that in the first case, the Java compiler will actually wrap the double primitive type using a Double class, which I don't want. I actually want it to instantiate a primitive array in this case (while instantiating an objects array with the String case). Does someone know what happens with doIt(double.class)? Is it instantiated as Double or double?
Thanks.
You couldn't actually make T = double here - Java generics simply don't work with primitive types. However, you can still instantiate your array:
import java.lang.reflect.*;
public class Test {
public static void main(String[] args) {
createArray(double.class);
}
private static void createArray(Class<?> clazz) {
Object array = Array.newInstance(clazz, 4);
System.out.println(array.getClass() == double[].class); // true
}
}
It really depends on what you want to do with the array afterwards.
You can make an array of primitive double like this:
double[] arr = (double[]) Array.newInstance(double.class, 0);
But you can't make this work with generics, because generic parameters are always reference types, not primitive types.
Generics will work with objects so it should be a Double after boxing.
You can create a method that takes an array type instead of the element type and get around the problem that type parameters must be reference types since all array types are reference types.
<T> T doIt(Class<T> arrayType) {
assert arrayType.getElementType() != null;
return <T> Array.newInstance(arrayType.getElementType(), 4);
}
Consider the method declaration:
String.format(String, Object ...)
The Object ... argument is just a reference to an array of Objects. Is there a way to use this method with a reference to an actual Object array? If I pass in an Object array to the ... argument - will the resultant argument value be a two-dimensional array - because an Object[] is itself an Object:
Object[] params = ....; // Make the array (for example based on user-input)
String s = String.format("%S has %.2f euros", params);
So the first component of the array (Which is used in the String.format method), will be an array and he will generate:
[class.getName() + "#" + Integer.toHexString(hashCode())]
and then an error because the array size is 1.
The bold sequence is the real question.
This is a second question: Does a ... array/parameter have a name?
From the docs on varargs:
The three periods after the final
parameter's type indicate that the
final argument may be passed as an
array or as a sequence of arguments.
So you can pass multiple arguments or an array.
The following works just fine:
class VarargTest {
public static void main(String[] args) {
Object[] params = {"x", 1.2345f};
String s = String.format("%s is %.2f", params);
System.out.println(s); // Output is: x is 1.23
}
}
You can just pass an array:
public void foo(String... args) {
}
String args[] = new String[10];
foo(args);
The situation you are describing is going to be fairly rare: most of the time, your varargs items will be Strings, or numbers, or Widgets... it will be unusual for them to be Objects (which could be anything) or arrays.
But if the varargs argument is a bunch of Objects or an array type, then your question does arise: you can pass it a single array and then how will the compiler know whether you meant to pass an array (the one you provided), or an series of 1 item which it should PUT into an array for you?
A quick test shows the answer:
public class TestClass {
public static void main(String[] args) {
Object anObject = new Object();
Object[] anArray = new Object[] {anObject, anObject};
System.out.println("object1 = " + anObject);
System.out.println("array1 = " + anArray);
takesArgs();
takesArgs(anObject, anObject);
takesArgs(anArray); // is this the same as array1?
takesArgs(anArray, anArray);
}
public static void takesArgs(Object... stuff) {
System.out.println("The array was " + stuff);
}
}
The result of executing (your exact numbers will vary:
object1 = java.lang.Object#3e25a5
array1 = [Ljava.lang.Object;#19821f
The array was [Ljava.lang.Object;#addbf1
The array was [Ljava.lang.Object;#42e816
The array was [Ljava.lang.Object;#19821f
The array was [Ljava.lang.Object;#9304b1
So the answer is that in ambiguous cases it treats what you passed as the array instead of creating a new array to wrap it. This makes sense as you could always wrap it in an array yourself if you wanted the other interpretation.