0

I wanted to join some string arrays into one. And i used ArrayUtils.addAll(T[], T...) i found on some answers here. As it is described there, i should just cast it to a String array. When i try to do it, it shows me this error

Cannot store java.io.Serializable in an array of java.lang.String at org.apache.commons.lang3.ArrayUtils.addAll

My code is here

String[] splitLeft=split(left);
String[] middle=new String[]{with};
String[] splitRight=split(right);

String[] inWords=(String[])ArrayUtils.addAll(splitLeft,middle,splitRight);

What is the problem, and how can i fix this?

Ps: with is just a string.

kkica
  • 4,034
  • 1
  • 20
  • 40
  • what ArraysUtils are you using? https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/ArrayUtils.html#addAll(java.lang.Object[], java.lang.Object[]) - only accepts 2 arrays – Bojan Petkovic Sep 14 '17 at 21:29
  • 2
    @BojanPetkovic 3.6 goes up to 11. Well, not 11, to varargs. – pvg Sep 14 '17 at 21:30
  • I am using lang3 – kkica Sep 14 '17 at 21:31
  • As a side note, the cast is generally unnecessary. You can provide an explicit type argument with `ArrayUtils.addAll(...)` (also usually unnecessary) and the cast doesn't do anything that the direct assignment doesn't already in newer versions of Java. – Radiodef Sep 14 '17 at 21:35
  • @Radiodef the cast isn't unnecessary in the above code: the return type is genuinely `Serializable[]` there, and so has to be cast to `String[]` to assign it to that variable. *However*, that cast fails at runtime, because it's not a `String[]`. Were you to add the type constraint ``, the code wouldn't compile. – Andy Turner Sep 14 '17 at 21:37
  • @AndyTurner You would get the same error without the cast, because of target type inference. All the cast does is provide a target type and so does the assignment, so it is pointless. I think the linked answer has a cast because it was originally written for a version of the API before generics. – Radiodef Sep 14 '17 at 21:38
  • @Radiodef no, you don't get the same error: it doesn't compile without the cast https://ideone.com/So0esD. (And it does compile with the cast https://ideone.com/v0wPk9). – Andy Turner Sep 14 '17 at 21:39
  • @AndyTurner That's weird. I don't think that's in the JLS. – Radiodef Sep 14 '17 at 21:56
  • @Radiodef of course it is. As I state in my answer: the least upper bound of `String` and `String[]` is `Serializable`. LUB is described [here](https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.10.4). – Andy Turner Sep 14 '17 at 22:00
  • @AndyTurner On review, I think I am wrong, but not for that reason. Rather, because [a method invocation is not a poly expression when in a casting context](https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12), so the target type isn't considered during inference like I assumed it would. (See [18.5](https://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html#jls-18.5.2) *"If the invocation is not a poly expression, let the bound set B3 be the same as B2."*) – Radiodef Sep 14 '17 at 22:20
  • @Radiodef it has nothing to do with that. If you invoke `addAll(T, T...)` with `addAll(new String[0], new String[0][0])` (which is effectively what is being invoked here, type-wise), the only types which satisfy `T` are `Serializable` and `Object`. It doesn't matter what context you do that in: it has to infer one of those types. – Andy Turner Sep 14 '17 at 22:28
  • @Radiodef see here, where it's not invoked in an assignment context: https://ideone.com/A2m4TM – Andy Turner Sep 14 '17 at 22:34

1 Answers1

3

The problem here is that the signature of the method is:

    addAll(T[] array1, T... array2)

so the second and third parameters are being treated as single elements of array2: they are not concatenated; as such, the inferred type is Serializable, which is the least upper bound of String (the element type of the first parameter) and String[] (the element type of the varargs).

Instead, you'll have to join them in multiple calls, if you're going to do it with ArrayUtils.addAll:

addAll(addAll(splitLeft, middle), splitRight)

Alternatively, you can just build the concatenated array in a small number of statements:

// Copy splitLeft, allocating extra space.
String[] inWords = Arrays.copyOf(splitLeft, splitLeft.length + 1 + splitRight.length);

// Add the "with" variable, no need to put it in an array first.
inWords[splitLeft.length] = with;

// Copy splitRight into the existing inWords array.
System.arraycopy(splitRight, 0, inWords, splitLength.length + 1, splitRight.length);
Andy Turner
  • 137,514
  • 11
  • 162
  • 243