JNA (Java): How to pass an array of pointers to struct? - java

I'm using JNA to call into a C library from Java.
In my C code I have:
void printStructArray( SomeStruct **someStruct, int arraySize );
This expects an array of pointers to struct, ie the method does this:
void printStructArray( SomeStruct **someStruct, int arraySize ) {
for( int i = 0; i < arraySize; i++ ) {
cout << "someStruct: " << someStruct[i]->aLong << " " << someStruct[i]->aString << " " << someStruct[i]->aDouble << endl;
}
}
It's just a toy example, but I have an actual library I want to talk to which needs the same type of argument, but I think using a toy example is easier to explain here?
I've tried all sorts of things, but I'm not sure how to (i) declare this function in JNA (ii) call this function in JNA.
My latest (failed) attempt is:
SomeStruct.byReference[] structs = new SomeStruct.byReference[]{
new SomeStruct.byReference(123,"hey!",1.23),
new SomeStruct.byReference(456,"cool!",1.45),
new SomeStruct.byReference(789,"world!",1.67) };
PointerByReference pointerByReference = new PointerByReference(structs[0].getPointer());
JniTest.instance.printStructArray(pointerByReference, 3);
This causes a SIGSEGV.
Alternatively:
SomeStruct.byReference[] structs = (SomeStruct.byReference[]) new SomeStruct().toArray( new SomeStruct.byReference[]{
new SomeStruct.byReference(123,"hey!",1.23),
new SomeStruct.byReference(456,"cool!",1.45),
new SomeStruct.byReference(789,"world!",1.67) } );
PointerByReference pointerByReference = new PointerByReference(structs[0].getPointer());
JniTest.instance.printStructArray(pointerByReference, 3);
This causes an ArrayStoreException
Tried this also:
SomeStruct.byReference[] structs = new SomeStruct.byReference[]{
new SomeStruct.byReference(123,"hey!",1.23),
new SomeStruct.byReference(456,"cool!",1.45),
new SomeStruct.byReference(789,"world!",1.67) }; JniTest.instance.printStructArray(structs, 3);
With method declared as:
void printStructArray(SomeStruct.byReference[] someStructarray, int num);
This gives '0' as the output from the function, although the good point is it doesn't crash, but it's not giving correct behavior either.
Thoughts?

It's sufficient to pass your array of Structure.ByReference; the address of the array is passed to the native code. JNA automatically allocates the space for the array of pointers, which goes out of scope after the function call.
PointerByReference is intended to pass a pointer value by reference (i.e. the callee may alter the value). It is not appropriate in this case.

I've just found a solution that works quite nicely, which is to use BridJ instead of JNA. Maybe there is a way to get JNA working, but it doesn't seem obvious. BridJ is really easy to use:
Declaration:
public static native void printStructArray(Pointer<Pointer<SomeStruct > > someStruct, int arraySize);
Usage:
Pointer<Pointer<SomeStruct>> pointers = Pointer.allocatePointers(SomeStruct.class, 3);
pointers.set(0, Pointer.pointerTo( new SomeStruct().aDouble(1.58).aLong(5432).aString(Pointer.pointerToCString("Wheee!")) ) );
pointers.set(1, Pointer.pointerTo( new SomeStruct().aDouble(1.58).aLong(5432).aString(Pointer.pointerToCString("Wheee!")) ) );
pointers.set(2, Pointer.pointerTo( new SomeStruct().aDouble(1.58).aLong(5432).aString(Pointer.pointerToCString("Wheee!")) ) );
JnitestLibrary.printStructArray(pointers, 3 );
It seems they dont support structures by value, but I dont have any structures by value in my current interface, so that's not a problem for me right now. Apparently performance is ok, but I haven't tested performance personally.
Note that I'm still open to JNA solutions, and will tick anyone who can give me a working JNA solution to the problem.

Is this C or C++?
If C, why don't you simply use calloc/malloc to allocate the double pointer for the structure as follows?
somestruct = (SomeStruct **)calloc(arraySize, sizeof(SomeStruct *));
for (i = 0; i < arraySize; i++)
somestruct[i] = (SomeStruct *)calloc(1, sizeof(SomeStruct));
Now, you can fill the structures as you want.

In the end, I never found a working solution to this. What I did was workaround by writing a wrapper interface, in C, which presented a very simple interface to Java, which was then very easy to link to using JNA, without needing Pointer and so on. This worked quite well, and was less effort than trying to get Pointer working.
So, my interface looked something like:
int createHandle()
void doSomething( int handle )
void releaseHandle( int handle)
It seemed to take a lot less effort to get this working, in terms of time, than trying to create some super complicated jna implementation to directly connect to the underlying c interface.
The other advantage is this meant it was easy to connect to a c++ library, since this way, the c++ interface is wrapped by a c interface, which is easy to connect to.

Related

How to call C function through JNA with 2d pointer?

Here is the signature of my C function :
typedef struct myitem_s {
int a;
int b;
} myitem_t;
int get_items(myitem_t** items);
The usage in a C program is::
myitem_t* items = NULL;
int n = = get_items(&items);
for (int i = 0; i < n; ++i) {
myitem_t* item = &items[i];
}
items is allocated in the get_items() function and contains one or more myitem_t elements.
From Java code I have succeeded in doing this:
Memory itemsPtr = new Memory(Native.POINTER_SIZE);
Pointer p = itemsPtr.getPointer(0);
int n = CLibrary.INSTANCE.get_items(p);
The n value is valid, itemsPtr is updated so I suggest value is good also. Now I have no idea of how to use it. Is there another way of doing it?
Your code works but you're using a lot of lower level functions when JNA has some higher level constructs.
First, the C struct can be represented by a JNA Structure.
#FieldOrder({ "a", "b" })
class MyitemT extends Structure {
public int a;
public int b;
}
Since the native code is handling the memory allocation, all you need is the pointer to it. Rather than a pointer-sized memory allocation, you probably want a PointerByReference.
PointerByReference pbr = new PointerByReference();
The key methods you want from this are getPointer() (the pointer to the pointer) and getValue() (the pointed-to value).
Given the above, pass the pointer-to-the-pointer to the method, which will allocate the memory and populate the value.
Using the mapping you already have (not shown but inferred):
int n = CLibrary.INSTANCE.get_items(pbr.getPointer());
However, you should actually map get_items() to take a PointerByReference argument and then you can just pass items directly.
At this point, items.getValue() is a Pointer to the start of your array of structures. Additional items would be at offsets of the pointer value based on the size of the structure (item.size()). There are multiple ways of getting at that.
In your case since you know you just have pairs of ints, you could skip the whole "structure" part and just use items.getValue().getInt(0) and items.getValue().getInt(4) for the first pair; 8 and 12 for the second pair, etc. But even better, just items.getValue().getIntArray(0,n*2); fetches an array of integers, just pull them out by pairs.
But that takes advantage of internal details. Probably the most JNA-ish choice is to use Structure.toArray() to create an array of your MyitemT structures. If you include a pointer constructor and create the initial structure using that pointer, Structure.toArray() uses that existing mapping. You can then read() into your array:
MyItemT item = new MyItemT(pbr.getValue());
MyItemT[] items = (MyItemT[]) item.toArray(n);
for (int i = 0; i < n; i++) {
items[i].read();
// now you can see items[i].a and items[i].b
}
Don't forget to eventually release the native-allocated memory however the API tells you to!

Having a List of an Abstract class in Java and needing to loop through the List

I'm trying to move my code from c# to java and it's the first time i'm trying to write java code.
Firstly i noticed that a List<> in c# is not as a list in java where i had to use an arrayList instead so i just changed
List<Instruments> instruments = new List<Instruments>();
to
List<Instruments> instruments = new ArrayList<Instruments>();
and that solved that.
Later on in my program i have a for loop which runs though the List (of an abstract "Instruments" class) and compares an enum (saved in .type) value which all the subclasses have. I:E
public static int HowManyOfType(InstrumentType TP)
{
int HowMany = 0;
for (int i = 0; i < instruments.Size(); i++)
{
if (instruments[i].type == TP)
HowMany++;
}
return HowMany;
}
However i'm getting the message "Array Type expected".
This problem wouldn't occur in c# because the property is stored in the abstract class and it would just do the comparison without needing to know the type of subclass that was stored.
I'm guessing that it's not that simple in java. Is there a was around this?
Thanks
Change this
if (instruments[i].type == TP)
to
if (instruments.get(i).type == TP)
Change your for loop to this.
for (Instruments eachInstrument : instruments) {
if (eachInstrument.type == TP) {
howMany++;
}
}
although without knowing what the data type of eachInstrument.type is, I can't be sure that it's correct to use ==. You may need to change this to eachInstrument.type.equals(TP).
If you are used to C# you might find lambdas in Java 8 more natural.
long howMany = instruments.stream().filter(t -> t.type == TP).count();
Unless the type is a primitive or an Enum you may need to use equals
long howMany = instruments.stream().filter(t -> t.type.equals(TP)).count();

JNA array of structures uninitialized after being passed from Java to C

I've been using JNA with relative success to make native function calls from Java to a small C library that I wrote. Passing structures or pointers from one to the other works great once you've worked out the tricks of structure mapping, memory management and passing by reference.
I am now trying to pass, from Java to C, an array of structures. Here is the C code for the structure:
typedef struct key {
int length;
void *data;
} key_t;
I have the matching definition in Java:
public class Key extends Structure {
public int length;
public Pointer data;
public Key() {
this.setFieldOrder(new String[] {"length", "data"});
}
public void setAsLong(long value) {
this.length = 8;
this.data = new Memory(this.length);
this.data.setLong(0, value);
}
public long longValue() {
return this.data != null ? this.data.getLong(0) : Long.MIN_VALUE;
}
};
If I understood the documentation and what I read online, I need to create my array as a contiguous memory section by doing the following on the Java side:
Key[] keys = new Key().toArray(2);
for (int i=0; i<2; i++) {
k.setAsLong(42+i);
}
So far so good. If I dump the content of each Key structure in Java using Structure.toString(), everything is in here as expected. Note that the code about setting as a long value, allocating memory for the key's content, etc, work fine when I pass a single Key structure from Java to C. So here I pass my array to my native function by using the pointer to the first element of the array:
instance.foo(keys[0].getPointer(), keys.length);
My C function is of course defined like this:
void foo(key_t *keys, size_t count) {
...;
}
The array gets there correctly: the keys pointer on the C side has the same address as keys[0].getPointer() in Java, but unfortunately the members of each structure in the array are 0/NULL, as pointed out by GDB:
(gdb) print keys
$1 = (key_t *) 0x7fd7e82389e0
(gdb) print keys[0]
$2 = {length = 0, data = 0x0}
At this point I honestly have no clue what's going on. As I said, if I pass just one structure, it works fine, but here no way. The only difference I can see is the Java native method signature which uses Pointer instead of Key[] but when I use the array I get:
IllegalArgumentException: [Lfoo.bar.Key; is not a supported argument type (in method foo ...
Thanks
If you pass a Pointer value, JNA has no idea that you're actually passing a Structure or an array of them, and it's up to you to ensure you call Structure.write() before and Structure.read() after the native call.
If you pass either a Structure or Structure[], then JNA will take care of the synchronization automagically. In the case of Structure, JNA uses internal bookkeeping to determine whether the structure you're passing is at the head of an array of structures.

How can I use pointers in Java?

I know Java doesn't have pointers, but I heard that Java programs can be created with pointers and that this can be done by the few who are experts in java. Is it true?
All objects in Java are references and you can use them like pointers.
abstract class Animal
{...
}
class Lion extends Animal
{...
}
class Tiger extends Animal
{
public Tiger() {...}
public void growl(){...}
}
Tiger first = null;
Tiger second = new Tiger();
Tiger third;
Dereferencing a null:
first.growl(); // ERROR, first is null.
third.growl(); // ERROR, third has not been initialized.
Aliasing Problem:
third = new Tiger();
first = third;
Losing Cells:
second = third; // Possible ERROR. The old value of second is lost.
You can make this safe by first assuring that there is no further need of the old value of second or assigning another pointer the value of second.
first = second;
second = third; //OK
Note that giving second a value in other ways (NULL, new...) is just as much a potential error and may result in losing the object that it points to.
The Java system will throw an exception (OutOfMemoryError) when you call new and the allocator cannot allocate the requested cell. This is very rare and usually results from run-away recursion.
Note that, from a language point of view, abandoning objects to the garbage collector are not errors at all. It is just something that the programmer needs to be aware of. The same variable can point to different objects at different times and old values will be reclaimed when no pointer references them. But if the logic of the program requires maintaining at least one reference to the object, It will cause an error.
Novices often make the following error.
Tiger tony = new Tiger();
tony = third; // Error, the new object allocated above is reclaimed.
What you probably meant to say was:
Tiger tony = null;
tony = third; // OK.
Improper Casting:
Lion leo = new Lion();
Tiger tony = (Tiger)leo; // Always illegal and caught by compiler.
Animal whatever = new Lion(); // Legal.
Tiger tony = (Tiger)whatever; // Illegal, just as in previous example.
Lion leo = (Lion)whatever; // Legal, object whatever really is a Lion.
Pointers in C:
void main() {
int* x; // Allocate the pointers x and y
int* y; // (but not the pointees)
x = malloc(sizeof(int)); // Allocate an int pointee,
// and set x to point to it
*x = 42; // Dereference x to store 42 in its pointee
*y = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
*y = 13; // Dereference y to store 13 in its (shared) pointee
}
Pointers in Java:
class IntObj {
public int value;
}
public class Binky() {
public static void main(String[] args) {
IntObj x; // Allocate the pointers x and y
IntObj y; // (but not the IntObj pointees)
x = new IntObj(); // Allocate an IntObj pointee
// and set x to point to it
x.value = 42; // Dereference x to store 42 in its pointee
y.value = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
y.value = 13; // Deference y to store 13 in its (shared) pointee
}
}
UPDATE: as suggested in the comments one must note that C has pointer arithmetic. However, we do not have that in Java.
As Java has no pointer data types, it is impossible to use pointers in Java. Even the few experts will not be able to use pointers in java.
See also the last point in: The Java Language Environment
Java does have pointers. Any time you create an object in Java, you're actually creating a pointer to the object; this pointer could then be set to a different object or to null, and the original object will still exist (pending garbage collection).
What you can't do in Java is pointer arithmetic. You can't dereference a specific memory address or increment a pointer.
If you really want to get low-level, the only way to do it is with the Java Native Interface; and even then, the low-level part has to be done in C or C++.
There are pointers in Java, but you cannot manipulate them the way that you can in C++ or C. When you pass an object, you are passing a pointer to that object, but not in the same sense as in C++. That object cannot be dereferenced. If you set its values using its native accessors, it will change because Java knows its memory location through the pointer. But the pointer is immutable. When you attempt to set the pointer to a new location, you instead end up with a new local object with the same name as the other. The original object is unchanged. Here is a brief program to demonstrate the difference.
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone {
public static void main(String[] args) throws java.lang.Exception {
System.out.println("Expected # = 0 1 2 2 1");
Cat c = new Cat();
c.setClaws(0);
System.out.println("Initial value is " + c.getClaws());
// prints 0 obviously
clawsAreOne(c);
System.out.println("Accessor changes value to " + c.getClaws());
// prints 1 because the value 'referenced' by the 'pointer' is changed using an accessor.
makeNewCat(c);
System.out.println("Final value is " + c.getClaws());
// prints 1 because the pointer is not changed to 'kitten'; that would be a reference pass.
}
public static void clawsAreOne(Cat kitty) {
kitty.setClaws(1);
}
public static void makeNewCat(Cat kitty) {
Cat kitten = new Cat();
kitten.setClaws(2);
kitty = kitten;
System.out.println("Value in makeNewCat scope of kitten " + kitten.getClaws());
//Prints 2. the value pointed to by 'kitten' is 2
System.out.println("Value in makeNewcat scope of kitty " + kitty.getClaws());
//Prints 2. The local copy is being used within the scope of this method.
}
}
class Cat {
private int claws;
public void setClaws(int i) {
claws = i;
}
public int getClaws() {
return claws;
}
}
This can be run at Ideone.com.
Java does not have pointers like C has, but it does allow you to create new objects on the heap which are "referenced" by variables. The lack of pointers is to stop Java programs from referencing memory locations illegally, and also enables Garbage Collection to be automatically carried out by the Java Virtual Machine.
You can use addresses and pointers using the Unsafe class. However as the name suggests, these methods are UNSAFE and generally a bad idea. Incorrect usage can result in your JVM randomly dying (actually the same problem get using pointers incorrectly in C/C++)
While you may be used to pointers and think you need them (because you don't know how to code any other way), you will find that you don't and you will be better off for it.
Technically, all Java objects are pointers. All primitive types are values though. There is no way to take manual control of those pointers. Java just internally uses pass-by-reference.
Not really, no.
Java doesn't have pointers. If you really wanted you could try to emulate them by building around something like reflection, but it would have all of the complexity of pointers with none of the benefits.
Java doesn't have pointers because it doesn't need them. What kind of answers were you hoping for from this question, i.e. deep down did you hope you could use them for something or was this just curiousity?
All objects in java are passed to functions by reference copy except primitives.
In effect, this means that you are sending a copy of the pointer to the original object rather than a copy of the object itself.
Please leave a comment if you want an example to understand this.
As others have said, the short answer is "No".
Sure, you could write JNI code that plays with Java pointers. Depending on what you're trying to accomplish, maybe that would get you somewhere and maybe it wouldn't.
You could always simulate pointes by creating an array and working with indexes into the array. Again, depending on what you're trying to accomplish, that might or might not be useful.
from the book named Decompiling Android by Godfrey Nolan
Security dictates that pointers aren’t
used in Java so hackers can’t break out of an application and into the operating
system. No pointers means that something else----in this case, the JVM----has to
take care of the allocating and freeing memory. Memory leaks should also
become a thing of the past, or so the theory goes. Some applications written in
C and C++ are notorious for leaking memory like a sieve because programmers
don’t pay attention to freeing up unwanted memory at the appropriate time----not
that anybody reading this would be guilty of such a sin. Garbage collection
should also make programmers more productive, with less time spent on
debugging memory problems.
Java reference types are not the same as C pointers as you can't have a pointer to a pointer in Java.
you can have pointers for literals as well. You have to implement them yourself. It is pretty basic for experts ;). Use an array of int/object/long/byte and voila you have the basics for implementing pointers. Now any int value can be a pointer to that array int[]. You can increment the pointer, you can decrement the pointer, you can multiply the pointer. You indeed have pointer arithmetics!
That's the only way to implements 1000 int attributes classes and have a generic method that applies to all attributes. You can also use a byte[] array instead of an int[]
However I do wish Java would let you pass literal values by reference. Something along the lines
//(* telling you it is a pointer)
public void myMethod(int* intValue);
You can, but not completely. You can't directly access pointers but you can have lists with variables that point to the same location. I came across a way by accident a few years ago.
I'm not sure why but in Java when you set a list to equal another list, rather than copying all the information, a pointer to the original list is made. I'm not sure if it applies to all forms of lists, but it has for the ones I have tested so far. I believe arrayList also has the function clone(), to circumvent this, if you wanted a proper seperate list.
int[] example
public class Main {
public static void main(String[] args){
int[] alpha = new int[] {1,2,3};
int[] beta = alpha;
beta[0]=9;
beta[1]=9;
beta[2]=9;
System.out.println("alpha: " + alpha[0] + ", " + alpha[1] + ", " + alpha[2]);
System.out.println("-beta: " + beta[0] + ", " + beta[1] + ", " + beta[2]);
}
}
arrayList example
import java.util.ArrayList;
public class Main {
public static void main(String[] args){
ArrayList<Integer> alpha = new ArrayList<>();
alpha.add(1);
alpha.add(2);
alpha.add(3);
ArrayList<Integer> beta = alpha;
beta.add(4);
beta.set(0, 5);
System.out.println("alpha: " + alpha.toString());
System.out.println("-beta: " + beta.toString());
}
}
All java objects are pointer because a variable which holds address is called pointer and object hold address.so object is pointer variable.
java can easily has pointer by knowing that the array name is pointer to the the first index. this why when we pass array to function we don't write its square brackets. because array is reference
public class Main
{
public static void func ( int ptr1[] , int ptr2[] )
{
int temp;
temp = ptr1[0];
ptr1[0] = ptr2[0];
ptr2[0] = temp;
}
public static void main(String[] args) {
int x = 5; int y = 8;
// in c language
// int *p = &x; int *q = &y;
// in Java
int p[] = new int[1];
int q[] = new int[1];
p[0] = x; // same as pointer
q[0] = y; // same as pointer
func( p , q ); // passing address ( refrence )
System.out.println( " After Swap " );
System.out.println( "x = " + p[0] + " " + "y = " + q[0] );
}
}

Java: Out with the Old, In with the New

Java is nearing version 7. It occurs to me that there must be plenty of textbooks and training manuals kicking around that teach methods based on older versions of Java, where the methods taught, would have far better solutions now.
What are some boilerplate code situations, especially ones that you see people implement through force of habit, that you find yourself refactoring to utilize the latest versions of Java?
Enums. Replacing
public static final int CLUBS = 0;
public static final int DIAMONDS = 1;
public static final int HEARTS = 2;
public static final int SPADES = 3;
with
public enum Suit {
CLUBS,
DIAMONDS,
HEARTS,
SPADES
}
Generics and no longer needing to create an iterator to go through all elements in a collection. The new version is much better, easier to use, and easier to understand.
EDIT:
Before:
List l = someList;
Iterator i = l.getIterator();
while (i.hasNext()) {
MyObject o = (MyObject)i.next();
}
After
List<MyObject> l = someList;
for (MyObject o : l) {
//do something
}
Using local variables of type StringBuffer to perform string concatenation. Unless synchronization is required, it is now recommended to use StringBuilder instead, because this class offers better performance (presumably because it is unsynchronized).
reading a string from standard input:
Java pre-5:
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str = reader.readLine();
reader.close();
}
catch (IOException e) {
System.err.println("error when closing input stream.");
}
Java 5:
Scanner reader = new Scanner(System.in);
String str = reader.nextLine();
reader.close();
Java 6:
Console reader = System.console();
String str = reader.readLine();
Older code using Thread instead of the many other alternatives to Thread... these days, very little of the code I run across still needs to use a raw thread. They would be better served by a level of abstraction, particular Callable/Futures/Executors.
See:
java.util.Timer
javax.swing.Timer
java.util.concurrent.*
Here is one that I see:
String.split() versus StringTokenizer.
StringTokenizer is not recommended for new code, but I still see people use it.
As for compatibility, Sun makes a huge effort to have Java be backwards and forwards compatible. That partially accounts for why generics are so complex. Deprecation is also supposed to help ease transitions from old to new code.
VARARGS can be useful too.
For example, you can use:
public int add(int... numbers){
int sum = 0 ;
for (int i : numbers){
sum+=i;
}
return sum ;
}
instead of:
public int add(int n1, int n2, int n3, int n4) ;
or
public int add(List<Integer> numbers) ;
Using local variables of type Vector to hold a list of objects. Unless synchronization is required, it is now recommended to use a List implementation such as ArrayList instead, because this class offers better performance (because it is unsynchronized).
Formatted printing was introduced as late as in JDK 1.5. So instead of using:
String str = "test " + intValue + " test " + doubleValue;
or the equivalent using a StringBuilder,
one can use
String str = String.format("test %d test %lg", intValue, doubleValue);
The latter is much more readable, both from the string concatenation and the string builder versions. Still I find that people adopt this style very slowly. Log4j framework for example, doesn't use this, although I believe it would be greatly benefited to do so.
Explicit conversion between primitive and wrapper types (e.g. Integer to int or vice versa) which is taken care of automatically by autoboxing/unboxing since Java 1.5.
An example is
Integer myInteger = 6;
int myInt = myInteger.intValue();
Can simply be written as
Integer myInteger = 6;
int myInt = myInteger;
But watch out for NullPointerExceptions :)
Q1: Well, the most obvious situations are in the generics / type specific collections. The other one that immediately springs to mind is the improved for loop, which I feel is a lot cleaner looking and easier to understand.
Q2: In general, I have been bundling the JVM along side of my application for customer-facing apps. This allows us to use new language features without having to worry about JVM incompatibility.
If I were not bundling the JRE, I would probably stick to 1.4 for compatibility reasons.
A simple change in since 1.5 but makes a small difference - in the Swing API accessing the contentPane of a JFrame:
myframe.getContentPane().add(mycomponent);
becomes
myframe.add(mycomponent);
And of course the introduction of Enums has changed the way many applications that used constants in the past behave.
String.format() has greatly improved String manipulation and the ternary if statement is quite helpful in making code easier to read.
Generic collections make coding much more bug-resistant.
OLD:
Vector stringVector = new Vector();
stringVector.add("hi");
stringVector.add(528); // oops!
stringVector.add(new Whatzit()); // Oh my, could spell trouble later on!
NEW:
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("hello again");
stringList.add(new Whatzit()); // Won't compile!
Using Iterator:
List list = getTheList();
Iterator iter = list.iterator()
while (iter.hasNext()) {
String s = (String) iter.next();
// .. do something
}
Or an alternate form sometimes seen:
List list = getTheList();
for (Iterator iter = list.iterator(); iter.hasNext();) {
String s = (String) iter.next();
// .. do something
}
Is now all replaced with:
List<String> list = getTheList();
for (String s : list) {
// .. do something
}
Although I admit that static imports can easily be overused, I like to use
import static Math.* ;
in classes that use a lot of Math functions. It can really decrease the verbosity of your code. I wouldn't recommend it for lesser-known libraries, though, since that can lead to confusion.
copying an existing array to a new array:
pre-Java 5:
int[] src = new int[] {1, 2, 3, 4, 5};
int[] dest = new int[src.length];
System.arraycopy(src, 0, dest, 0, src.length);
Java 6:
int[] src = new int[] {1, 2, 3, 4, 5};
int[] dest = Arrays.copyOf(src, src.length);
formerly, I had to explicitly create a new array and then copy the source elements to the new array (calling a method with a lot of parameters). now, the syntax is cleaner and the new array is returned from a method, I don't have to create it. by the way, the method Arrays.copyOf has a variation called Arrays.copyOfRange, which copies a specific region of the source array (pretty much like System.arraycopy).
Converting a number to a String:
String s = n + "";
In this case I think there has always been a better way of doing this:
String s = String.valueOf(n);
The new for-each construct to iterate over arrays and collection are the biggest for me.
These days, when ever I see the boilerplate for loop to iterate over an array one-by-one using an index variable, it makes me want to scream:
// AGGHHH!!!
int[] array = new int[] {0, 1, 2, 3, 4};
for (int i = 0; i < array.length; i++)
{
// Do something...
}
Replacing the above with the for construct introduced in Java 5:
// Nice and clean.
int[] array = new int[] {0, 1, 2, 3, 4};
for (int n : array)
{
// Do something...
}
Clean, concise, and best of all, it gives meaning to the code rather than showing how to do something.
Clearly, the code has meaning to iterate over the collection, rather than the old for loop saying how to iterate over an array.
Furthermore, as each element is processed independent of other elements, it may allow for future optimizations for parallel processing without having to make changes to the code. (Just speculation, of course.)
Related to varargs; the utility method Arrays.asList() which, starting from Java 5, takes varargs parameters is immensely useful.
I often find myself simplifying something like
List<String> items = new ArrayList<String>();
items.add("one");
items.add("two");
items.add("three");
handleItems(items);
by using
handleItems(Arrays.asList("one", "two", "three"));
Annotations
I wonder no one mentioned it so far, but many frameworks rely on annotations, for example Spring and Hibernate. It is common today to deprecate xml configuration files are in favor of annotations in code (though this means losing flexibility in moving from configuration to meta-code, but is often the right choice).The best example is EJB 2 (and older) compared to EJB 3.0 and how programming EJB has been simplified thanks to annotations.
I find annotations also very useful in combination with some AOP tools like AspectJ or Spring AOP. Such combination can be very powerful.
Changing JUnit 3-style tests:
class Test extends TestCase {
public void testYadaYada() { ... }
}
to JUnit 4-style tests:
class Test {
#Test public void yadaYada() { ... }
}
Improved singleton patterns. Technically these are covered under the popular answer enums, but it's a significant subcategory.
public enum Singleton {
INSTANCE;
public void someMethod() {
...
}
}
is cleaner and safer than
public class Singleton {
public static final Singleton INSTANCE = new Singleton();
private Singleton() {
...
}
public void someMethod() {
...
}
}
Converting classes to use generics, thereby avoiding situations with unnecessary casts.
Okay, now it's my turn to get yelled at.
I don't recommend 90% of these changes.
It's not that it's not a good idea to use them with new code, but breaking into existing code to change a for loop to a for(:) loop is simply a waste of time and a chance to break something. (IIWDFWI) If it works, don't fix it!
If you are at a real development company, that change now becomes something to code-review, test and possibly debug.
If someone doing this kind of a refactor for no reason caused a problem of ANY sort, I'd give them no end of shit.
On the other hand, if you're in the code and changing stuff on that line anyway, feel free to clean it up.
Also, all the suggestions in the name of "Performance" really need to learn about the laws of optimization. In two words, Don't! Ever! (Google the "Rules of optimization if you don't believe me).
I'm a little wary to refactor along these lines if that is all you are doing to your source tree. The examples so far do not seem like reasons alone to change any working code base, but maybe if you are adding new functionality you should take advantage of all the new stuff.
At the end of the day, these example are not really removing boiler plate code, they are just using the more manageable constructs of newer JDKs to make nice looking boiler plate code.
Most ways to make your code elegant are not in the JDK.
Using Swing's new DefaultRowSorter to sort tables versus rolling your own from scratch.
New version of Java rarely break existing code, so just leave old code alone and focus on how the new feature makes your life easier.
If you just leave old code alone, then writing new code using new features isn't as scary.
String comparisons, really old school Java programmers I've met would do:
String s1 = "...", s2 = "...";
if (s1.intern() == s2.intern()) {
....
}
(Supposedly for performance reasons)
Whereas these days most people just do:
String s1 = "...", s2 = "...";
if (s1.equals(s2)) {
....
}
Using Vector instead of the new Collections.
Using classes instead of enums
public class Enum
{
public static final Enum FOO = new Enum();
public static final Enum BAR = new Enum();
}
Using Thread instead of the new java.util.concurrency package.
Using marker interfaces instead of annotations
It is worth noting that Java 5.0 has been out for five years now and there have only been minor changes since then. You would have to be working on very old code to be still refactoring it.

Categories

Resources