I'm trying to implement a lambda function (for educational purposes) to initiate an array to append to the front of potentially encrypted data to save information like salt and initiation vector, which uses an if-elseif conditional to set its first byte to its own length (so you know where the buffer ends and data starts), and then to add the salt and initiation vector. Problem is I keep getting these errors:
The method setAll(T[], IntFunction<? extends T>) in the type Arrays is not applicable for the arguments (byte[]::buffer, ( i) -> {})
The target type of this expression must be a functional interface
Type mismatch: cannot convert from byte to T
From what I understand, this is because it doesn't like me using bytes. Why is this, and what are some ways to work around this?
The byte[] casting before buffer in the setAll parameter is added because I tried to make it not be T[] in an attempt to have it accept bytes.
public final class App {
public static void main(final String[] args) {
byte[] salt = new byte[16];
SecureRandom secRand = new SecureRandom();
secRand.nextBytes(salt);
byte[] initVectorBytes = new byte[16];
secRand.nextBytes(initVectorBytes);
byte[] buffer = new byte[salt.length + initVectorBytes.length + 1];
Arrays.setAll(byte[] buffer, i -> {
if(i ==0) {
return (byte) (salt.length + initVectorBytes.length + 1)
}else if(i < 17) {
return salt[i-1];
}else if(i >= 17) {
return initVectorBytes[i-17];
}
});
}
}
From what I understand, this is because it doesn't like me using bytes. Why is this, and what are some ways to work around this?
It doesn't like you using bytes because arrays of different element types are not compatible, and none of the overloads of Arrays.setAll() accepts an array argument of type byte[]. That includes the generic one, because type parameters can match only reference types, whereas byte is a primitive type.
In your particular case, the best workaround is probably to stop trying to be so clever. It would be clearer, shorter, and almost surely faster to do this, instead:
final static int SALT_LENGTH = 16;
final static int INIT_VECTOR_LENGTH = 16;
// ...
SecureRandom secRand = new SecureRandom();
byte[] buffer = new byte[1 + SALT_LENGTH + INIT_VECTOR_LENGTH];
secRand.nextBytes(buffer);
buffer[0] = buffer.length;
Even if there were a setAll() that worked on byte arrays, it wouldn't offer an advantage over that.
Note also that if this were for use in a method that might be invoked more than once then it it would be better to have a single SecureRandom that you reuse, instead of setting up a new one every time the method is invoked.
Furthermore, if you wanted to generate random bytes for only a small portion of a large array, such that it didn't make sense to start by filling the whole array, then System.arraycopy() is a much better way to copy a range of elements from from one array into another than Arrays.setAll().