Semantics of returning arrays - java

When I create a method to determine what value I want to return, usually I can return a value directly - like so:
return 0;
However, I've discovered that when returning arrays, I have to create a new instance of an array, and return it - like so:
String[] rtnArr = {"str1", "str2"};
return rtnArr;
Why is this? Am I creating two arrays here, or am I only specifying a type when I instantiate the method?
Edit: I should clarify that I am returning one or another array based on a preliminary condition. That is to say, I have a switch and each case returns an array of different strings.

You are not creating two arrays. Array initializers are only allowed when initiating a variable, so you can't use them directly in a return statement.

You don't actually need a variable to return an array. You can also return an array like this
return new String[] {"Hello", "World"};
When you declare an array you can initialize it as String test[] = {"Hello", "World"}; because the array is obviously a string array so you don't need to do new String[] {"Hello", "World"}, but otherwise, you need an explicit initialization of the array with a type for type safety.

I've discovered that when returning arrays, I have to create a new instance of an array, and return it Why is this ? Am I creating two arrays here, or am I only specifying a
type when I instantiate the method ?
You don't need to return a new instance of the array always, sometimes you might need to return an existing array object as shown in the below code:
public class MyArrayTest {
private String[] myArray;
public MyArrayTest(String[] myArray) {
this.myArray = myArray;
}
public String[] getMyArray() {
return myArray;//returning existing array object
}
}

Related

How to cast a multidimensional array without knowing the dimension in Java

There is a multidimensional String array being passed in as an Object.
I'm supposed to "unfold" it and process each of its primitive entries.
There's no way to know the dimensions other than by looking at the Object itself.
The difficulty i'm having is in casting. I can look up the array dimension by invoking its getClass().getName() and counting the [-s there.
But then how to cast it?
String[] sa = (String[]) arr;
is giving
Exception in thread "main" java.lang.ClassCastException: [[Ljava.lang.String; cannot be cast to [Ljava.lang.String;
Can this casting be done without any use of reflection?
Note - The array can be of any dimension - not just 1 or 2.
TIA.
If you want to work with an array which dimension is not known at the compile time, I would suggest you to recursively process all of its entries instead of trying to cast it.
You can use object.getClass().isArray() method to check if the current entry is an array and then iterate over it using Array.getLength(object) and Array.get(object, i):
public static void main(String[] args) {
Object array = new String[][] {new String[] {"a", "b"}, new String[] {"c", "d"}};
processArray(array, System.out::println);
}
public static void processArray(Object object, Consumer<Object> processor) {
if (object != null && object.getClass().isArray()) {
int length = Array.getLength(object);
for (int i = 0; i < length; i ++) {
Object arrayElement = Array.get(object, i);
processArray(arrayElement, processor);
}
} else {
processor.accept(object);
}
}
If the size of the array is not known statically (at compile time), then it's logically impossible to get the length relying solely on static means, i.e. without use of dynamic means.
Perhaps this question has the solution you need:
Getting the field "length" in a Java array using reflection

Return inside a method one or two arrays

Its not duplicated i have read all and nothing suite in my case so please read it and answer it.I have two arrays.One is Vehicle and the other is pin.This is a part of code and it is only the method.
First question :
if i have declare the arrays on the same main out of
this method the way i pass them on the method is right?With other words the parameteres
are good or need (int vehicle[],int pin[]) or something else?
Second question +=
i dont know what it does but i think that in the array pin it takes
as an ecample the pin[1] cost has 10.The number 10 is taken by
getcostosvehicle();(we put it from userinput) so when the array fills
and it hasnt any slot then the costs will be finished.As a result will
have lets say the ended slot is 20 in pin[20] lets say it has 350.The
return statement will give us only the last cost?It would be better to
write return pin[i]; so in that way it will return all the pin with
the whole costs of each one slot,am i right?
Third question
On this code and that i want to write me as an answer could you return
two arrays?I mean return pin[i],vehicle[i]; not only return pin[i];.If
yes,could you do an answer and doesnt need to fill in the vehicle
array.Just to show me if this can happen.
public static int getallcosts(vehicle[],pin[]) {
int costos = 0;
for(int i =0; i < pin.length; i++) {
costos += pin[i].getcostosvehicle();
}
return costos;
}
if i have declare the arrays on the same main out of this method the way i pass them on the method is right?With other words the parameteres are good or need (int vehicle[],int pin[]) or something else?
I'm not sure I understand you correctly but of course getallcosts(vehicle[],pin[]) won't compile, i.e. you need to define the type of the arrays (or the names if vehicle and pin would actually be the types).
It would be better to write return pin[i]; so in that way it will return all the pin with the whole costs of each one slot,am i right?
No, you can only have one return value. If you want to return multiple values then you need to wrap them in an object (array, list, pojo, etc.).
On this code and that i want to write me as an answer could you return two arrays?
See the part above: if you want to return multiple arrays you need to add them so some object and return that object. Since you didn't provide the types for the arrays I'll use another example:
class Result {
String[] strings;
int[] numbers;
}
Result someMethod() {
Result r = new Result();
r.strings = new String[]{"a","b","c"};
r.numbers= new int[]{1,2,3};
return r;
}
First question:
If you are calling a method (so you're not defining it) yuo can write parameters as you do, without type.
Otherwise you need to specify type. In this case you are defining a new method so you need to specify type of parameters.
Second question:
'+=' it's like write
costos = costos + pin[i].getcostosvehicle();
So you will add to the current value of 'costos' the 'costos' of vehicle retrieved by 'getcostosvehicle()';
Third question:
As i know you can't return two Objects of any type in return statement.
So you'll need to reorganize your code to do operation first on an array and return it and then on the other one and return it.
For example you can do a method that have as parameter a generica array do some logic inside and then return it. You will call this method for the first array and then for the second.
Example:
public int[] method(int[] array){
/*do something
*/
return array;
}
Then you will call:
firstArray = method(firstArray);
secondArray = method(secondArray);
If you want more, or i have to change something comment please.

Is a final array of final strings still mutable?

Suppose I have an array
public static final String[] fooArray ={ Foo.a, Foo.b, Foo.c };
where Foo.a b and c are static final Strings.
Could I still do something like fooArray[0] = "taco"; and end up with { taco, Foo.b, Foo.c } as the contents of fooArray?
If so, would making the array private, and having a getter that makes a copy of the array using Arrays.copyOf solve this issue?
The final applies to the array reference, not its entries. Different strings can still be written to its entries.
If so, would making the array private, and having a getter that makes a copy of the array using Arrays.copyOf solve this issue?
Yes, defensive copies are a fairly standard way to handle this.
Alternately, given what you've outlined, you don't need to have the array at all, just a getter that looks like this:
public String[] getFooArray() {
return new String[] { Foo.a, Foo.b, Foo.c };
}
Or as jtahlborn commented, use an unmodifiable List<String>:
public static final List<String> fooArray;
static {
List<String> a = new ArrayList<>();
Collections.addAll(a, Foo.a, Foo.b, Foo.c);
fooArray = Collections.unmodifiableList(a);
}
// (There's probably some really nifty Java8 way to do that as a one-liner...
Yes.
A final array means you can't reassign the array.
So you couldn't do: fooArray = new String[]{...};.
But you can however change what is inside the array. This is the effect of saying: "You can't change the box, but you can change the apples inside the box to be oranges." The box stays the same, and is final, but you've effectively changed the contents.
That being said, if you encapsulate the class, then you can just clone the array when it is needed.
This is currently employed by many classes, such as String#toCharArray and Enum#values, where changing the array's contents comprises the integrity of the finalized object(s).
The final-modifier will only prevent changing the fooArray-reference, not the contents of the array itself. Making it private and having a getter returning a copy would hide the original array, and any changes made to the returned array would only affect the copy. However, it would still be possible to modify the original via reflection, but if your intent is to only prevent accidental modification of the original array, that would work.
Rest have answered about the final well. Just a suggestion on the other part - rather than implementing a getter which does a copy of entire array, if your scenario allows, its better to have a getArrayElement(int position) where you just return an array element rather than the whole array - copying an array is expensive.
You could make a getter that returns a mutable copy of an immutable value.
If you used array copy the values inside the copy will still be final.
public class HelloWorld{
public static void main(String []args){
System.out.println("Hello World");
final int b = 5;
int c = b; // Because of c being mutable we can now change this copy
c = 7;
System.out.println(c);
}
}
... Some psudo code -> for copying an iterable into a mutable form.
public collection<int>(final collection<final int> finalCollection )
collection nonFinalCollection = new collention();
for(k : finalCollention){collection.add((int) k)}
return(collection)

What does int[]... arrays mean in Java?

Can you help me? What does int[]... arrays mean in Java?
Example:
public static int[] concat(int[]... arrays) {
int length = 0;
for (int[] array : arrays) {
length += array.length;
}
That is called varargs.. notation,
So that you can pass individual int[] objects to that method,, without worrying of no.of arguments.
When you write
public static int[] concat(int[]... arrays) {
Now you can use that method like
Classname.concat(array1,array2,array3) //example1
Classname.concat(array1,array2) //example2
Classname.concat(array1,array2,array3,array4) //example3
A clear benefit is you need not to prepare an array to pass a method. You can pass values of that array directly.
It means that the concat function can receive zero or more arrays of integers (int[]). That's why you can loop over the arrays argument, accessing one of the arrays contained in each iteration - if any. This is called variable arguments (or varargs).
Check this other question for more info.
This means, that you can pass zero, one or more arrays of int (int[]) to your method. Consider following example
public void method(String ... strings)
can be called as
method()
method("s")
method("s", "d")
...
So your method can be called as
concat()
concat(new int[0])
concat(new int[0], new int[0])
...
This means that you can pass the method any number of int[] objects:
concat(new int[]{1,2});
concat(new int[]{1,2}, new int[]{3,4,5});
concat(new int[]{1}, new int[]{3,4,5,6}, new int[]{1,1,1,1,1,1,1});
Why this is useful? It's clear why :)
The ... is the most important part, it means you can have an unlimited amount of integers passed in and it is just accessed via the array, so you could call it as:
concat(1,2,3,4,5) or concat(1)
Most languages have this sort of feature, some call it var args others call it params.
varargs ("...") notation basically informs that the arguments may be passed as a sequence of arguments (here - ints) or as an array of arguments. In your case, as your argument is of type "array of int", it means arguments may be passed as a sequence of arrays or as an array of arrays of int (note that array of arrays is quite equivalent to multidimensional array in Java).
For example you have a method:
void functionName (Object objects...)
{
Object object1=objects[0];
Object object2=objects[1];
Object object3=objects[2];
}
You can use your method as:
Object object1,object2,object3;
functionName(object1,object2,object3);
Using Variable Arguments
The ellipsis (...) identifies a variable number of arguments, and
is demonstrated in the following summation method.
public static int[] concat(int[]... arrays)
Use method
concat(val1, val2, val3);
concat(val1, val2, val3, val3);

Java method returning List and a integer

I have a method which reads a file and returns the contents of the text file in a list of String array. Find the implementation of the method and how I read it below. Now I want to have the number of lines in the file as well. I can get it as shown below in the comment - Can you please let me know how can I pass the integer variable as well from the method and read the integer as well?
Below - i.e read file should return List consisting of string arrays and an int as well.
public List<String[]> readFile() {
final List<String[]> userList = new ArrayList<String[]>();
BufferedReader bufferedreader = null;
try {
final String FileName="abs.txt"
bufferedreader = new BufferedReader(new FileReader(FileName));
String line = null;
while ((line = bufferedreader.readLine()) != null) {
// Add Variable ++ to get number of lines
final String[] values = line.split(",");
userList.add(values);
}
}
catch (FileNotFoundException ex) {
logError(ex.getMessage());
}
catch (IOException ex) {
logError(ex.getMessage());
}
finally {
try {
if (bufferedreader != null){
bufferedreader.close();
}
}
catch (IOException ex) {
logError(ex.getMessage());
}
}
return userList;
}
This is how I read it:
List<String[]> usersArray1 = new ArrayList<String[]>();
usersArray1=complianceTracker.readFile();
In this instance, the number of lines in your file corresponds to the number of entries in usersArray1, you can get this as usersArray1.size().
Um, you can't. Java can only return 1 object.
You could make an encapsulating object to hold both the list and the int, or you can make the list you're using untyped and add in the int at the beginning or end, or just take the string value of the int and add it at the beginning or end and parse it later.
Edit: You know what? You're trying to get the int that holds the length of the list. You don't have to do this: lists already know how big they are, and you can retrieve it with size().
You can't return a list of String that also contains an integer. There are several things that can be done to work around this:
Redefine your method to take a List<String> argument; the method fills the list and returns an int.
In the calling code, just use the size() method of List to determine the number of entries after the method returns.
Define a class that contains an int and List<String> field, and return that instead of just the List<String>.
Pass an int[] array as an argument initialized to a single element. Store the integer return value in position 0 of the array. (Requires that the array be at least 1 long when the method is called.)
There are probably other techniques people can come up with.
The simplest answer for this particular case is the one from Mark Elliott, who seems to be the only one who read what readFile() is doing. The number of lines returned is usersArray1.size().
Another minor point. (Repeating your usage example here for reference)
List<String[]> usersArray1 = new ArrayList<String[]>();
usersArray1=complianceTracker.readFile();
The first line is needlessly creating an instance of ArrayList<String[]> which will be ready to be GC'ed after the second line executes. The usersArray1 reference will then refer to the object created on the first line of the readFile() method, leaving no reference referring to the object created when usersArray1 was declared and initialized.
Create a bean.
public class ResultBean
{
private List<String> userArray;
private Integer anotherResult;
//create get set here
}
later your readFile only need to return this resultBean class.
public ResultBean readFile()
{
ResultBean bean = new ResultBean();
//your existing logic here.
bean.setUserArray(new ArrayList<String>()); //please implement your own set here. This is just an example.
bean.setAnotherResult(Integer.valueOf(0));
return bean;
}
Whenever you need to return more than one piece of data, you have two choices, sometimes used together:
Use (write, if necessary) a class wrapping the data to be returned (in this case, a List and an integer).
Pass in as an argument that can hold some of the data, and can be modified by the method at hand.
There are basically two solutions to the problem of returning two things:
Create a class that keeps the two things together (makes a lot of sense if the integer and list of strings are passed around your code a lot).
Use various tricks for returning one (or both) through the parameters, including:
Passing a variable that is a new int[1] to the function, then changing the contents of that "array" in the function and reading from it after the function.
Passing in a class that encapsulates an integer in a mutable way (like an AtomicInteger).
Passing the List object to the function and modifying it (while maintaining the same List reference).
ints are passed by value and not reference by default in java. An easy way around this is to create a small class. Try something like
public class Data
{
public List<String[]> usersArray1;
public int value;
}
you could simply pass this to your method and store both the List of string[]s in there and the int could go in there too. Hope this helps!

Categories

Resources