views:

1014

answers:

9

Hi all,

I'm looking for a method that will return a section or segment of an array - like if I wanted only the 4th and 5th bytes of a byte array. I don't want to have to create a new byte array in the heap memory just to do that. Right now I have the following code:

doSomethingWithTwoBytes(byte[] twoByteArray);

void someMethod(byte[] bigArray)
{
      byte[] x = {bigArray[4], bigArray[5]};
      doSomethingWithTwoBytes(x);
}

I'd like to know if there was a way to just do doSomething(bigArray.getSubArray(4, 2)) where 4 is the offset and 2 is the length, for example.

Anyone know?

Please let me know.

Thanks, jbu

A: 

List.subList(int startIndex, int endIndex)

Manuel Selva
You would first need to wrap the Array as a List: Arrays.asList(...).sublist(...);
camickr
+3  A: 

The Lists allow you to use and work with subList of something transparently. Primitive arrays would require you to keep track of some kind of offset - limit. ByteBuffers have similar options as I heard.

Edit: If you are in charge of the useful method, you could just define it with bounds (as done in many array related methods in java itself:

doUseful(byte[] arr, int start, int len) {
    // implementation here
}
doUseful(byte[] arr) {
    doUseful(arr, 0, arr.length);
}

It's not clear, however, if you work on the array elements themselves, e.g. you compute something and write back the result?

kd304
+8  A: 

If you're seeking a pointer style aliasing approach, so that you don't even need to allocate space and copy the data then I beleive you're out of luck.

System.arraycopy() will copy from your source to destination, and efficiency is claimed for this utility. You do need to allocate the destination array.

djna
yes, I was hoping for some kind of pointer method since I don't want to be dynamically allocating memory. but it looks like that's what i'm going to have to do.
jbu
+1  A: 

I see the subList answer is already here, but here's code that demonstrates that it's a true sublist, not a copy:

public class SubListTest extends TestCase {
    public void testSubarray() throws Exception {
     Integer[] array = {1, 2, 3, 4, 5};
     List<Integer> list = Arrays.asList(array);
     List<Integer> subList = list.subList(2, 4);
     assertEquals(2, subList.size());
     assertEquals((Integer) 3, subList.get(0));
     list.set(2, 7);
     assertEquals((Integer) 7, subList.get(0));
    }
}

I don't believe there's a good way to do this directly with arrays, however.

Carl Manaster
+4  A: 

You could use the ArrayUtils.subarray in apache commons. Not perfect but a bit more intuitive than System.arraycopy. The downside is that it does introduce another dependency into your code.

seth
It's the same as Arrays.copyOfRange() in Java 1.6
newacct
Ah, good to know. Thanks.
seth
+1  A: 

One option would be to pass the whole array and the start and end indices, and iterate between those instead of iterating over the whole array passed.

void method1(byte[] array) {
    method2(array,4,5);
}
void method2(byte[] smallarray,int start,int end) {
    for ( int i = start; i <= end; i++ ) {
        ....
    }
}
Sam DeFabbia-Kane
+2  A: 

Use java.nio.Buffer's. It's a lightweight wrapper for buffers of various primitive types and helps manage slicing, position, conversion, byte ordering, etc.

If your bytes originate from a Stream, the NIO Buffers can use "direct mode" which creates a buffer backed by native resources. This can improve performance in a lot of cases.

James Schek
A: 

Java references always point to an object. The object has a header that amongst other things identifies the concrete type (so casts can fail with ClassCastException). For arrays, the start of the object also includes the length, the data then follows immediately after in memory (technically an implementation is free to do what it pleases, but it would be daft to do anything else). So, you can;t have a reference that points somewhere into an array.

In C pointers point anywhere and to anything, and you can point to the middle of an array. But you can't safely cast or find out how long the array is. In D the pointer contains an offset into the memory block and length (or equivalently a pointer to the end, I can't remember what the implementation actually does). This allows D to slice arrays. In C++ you would have two iterators pointing to the start and end, but C++ is a bit odd like that.

So getting back to Java, no you can't. As mentioned, NIO ByteBuffer allows you to wrap an array and then slice it, but gives an awkward interface. You can of course copy, which is probably very much faster than you would think. You could introduce your own String-like abstraction that allows you to slice an array (the current Sun implementation of String has a char[] reference plus a start offset and length, higher performance implementation just have the char[]). byte[] is low level, but any class-based abstraction you put on that is going to make an awful mess of the syntax, until JDK7 (perhaps).

Tom Hawtin - tackline
+2  A: 

byte [] a = new byte [] {0,1,2,3,4,5,6,7};

// get a[4], a[5]

byte [] subArray = Arrays.copyOfRange(a, 4, 6);

// Arrays.copyOfRange() since Java 1.6

unhillbilly