Behavior of an array after sorting in Java - java

I want to get some views on the behavior of the following program :
package main;
import java.util.Arrays;
public class StringAnagram {
public static void main(String args[]) {
String a = "aabbaabb";
char[] aArr = a.toCharArray();
Arrays.sort(aArr); //1
Arrays.sort(a.toCharArray()); //2
System.out.println(aArr); // Sorted
System.out.println(a.toCharArray()); // UnSorted
}
}
According to me statement 1 sorts the character array referenced by aArr but when it comes to statement 2 the sorting of character array is taking place but somehow the sorted array is not referenced by any variable, so the behavior is lost. Could someone please help me with the same.

Yes. You are right.
Each call to toCharArray() actually creates a new array instance with the characters in the string.
In the case of aArr, you actually refer to the new array instance, you use aArr to sort. Its the array instances referred by the variable aArr which gets sorted.
But when you pass a.toCharArray() to Array.sort() method, you are passing array instance which you don't have a variable referring to. The array instance gets sorted but you don't have any reference.
When you you call println using a.toCharArray() again a new array instance is created and passed to println which is obviously unsorted.

Well, let's see what happens.
First, a.toCharArray() is called. This returns a new char array containing the chars "aabbaabb".
Then, this array is sorted.
You didn't give yourself a way to access the array, so you can't. This is what "lost" means here. Nothing special or magic happened, you just made an array you can't access. It's not going to waste memory - the garbage collector will detect that it can't be accessed, and destroy it.
It's similar to if you just did this without the sorting:
a.toCharArray();
Again, toCharArray goes and makes an array for you, and you don't give yourself a way to use it, so it's also "lost". The sorting was a red herring.

Arrays.sort(a.toCharArray());
This sorts the array returned by a.toCharArray() and not the String a. So whenever you do a.toCharArray() you get a separate(new) Character array of the String. Hence it is unsorted.

Related

Does String object in Java store characters in a char array?

I am solving an assignment where I should not use arrays or collections to sort Integers. I am doing it with strings. I want to know whether strings in java are stored as character array.
Use LinkedList where implementation is not backed by an array.
Yes String does use char array behind the scene
While some are saying to check the Java source, I'll save you some time.
I can guarantee that even starting the JVM uses a collection in some way. That is how fundamental they are to programming. So I'm assuming your assignment takes that into account. Therefore, in this case, I would say for these, your professor means to not explicitly use a collection or array. Avoiding behind the scenes collections is literally impossible.
Don't believe me? Take a look at this code:
public static void main(String [] args) {
// looks like an array to me ^
}
Do note that the String class in Java has a toCharArray() method, so avoid this.

Passing on a Multi-Dimensional Array to another Method in Java

I have numbers[x][y] and int pm2 = 0;. Is there a way to pass on this Mult-Array onto public static boolean checkNumber(int[] list, int num)? <- the parameters has to be used this way.
I invoked checkNumber(numbers[x][y], pm2);
I need to use the checkNumber method to check if a number has already been entered and returns true if the number is present and false if number is absent.
I am allowed to use multiple methods thought so I did have an idea of doing numbers[x][0] , numbers[x][1] etc, etc and invoking them into multiple checkNumber() methods. I was just wondering if there's a shorter way.
You have single dimensional array as parameter.
So you have to pass one at a time probably in loop.
I was just wondering if there's a shorter way.
No there isn't. The Java language doesn't support any kind of array "slicing", and you can't subvert the type system to allow you to refer use an array with a different type to what it really has.
You need to implement your idea of iterating the int[] component array of the int[][], passing each one to checkNumber(int[], int). Something like this:
for (int[] subarray : numbers) {
checkNumbers(subarray, pm2);
}

Calling methods with array output twice in same scope

Suppose you have a method that outputs arrays of different sizes.
Before you use it, you need to create an array reference variable. Before you can do that, you need to find the array length, e.g.
int[] intArray = new int[methodReturnsArray().length]
And then you can set intArray to your array produced by methodReturnsArray().
I feel a bit uneasy about this, because we're calling methodReturnsArray() twice: once to find out how big the array is, and again to set it equal to the reference variable.
Is that wasting resources to call the method twice, or is the array only created once (when you find its size)?
Edit: I know you can just initialize intArray to the method returned by the array. But for some complicated reasons (to do with "methodReturnsArray" being called in a loop with a different-sized array for each iteration) I need to know whether calling twice will waste computational resources.
It depends on how you will then fill new array variable.
But the common approach will be introducing new local variable for saving reference to original array from method methodReturnsArray. i.e.:
int[] methodArray = methodReturnsArray();
int[] intArray = new int[methodArray.length];
...
Then the best way for copying an array is System.arrayCopy(...) method.
This approach will work in any case, and it will prevent you from doing things in method methodReturnsArray twice.

Convert ArrayList<String> to String[] array [duplicate]

This question already has answers here:
Converting 'ArrayList<String> to 'String[]' in Java
(17 answers)
Closed 8 years ago.
I'm working in the android environment and have tried the following code, but it doesn't seem to be working.
String [] stockArr = (String[]) stock_list.toArray();
If I define as follows:
String [] stockArr = {"hello", "world"};
it works. Is there something that I'm missing?
Use like this.
List<String> stockList = new ArrayList<String>();
stockList.add("stock1");
stockList.add("stock2");
String[] stockArr = new String[stockList.size()];
stockArr = stockList.toArray(stockArr);
for(String s : stockArr)
System.out.println(s);
Try this
String[] arr = list.toArray(new String[list.size()]);
What is happening is that stock_list.toArray() is creating an Object[] rather than a String[] and hence the typecast is failing1.
The correct code would be:
String [] stockArr = stockList.toArray(new String[stockList.size()]);
or even
String [] stockArr = stockList.toArray(new String[0]);
For more details, refer to the javadocs for the two overloads of List.toArray.
The latter version uses the zero-length array to determine the type of the result array. (Surprisingly, it is faster to do this than to preallocate ... at least, for recent Java releases. See https://stackoverflow.com/a/4042464/139985 for details.)
From a technical perspective, the reason for this API behavior / design is that an implementation of the List<T>.toArray() method has no information of what the <T> is at runtime. All it knows is that the raw element type is Object. By contrast, in the other case, the array parameter gives the base type of the array. (If the supplied array is big enough to hold the list elements, it is used. Otherwise a new array of the same type and a larger size is allocated and returned as the result.)
1 - In Java, an Object[] is not assignment compatible with a String[]. If it was, then you could do this:
Object[] objects = new Object[]{new Cat("fluffy")};
Dog[] dogs = (Dog[]) objects;
Dog d = dogs[0]; // Huh???
This is clearly nonsense, and that is why array types are not generally assignment compatible.
An alternative in Java 8:
String[] strings = list.stream().toArray(String[]::new);
I can see many answers showing how to solve problem, but only Stephen's answer is trying to explain why problem occurs so I will try to add something more on this subject. It is a story about possible reasons why Object[] toArray wasn't changed to T[] toArray where generics ware introduced to Java.
Why String[] stockArr = (String[]) stock_list.toArray(); wont work?
In Java, generic type exists at compile-time only. At runtime information about generic type (like in your case <String>) is removed and replaced with Object type (take a look at type erasure). That is why at runtime toArray() have no idea about what precise type to use to create new array, so it uses Object as safest type, because each class extends Object so it can safely store instance of any class.
Now the problem is that you can't cast instance of Object[] to String[].
Why? Take a look at this example (lets assume that class B extends A):
//B extends A
A a = new A();
B b = (B)a;
Although such code will compile, at runtime we will see thrown ClassCastException because instance held by reference a is not actually of type B (or its subtypes). Why is this problem (why this exception needs to be cast)? One of the reasons is that B could have new methods/fields which A doesn't, so it is possible that someone will try to use these new members via b reference even if held instance doesn't have (doesn't support) them. In other words we could end up trying to use data which doesn't exist, which could lead to many problems. So to prevent such situation JVM throws exception, and stop further potentially dangerous code.
You could ask now "So why aren't we stopped even earlier? Why code involving such casting is even compilable? Shouldn't compiler stop it?". Answer is: no because compiler can't know for sure what is the actual type of instance held by a reference, and there is a chance that it will hold instance of class B which will support interface of b reference. Take a look at this example:
A a = new B();
// ^------ Here reference "a" holds instance of type B
B b = (B)a; // so now casting is safe, now JVM is sure that `b` reference can
// safely access all members of B class
Now lets go back to your arrays. As you see in question, we can't cast instance of Object[] array to more precise type String[] like
Object[] arr = new Object[] { "ab", "cd" };
String[] arr2 = (String[]) arr;//ClassCastException will be thrown
Here problem is a little different. Now we are sure that String[] array will not have additional fields or methods because every array support only:
[] operator,
length filed,
methods inherited from Object supertype,
So it is not arrays interface which is making it impossible. Problem is that Object[] array beside Strings can store any objects (for instance Integers) so it is possible that one beautiful day we will end up with trying to invoke method like strArray[i].substring(1,3) on instance of Integer which doesn't have such method.
So to make sure that this situation will never happen, in Java array references can hold only
instances of array of same type as reference (reference String[] strArr can hold String[])
instances of array of subtype (Object[] can hold String[] because String is subtype of Object),
but can't hold
array of supertype of type of array from reference (String[] can't hold Object[])
array of type which is not related to type from reference (Integer[] can't hold String[])
In other words something like this is OK
Object[] arr = new String[] { "ab", "cd" }; //OK - because
// ^^^^^^^^ `arr` holds array of subtype of Object (String)
String[] arr2 = (String[]) arr; //OK - `arr2` reference will hold same array of same type as
// reference
You could say that one way to resolve this problem is to find at runtime most common type between all list elements and create array of that type, but this wont work in situations where all elements of list will be of one type derived from generic one. Take a look
//B extends A
List<A> elements = new ArrayList<A>();
elements.add(new B());
elements.add(new B());
now most common type is B, not A so toArray()
A[] arr = elements.toArray();
would return array of B class new B[]. Problem with this array is that while compiler would allow you to edit its content by adding new A() element to it, you would get ArrayStoreException because B[] array can hold only elements of class B or its subclass, to make sure that all elements will support interface of B, but instance of A may not have all methods/fields of B. So this solution is not perfect.
Best solution to this problem is explicitly tell what type of array toArray() should be returned by passing this type as method argument like
String[] arr = list.toArray(new String[list.size()]);
or
String[] arr = list.toArray(new String[0]); //if size of array is smaller then list it will be automatically adjusted.
The correct way to do this is:
String[] stockArr = stock_list.toArray(new String[stock_list.size()]);
I'd like to add to the other great answers here and explain how you could have used the Javadocs to answer your question.
The Javadoc for toArray() (no arguments) is here. As you can see, this method returns an Object[] and not String[] which is an array of the runtime type of your list:
public Object[] toArray()
Returns an array containing all of the
elements in this collection. If the collection makes any guarantees as
to what order its elements are returned by its iterator, this method
must return the elements in the same order. The returned array will be
"safe" in that no references to it are maintained by the collection.
(In other words, this method must allocate a new array even if the
collection is backed by an Array). The caller is thus free to modify
the returned array.
Right below that method, though, is the Javadoc for toArray(T[] a). As you can see, this method returns a T[] where T is the type of the array you pass in. At first this seems like what you're looking for, but it's unclear exactly why you're passing in an array (are you adding to it, using it for just the type, etc). The documentation makes it clear that the purpose of the passed array is essentially to define the type of array to return (which is exactly your use case):
public <T> T[] toArray(T[] a)
Returns an array containing all of the
elements in this collection; the runtime type of the returned array is
that of the specified array. If the collection fits in the specified
array, it is returned therein. Otherwise, a new array is allocated
with the runtime type of the specified array and the size of this
collection. If the collection fits in the specified array with room to
spare (i.e., the array has more elements than the collection), the
element in the array immediately following the end of the collection
is set to null. This is useful in determining the length of the
collection only if the caller knows that the collection does not
contain any null elements.)
If this collection makes any guarantees as to what order its elements
are returned by its iterator, this method must return the elements in
the same order.
This implementation checks if the array is large enough to contain the
collection; if not, it allocates a new array of the correct size and
type (using reflection). Then, it iterates over the collection,
storing each object reference in the next consecutive element of the
array, starting with element 0. If the array is larger than the
collection, a null is stored in the first location after the end of
the collection.
Of course, an understanding of generics (as described in the other answers) is required to really understand the difference between these two methods. Nevertheless, if you first go to the Javadocs, you will usually find your answer and then see for yourself what else you need to learn (if you really do).
Also note that reading the Javadocs here helps you to understand what the structure of the array you pass in should be. Though it may not really practically matter, you should not pass in an empty array like this:
String [] stockArr = stockList.toArray(new String[0]);
Because, from the doc, this implementation checks if the array is large enough to contain the collection; if not, it allocates a new array of the correct size and type (using reflection). There's no need for the extra overhead in creating a new array when you could easily pass in the size.
As is usually the case, the Javadocs provide you with a wealth of information and direction.
Hey wait a minute, what's reflection?

Basic array initialization and sorting question

this is a rather basic java question
I have an array containing String that i want to sort using java.util.Arrays.sort
when i write
String[] myArray = {"A","B","C"};
java.util.Arrays.sort(myArray);
it gets sorted correctly
however when i have
String[] myArray = new String[10];
myArray[0] = "A";
myArray[1] = "B";
myArray[2] = "C";
java.util.Arrays.sort(myArray);
sort throws a nullreferenceexception
i'm pretty sure its something really dumb i just dont get right now. I have to new the String, because hardcoding default values doesnt get anyone, anywhere.
When you initialize the second array, you only initialize the first three elements. The other elements are initialized to null and thus can't be sorted.
In the source, the method uses compareTo() as a sort condition. Obviously, invoking compareTo() on null, will raise a NullPointerException. As its mentioned in Java Docs that,
All elements in the array must be
mutually comparable (that is,
e1.compareTo(e2) must not throw a
ClassCastException for any elements
e1 and e2 in the array)
Of course here its not about ClassCastException, but invocation of comapreTo() is obvious.
[Edited]
P.S. Figuring this out from Exception Stack Trace is your best bet.
try the following to sort just the first three elements.
Arrays.sort(myArray, 0, 3);
What happens is that when you have the array that has ten items, the other items are uninitialized. So when the sort algorithm works, it tries to take the value of the string, but instead gets nothing, and throws the exception.
You need to make sure that you don't try to sort an array that has more space than things you place into it.
I think that since you make myArray store 10 elements, it's (effectively) adding 7 nulls to the end, and then Arrays.sort() can't sort a null element against a string.
It cant work on null strings which are there when you initially create the Array.
To avoid either explicitly make all as "" or else assign as much as require.
Although dont know whether this is a miss at API level as they could have catered for the null object (the way we get in SQL orderby) or is there something more to it.
You defining the array size by 10 but only initializing 3 indexes. Change your array size to 3 or initialize all ten.
The array has 10 items, but you only put 3 inside. So, the other 7 are NULL. Consider using a ArrayList instead.
An array list should be used because there are 3 elements not 10.
The other 7 elements of the array will have a null value.
It is these null values that cause the Null Pointer issue when sorting.

Categories

Resources