Using variables instead of a long statement? - java

I am facing a confusion while working with objects. I searched google but couldn't find actual words to search for. The question is:
I am working with objects which consist some other object. For example:
public void mapObjects(A a, B b) {
a.setWeight(BigDecimal.valueOf(b.getWeight));
//Now my doubt lies here
if (a.getCharges.getDiscounts.getDiscountList != null) {
for(int i = 0; i < a.getCharges.getDiscounts.getDiscountList.size(); i++){
b.getList().get(0).setDiscountValue(a.getCharges.getDiscounts.getDiscountList.get(i).getValue());
b.getList().get(0).setDiscountName(a.getCharges.getDiscounts.getDiscountList.get(i).getValue);
}
}
}
The above code is just an example. The project in which I am working uses similar type of coding style. The usage of a.getCharges.getDiscounts.getDiscountList() kind of code always bugs me. Because I am again and again calling the same statement.
When I asked a senior why dont we save this statement into a simple List<> variable. He told me that it will use extra references which will increase overhead. Can using a variable be that much overhead than calling getters again and again?

As Java exchanges references not actual object, if you take a local variable it will just add a reference variable entry in stack frame.
This memory would be very less, almost negligible
This memory will be released once the method is completed because this will be local to the method
Despite that, you can gain significant performance gains if you use local variables. You are extracting same information within loop multiple times.
a.getCharges.getDiscounts.getDiscountList.size() is called multiple times. It should be a local variable.
b.getList().get(0) is being called multiple times. It should be a local variable.
a.getCharges.getDiscounts.getDiscountList is called multiple times. It should be a local variable.
Changing these to local variables would results in good performance gains, because unnecessary method calls would be saved.

Point your senior to this. If it works for limited resources on Android, I guess the technique of storing in local variables everything used in a for cycle is actually beneficial for performance anywhere.
In the excerpt below, note that we aren't even speaking about the overhead introduced by calling the (virtual) list.size() method, only storing the array.length as a local variable produces notable differences in performance.
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
zero() is slowest, because the JIT can't yet optimize away the cost of getting the array length once for every iteration through the loop.
one() is faster. It pulls everything out into local variables, avoiding the lookups. Only the array length offers a performance benefit.
two() is fastest for devices without a JIT, and indistinguishable from one() for devices with a JIT. It uses the enhanced for loop syntax introduced in version 1.5 of the Java programming language.

Just make the discountList field never null - ie initialized to an empty list - and iterate over it. Something like:
for (Discount discount : a.getCharges().getDiscounts().getDiscountList()) {
b.getList().get(0).setDiscountValue(discount.getValue());
b.getList().get(0).setDiscountName(discount.getName());
}
Your "senior" may need to do some research. The "performance impact" of doing this is a few bytes per object and a few microseconds per access. If he's really hung up about memory, initialise it with a LinkedList, which has almost no memory footprint.

In Java a variable V pointing to an object instance O is simply a numeric value pointing to a memory location where the object's data is stored.
When we assign Vto another variable V1 all that happens is that V1 now points to the same memory location where data for O is stored. This means that new memory is not allocated when you do simple assignment unlike C++ code where the = operator can be be overloaded to do a deep-copy in which case new memory is actually allocated. Illustrating with an example below
Consider a class like below
class Foo {
private List<String> barList = new ArrayList<>();
//class methods...
//getter for the list
List<String> getBarList() {
return this.barList;
}
}
public static void main(String[] args) {
Foo f = new Foo()
//the below lien will print 0 since there is no bar string added
System.out.println("Bar list size: " + f.getBarList().size());
// add a bar string. Observe here that I am simply getting the list
// and adding - similar to how your code is currently structured
f.getBarList().add("SomeString");
//now get a reference to the list and store it in a variable.
// Below anotherList only points to the same memory location
// where the original bar list is present. No new memory is allocated.
List<String> anotherList = f.getBarList();
//print the content of bar list and another list. Both will be same
for(String s : f.getBarList()) {
System.out.println(s);
}
for(String s: anotherList) {
System.out.println(s);
}
//add a new bar string using the reference variable
anotherList.add("Another string");
//print the content of bar list and another list. Both will be same. If anotherList had separate memory allocated to it then the new string added would be only seen when we print the content of anotherList and not when we print the content of f.getBarList(). This proves that references are only some numeric addresses that point to locations of the object on heap.
for(String s : f.getBarList()) {
System.out.println(s);
}
for(String s: anotherList) {
System.out.println(s);
}
}
Hope this helps.

Related

When to create references, store values and set references to null

I have a couple of questions:
Regarding the creation of References to Objects and primitive
values, I was wondering: when is it usually appropriate to store
values in a variable?
From my general knowledge, the rule of thumb would be to create
references when the same value is used more than once or to avoid
hard-coding E.g.
String name = "Bob";
System.out.println("Welcome " + name + ". Is your name really " + name + "?");
Whereas if it is only used once like in the example below, it would
be more performant to simply do the following.
System.out.println("Welcome Bob");
as opposed to
String name = "Bob";
System.out.println("Welcome " + name + ".");
Added question: If we are talking about a variable that is used when iterating over an array or enumerable object, which of the following would be more performant (assuming we are looping over an object like 1 million times)? Or would there be no difference and is simply a stylistic choice?
For example,
// nameArray is an extremely long array
public static void loop(String[] nameArray) {
String name; //Should this be declared inside the loop?
int len = nameArray.length();
for(int i = 0; i < len; i++) {
name = nameArray[i];
System.out.println(name);
}
}
or would this be more preferred?
// nameArray is an extremely long array
public static void loop(String[] nameArray) {
int len = nameArray.length();
for(int i = 0; i < len; i++) {
String name = nameArray[i]; //Declare String reference inside for loop
System.out.println(name);
}
}
In regards to garbage collection, after a reference to an object/primitive
has passed its useful life, is it always good practice to set
that value to null to make it eligible for garbage collection (assuming that there are no other references to that object/primitive value) ?
For example,
String name = "Bob";
System.out.println("Welcome " + name + ".);
name = null;
thank you in advance for taking time to look at this.
No it makes no difference - the object is allocated whether you use a local variable to refer to it or not. Use whatever is more readable.
It is almost never good practice to set values to null explicitly. There are a few corner cases, such as when not doing it would hold unnecessary references to variables that would otherwise be eligible for garbage collection (see for example: Effective Java - Item 6: Eliminate obsolete object references). In all other situations, limiting the scope of variables as much as possible is the most efficient way to help the garbage collector.
The bottom line being: use variables when you need them and let the garbage collector do its job, unless you have a compelling reason not to.
when is it usually appropriate to store values in a variable?
In most cases the answer is: When the code benefits from it from a maintenance perspective. If the code becomes easier to understand or debug, then use a variable.
After a reference to an object/primitive has passed its useful life, is it always good practice to set that value to null to make it eligible for garbage collection?
If the variable goes out of scope shortly after, then setting it to null will just unnecessarily clutter the code. I would use it only for long-lived variables, and perhaps for variables that point to large objects.
From my general knowledge, the rule of thumb would be to create references when the same value is used more than once or to avoid hard-coding
Please, forget this rule. Use variables and their scope to help others (and you) understand your program more easily. You can do something like this
private static final String MY_UNCLE_NAME = "Bob";
System.out.println(String.format("Welcome %s.", MY_UNCLE_NAME));
Updated
If we are talking about a variable that is used when iterating over an array or enumerable object, which of the following would be more performant (assuming we are looping over an object like 1 million times)? Or would there be no difference and is simply a stylistic choice?
Always use this (keep a scope of variables as less as possible and forget about local optimizations).
// nameArray is an extremely long array
public static void loop(String[] nameArray) {
int len = nameArray.length();
for(int i = 0; i < len; i++) {
String name = nameArray[i]; //Declare String reference inside for loop
System.out.println(name);
}
}

Java Array of Objects crashes

Java noob question:
Consider the following C array and initializer code:
struct {
int x;
int y;
} point_t;
point_t points[1000];
Easy. This gets created and memory allocated at load time.
Now consider the similar in Java:
public class point_t
{
public int x;
public int y;
}
point_t points[] = new point_t[1000];
// Without this loop, java will crash when you run this
for (int i=0; i<1000; i++)
{
points[i] = new point_t;
}
points[0].x = 10; // Crash would occur here without above loop
points[1].x = 10;
Initially my java program was crashing with a null pointer dereference. The problem was that, coming from C++, I was not aware that you have to create the 1000 point_t objects. Just a comment but this seems INSANE. Suppose the array size was 1 million or 1 billion. It would literally take seconds simply to "create" this array with empty entries at run time. In C++ it all happens at load time. I admit that you don't always know what would be in the C++ array's cells, but in embedded systems where I work, quite often the memory is auto initialized to zeros so it works.
So is there any easier, quicker, more efficient way in Java to create an array and allocate the memory when you have an array of objects? Or am I doing something wrong in the code above?
Since you are coming from a C++ background, this may help. In Java, when you write
point_t points[] = new point_t[1000];
This is similar to writing, in C++,
point_t* points[] = new point_t*[1000];
That is, in Java, when you create the array, you are not creating an array of point objects, but rather and array of point references, the same as if you would have created an array of point pointers in C++.
Java is a managed (garbage-collected) language; that is what Java programmers would expect.
As for the second part of your question, how one would create the objects themselves, what you did is fine. Create 1000 point objects in a loop and load them up. If you want shorter code, you can write a nice method to do this work. :)
You can also look into other collection libraries that might have these kind of convenience factory methods.
Writing
point_t[] points = new point_t[ 1000 ];
is allocating a thousand references to point_t objects. (In C parlance, it's allocating pointers to structs of that type.)
That loop
for (int i=0; i<1000; i++)
{
points[i] = new point_t;
}
allocates a new point_t object, and puts the references (pointer) to it in the array. Until you did that, the array was nothing but nulls, and it probably gave you null exceptions.
That's not an array of point_t instances; those live out on the heap.
It's really an array of references to those point_t instances out on the heap.
Any reference that is not initialized by being assigned to a reference value (e.g. by calling new) is set to null.
It's true for non-array reference types, too.
public class Person {
private String name; // not initialized; that means it's null
public Person() {} // oops; constructor should have initialized name, but now it's null
public String getName() { return name; } // returns null unless you set it properly
public void setName(String newName) { this.name = newName; }
}
You can use the Flyweight pattern to share the same data between different objects and defer the creation of the point object until it is really necessary

In Java, Is it possible to concatenate the value of a variable into a variable name (Sounds messed up, but please read details)

Basically I have a variable, zlort = one;
I want to concatenate the value of zlort into a variable (object reference) name.
Like
BankAccount Accountzlort = new BankAccount;
I want the zlort in Account.zlort to actually be the replaced with value of zlort (one--meaning I want the value to be Accountone), and not zlort itself.
Is it possible to do this?
Thanks!
No you can't, but you might put the instance in a map:
Map<String,BankAccount> map = new HashMap<String,BankAccount>();
map.put("Account" + zlort, new BankAccount());
If you mean dynamically choosing the name to assign a variable to, then no.
You could use a HashMap to achieve the same effect.
It is not possible to change the name of a variable at runtime. That would lead to extreme security and stability problems when dealing with any real-world application.
However, as the two answers here have mentioned, a HashMap might acheive what you are looking for. (See the javadoc!!)
A HashMap (or any other map, for that matter) maps a Key to a Value. The concept is similar to a variable, which is a name -> value mapping. The only difference is that variables are part of the actual program code, which is effectively unmodifiable after compiling. A Map is a data structure that can be modified by the running program. This allows you to freely add key-value pairings to it.
Note that in Java, type-safety is encouraged through the use of Generics. Basically this ensures that the key can only be of one type (e.g. String) and the value can be of only one type (BankAccount). A thorough coverage of Generics can be found here.
You would declare this as follows:
Map<String, BankAccount> accounts = new HashMap<String, BankAccount>();
And then to add a key-value pair to the map, you would use the put() method (which 'puts' a value into the map, associated with a key)
String key = "Key"
BankAccount value = new BankAccount();
accounts.put(key, value);
To retrieve it, you would use the get() method.
BankAccount retrievedValue;
retrievedValue = accounts.get(key);
After reading the explanations in your comments, the fact that you can't use an array but can use an `ArrayList'...
Rather than creating a new variable name (or array element, or map value) for each BankAccount, you can probably use scope to your advantage.
Scope is the concept that a reference to a variable only has meaning within a certain part of code. If you declare a variable inside a method, that variable can only be seen within that method. A variable declared within a block (a loop, if statement, etc ) can only be seen from within that block.
Class fields have a different kind of scoping that can be adjusted with keywords (see here).
For example:
public class ScopeExample
int classInt = 10;
public void method() {
int methodInt = 0; // This integer can only be seen by code in
// this method
}
public void method2() {
//doSomething(methodInt) // This line won't compile because i is
// declared in a different method!
doSomething(classInt); // This line will compile and work
// because x is declared in the class that
// contains this method.
int index = 0;
while (index < 3) {
int whileInt = index; // This integer can only be seen from within
// this while loop! It is created each
// loop iteration.
doSomething(whileInt);
}
doSomething(whileInt); //This line won't work, whileInt is out of scope!
}
public doSomething(int a) {
System.out.println(a);
}
}
SO! If you create a BankAccount object within the loop, you don't have to worry about creating a new name for the next one. Each time the loop iterates it will become a new object (when you create it).
If you have to store it, you definitely will need to use an array or other data structure (ArrayList!).
Building on the idea of scope, you -can- have the same variable name for each new BankAccount. A variable reference name isn't guaranteed to be paired with the object that it refers to. That is a convenience to the programmer, so you don't have to know the exact memory address it is being stored in.
For example:
public static void main(String[] args) {
Object o;
int i = 0;
while (i < 5) {
Object reference = new Object(); // Create a new Object and store
// it in 'reference'
o = obj; // The Object 'o' now refers to the object in 'reference'
i++;
}
System.out.println(o); // This should print information about the
// LAST object created.
}
The new Object created in the loop does not belong to 'obj'. You as a programmer use 'obj' to point to the Object. The program doesn't really know what obj means, other than the fact that it points to the Object you just created.
Finally, you can use this along with an ArrayList to make your life easier.
public static void main(String[] args) {
// Our new ArrayList to hold our objects!
ArrayList<Object> stuff = new ArrayList<Object>();
int i = 0;
while (i < 5) {
Object obj = new Object(); // Create an object and make obj point to it.
stuff.add(obj); // Put "the object that 'obj' points to" in 'stuff'.
i++;
}
// This loop goes through all of the Objects in the ArrayList and prints them
for (int index = 0; index < stuff.size(); index++) {
System.out.println(stuff.get(i)); // This will print a single
// object in the ArrayList each time.
}
}

Serializable, cloneable and memory use in Java

I am using an inner class that is a subclass of a HashMap. I have a String as the key and double[] as the values. I store about 200 doubles per double[]. I should be using around 700 MB to store the keys, the pointers and the doubles. However, memory analysis reveals that I need a lot more than that (a little over 2 GB).
Using TIJmp (profiling tool) I saw there was a char[] that was using almost half of the total memory. TIJmp said that char[] came from Serializable and Cloneable. The values in it ranged from a list of fonts and default paths to messages and single characters.
What is the exact behavior of Serializable in the JVM? Is it keeping a "persistent" copy at all times thus, doubling the size of my memory footprint? How can I write binary copies of an object at runtime without turning the JVM into a memory hog?
PS: The method where the memory consumption increases the most is the one below. The file has around 229,000 lines and 202 fields per line.
public void readThetas(String filename) throws Exception
{
long t1 = System.currentTimeMillis();
documents = new HashMapX<String,double[]>(); //Document names to indices.
Scanner s = new Scanner(new File(filename));
int docIndex = 0;
if (s.hasNextLine())
System.out.println(s.nextLine()); // Consume useless first line :)
while(s.hasNextLine())
{
String[] fields = s.nextLine().split("\\s+");
String docName = fields[1];
numTopics = fields.length/2-1;
double[] thetas = new double[numTopics];
for (int i=2;i<numTopics;i=i+2)
thetas[Integer.valueOf(fields[i].trim())] = Double.valueOf(fields[i+1].trim());
documents.put(docName,thetas);
docIndex++;
if (docIndex%10000==0)
System.out.print("*"); //progress bar ;)
}
s.close();
long t2 = System.currentTimeMillis();
System.out.println("\nRead file in "+ (t2-t1) +" ms");
}
Oh!, and HashMapX is an inner class declared like this:
public static class HashMapX< K, V> extends HashMap<K,V> {
public V get(Object key, V altVal) {
if (this.containsKey(key))
return this.get(key);
else
return altVal;
}
}
This may not address all of your questions, but is a way in which serialization can significantly increase memory usage: http://java.sun.com/javase/technologies/core/basic/serializationFAQ.jsp#OutOfMemoryError.
In short, if you keep an ObjectOutputStream open then none of the objects that have been written to it can be garbage-collected unless you explicitly call its reset() method.
So, I found the answer. It is a memory leak in my code. Had nothing to do with Serializable or Cloneable.
This code is trying to parse a file. Each line contains a set of values which I am trying to extract. Then, I keep some of those values and store them in a HashMapX or some other structure.
The core of the problem is here:
String[] fields = s.nextLine().split("\\s+");
String docName = fields[1];
and I propagate it here:
documents.put(docName,thetas);
What happens is that docName is a reference to an element in an array (fields) and I am keeping that reference for the life of the program (by storing it in the global HashMap documents). As long as I keep that reference alive, the whole String[] fields cannot be garbage collected. The solution:
String docName = new String(fields[1]); // A copy, not a reference.
Thus copying the object and releasing the reference to the array element. In this way, the garbage collector can free the memory used by the array once I process every field.
I hope this will be useful to all of those who parse large text files using split and store some of the fields in global variables.
Thanks everybody for their comments. They guided me in the right direction.

What is inside code for array.length() in Java?

What is stored in 10th location of array
say
int[] array=new int[10];
Say we have values stored from array[0] to array[9], if I were to print elements without using
array.length()
or for (int a: array)
How do I proceed?
My basic question is how will JVM determine end of array, is it when a null is encountered parsing array or when a garbage value is encountered? what is inbuilt code of array.length() function?
What is stored in 10th location of array say
...
my basic question is how will JVM determine end of array, is it when a null is encountered parsing array or when a garbage value is encountered? what is inbuilt code of array.length() function?
Welcome C/C++ programmer :-)
Java uses a different paradigm than C/C++ for arrays. C/C++ uses the terminator/sentinel a.k.a. "garbage") value like NULL to indicate the end of the array. In Java, arrays are more like objects with a special "instance variable"-like variable length that indicates how many slots there are in the array. This special "instance variable" is set at the array's creation and is read-only. Its accessible by saying array.length.
Java expects the code to know when to stop at the end of the array by making sure they don't specify an index greater than length - 1. However, the JVM checks every access to the array for security reasons just in case. If the JVM finds an array index that is less than 0 or greater than length - 1, then the JVM throws an IndexOutOfBoundsException.
What is stored in 10th location of array
Since we can always check the length, there is no need for a marker at the end of the array in Java. There isn't anything special after the last item in the array (it likely will be some other variable's memory).
if I were to print elements without using array.length()
for(int a: array) {
// code of loop body here
}
This code is magically transformed by the compiler to:
for (int i = 0; i < array.length; i++) {
int a = array[i];
// code of loop body here
}
However, the i index variable isn't accessible to the user's code. This code still uses array.length implicitly.
Arrays are objects with a length field. While looping, Java loads the length field and compares the iterator against it.
See 10.7 Array Members in the JLS
Internally, the JVM can track the length of an array however it sees fit. There's actually a bytecode instruction called arraylength that the Java compiler emits whenever you try to get the length of an array, indicating that it's up to the JVM to determine the best way to track the length of an array.
Most implementations probably store arrays as a block of memory whose first entry is the length of the array and whose remaining elements are the actual array values. This allows the implementation to query the length of the array, along with any value in the array, in O(1). If the implementation wanted to, though, it could store the elements followed by a sentinel value (as you've suggested), but I don't believe that any implementations do this because the cost of looking up the length would be linear in the size of the array.
As for how the foreach loop works, the compiler translates that code into something like this:
for (int i = 0; i < arr.length; ++i) {
T arrayElem = arr[i];
/* ... do work here ... */
}
And finally, with regards as to what the 10th element of a 10-element array is, there's no guarantee that there's even an object at that location. The JVM could easily allocate space for the array in a way where there is no tenth element. Since you can't ever actually get this value in Java (it would throw an exception if you tried), there's no requirement that the JVM even have something meaningful there.
Hope this helps!
Define what a "garbage value" is. (Hint: since everything is binary, there is no such thing unless you use a sentinel value, and that's just bad practice).
The length of the array is stored inside the Array instance as a member variable. It's nothing complex.
In a comment on another, the OP writes:
I agree array.length is the conventional method, I was looking for any other option if available.
There is no other reasonable implementation option open to the JVM implementer ... on any mainstream hardware architecture.
In particular, the sentinel approach ONLY detects the case where an application fetches an array element one index beyond the end.
If it fetches 2 or more indexes beyond, then it misses the sentinel and proceeds to access memory whose contents are unknown.
If it stores, then the sentinel is not consulted.
If it needs to directly access the array size as part of the application algorithm, searching for a sentinel is a very inefficient way of doing it. (Not to mention unreliable; e.g. if null is a valid array element.)
Sentinels don't work for (most) primitive arrays because there is no value that can be used as a sentinel. (The idea of a primitive array holding a null is nonsensical from the JLS perspective, since null is not type compatible with any Java primitive type.)
The garbage collector needs an array length in all cases.
In short, the length has to be stored in the array to deal with the other cases. Storing a sentinel as well means you are wasting space storing redundant information, and CPU cycles creating the sentinel and copying it (in the GC).
Okay, here I go :-)
Ways to deal with "arrays" in C
In C there are numerous ways to deal with array. For the remainder I will talk about string* (and use the variable strings which has a type of string*). This is because t[] "effectively decomposes" into t* and char* is the type of a "C string". Thus string* represents a pointer to "C string". This glosses over a number of pedantic issues in C w.r.t. "arrays" and "pointers". (Remember: just because a pointer can be accessed as p[i] doesn't make the type an array in C parlance.)
Now, strings (of type string*) has no way to know it's size -- it only represents a pointer to some string, or NULL perhaps. Now, let's look at some of the ways we can "know" the size:
Use a sentinel value. In this I am assuming the use NULL as the sentinel value (or it might be -1 for an "array" of integers, etc.). Remember that C has no such requirement that arrays have a sentinel value so this approach, like the following two, is just convention.
string* p;
for (p = strings; p != NULL; p++) {
doStuff(*p);
}
Track the array size externally.
void display(int count, string* strings) {
for (int i = 0; i < count; i++) {
doStuff(strings[i]);
}
}
Bundle the "array" and the length together.
struct mystrarray_t {
int size;
string* strings;
}
void display(struct mystrarray_t arr) {
for (int i = 0; i < arr.size i++) {
doStuff(arr.strings[i]);
}
}
Java uses this last approach.
Every array object in Java has a fixed sized which can be accessed as arr.length. There is special byte-code magic to make this work (arrays are very magical in Java), but at the language level this is exposed as just a read-only integer field that never changes (remember, each array object has a fixed size). Compilers and the JVM/JIT can take advantage of this fact to optimize the loop.
Unlike C, Java guarantees that trying to access an index out of bounds will result in an Exception (for performance reasons, even if it were not exposed, this would require the JVM kept track of the length of each array). In C this is just undefined behavior. For instance, if the sentinel value wasn't within the object (read "the desired accessibly memory") then example #1 would have lead to a buffer-overflow.
However, there is nothing to prevent one from using sentinel values in Java. Unlike the C form with a sentinel value, this is also safe from IndexOutOfBoundExceptions (IOOB) because the length-guard is the ultimate limit. The sentinel is just a break-early.
// So we can add up to 2 extra names later
String names[] = { "Fred", "Barney", null, null };
// This uses a sentinel *and* is free of an over-run or IOB Exception
for (String n : names) {
if (n == null) {
break;
}
doStuff(n);
}
Or possibly allowing an IOOB Exception because we do something silly like ignore the fact that arrays know their length: (See comments wrt "performance").
// -- THERE IS NO EFFECTIVE PERFORMANCE GAIN --
// Can ONLY add 1 more name since sentinel now required to
// cleanly detect termination condition.
// Unlike C the behavior is still well-defined, just ill-behaving.
String names[] = { "Fred", "Barney", null, null };
for (int i = 0;; i++) {
String n = strings[i];
if (n == null) {
break;
}
doStuff(n);
}
On the other hand, I would discourage the use of such primitive code -- better to just use a suitable data-type such as a List in almost all cases.
Happy coding.
In terms of how you'd print all the elements in the array without using either a for each loop or the length field, well in all honesty you just wouldn't. You could potentially just have a for loop like the following:
try {
for(int i=0 ; ; i++) {
System.out.println(arr[i]);
}
}
catch(IndexOutOfBoundsException ex) {}
But that's an awful way to do things!
how will you print elements without using array.length or foreach loop
You could of course loop through the array without bounds checking and then catch (and swallow) the ArrayIndexOutOfBoundsException in the end:
try {
int i = 0;
while (true) {
System.out.println(arr[i++]);
}
catch (ArrayIndexOutOfBoundsException e) {
// so we are past the last array element...
}
This technically works, but it is bad practice. You should not use exceptions for flow control.
All array access outside the interval [0, 9] gives an ArrayIndexOutOfBoundsException, not only position 10. So, conceptually you could say that your whole memory (reaching with indexes from Integer.MIN_VALUE to Integer.MAX_VALUE) is filled with sentinel values, apart from the space of the array itself, and when reading or writing to a position filled with a sentinel, you get your exception. (And each array has its own whole memory to spend).
Of course, in reality no one has a whole memory for each array to spend, so the VM implements the array accesses a bit smarter. You can imagine something like this:
class Array<X> {
private final int length;
private final Class<X> componentType;
/**
* invoked on new X[len] .
*/
public Array<X>(int len, Class<X> type) {
if(len < 0) {
throw new NegativeArraySizeException("too small: " + len);
}
this.componentType = type;
this.len = len;
// TODO: allocate the memory
// initialize elements:
for (int i = 0; i < len; i++) {
setElement(i, null);
}
}
/**
* invoked on a.length
*/
public int length() {
return length;
}
/**
* invoked on a[i]
*/
public X getElement(int index) {
if(index < 0 || length <= index)
throw new ArrayIndexOutOfBoundsException("out of bounds: " + index);
// TODO: do the real memory access
return ...;
}
/**
* invoked on a[i] = x
*/
public X setElement(int index, X value) {
if(index < 0 || length <= index) {
throw new ArrayIndexOutOfBoundsException("out of bounds: " + index);
}
if(!componentType.isInstance(value)) {
throw new ArrayStoreException("value " + value + " is of type " +
value.getClass().getName() + ", but should be of type "
+ componentType.getName() + "!");
}
// TODO: do the real memory access
return value;
}
}
Of course, for primitive values the component type check is a bit simpler, since already the compiler (and then the VM bytecode verifier) checks that there are the right types, sometimes doing a type conversion, too. (And the initialization would be with the default value of the type, not null.)

Categories