Javaで配列を結合するためにはいくつかの方法がある。その中でも、クラスライブラリを使ってしまうのが楽だろう。
このページではJavaの配列の結合についてお伝えする。参考にしていただければと思う。
目次
Javaで配列を結合する方法
配列を結合する方法はいくつかある。コードを最初から書いてもよいが、Javaのクラスライブラリを使えばスマートに配列を結合できる。
では、配列を結合するために使えるJavaのクラスライブラリの使い方を紹介しよう。
利用できるクラスライブラリ
ここでは、3つのクラスライブラリを紹介する。どれを使うかは、いろいろな場面に応じて、使い分けることになる。
Java 標準クラスライブラリ
Java標準のライブラリの中にあるパッケージjava.langにSystemクラスがある。そのSystemクラスに配列をコピーするarraycopyクラスメソッドがある。このメソッドを使うとふたつの配列の間で要素をコピーすることができる。
結合した結果を入れる配列を準備しておいて、そこに結合したい配列をコピーする。このような方法ために、このクラスメソッドが使える。
書き方はこうだ。
1 2 3 4 |
配列の型名[] 配列変数名 = System.arraycopy ( コピー元配列変数名, コピー元の開始位置, コピー先配列変数名, コピー先の開始位置, コピーする要素の数) |
詳細は「クラスライブラリ」のセクションで説明している。
Apache Commons Lang
Apache Commons Langによって提供されるクラスライブラリがある。その中の ArrayUtilsクラスに配列を結合するaddAllクラスメソッドがある。このメソッドを使うとふたつの配列間の要素を結合した新たな配列を作ることができる。単純に配列を結合するだけなら、System.arraycopyメソッドよりこのメソッドのほうが簡単だ。
とはいえ、準備としてクラスライブラリをダウンロードして、Javaの開発環境に取り込んでおくことが必要である。
基本的な書き方はこうだ。
配列の型名[] 配列変数名 = ArrayUtils.addAll (配列変数名1, 配列変数名2)
詳細は「クラスライブラリ」のセクションで説明している。
Java 8 Stream
Java 8で標準クラスライブラリに新たに追加されたjava.util.streamパッケージにStreamクラスがある。その新たなクラスにconcatクラスメソッドがある。このメソッドを使うとふたつの配列間の要素を結合して新たな配列を作ることができる。Streamを使うために配列からStreamに変換し、また配列に戻す必要がある。しかし、一度Streamに変換すればStreamの新たな機能を使うことができる。
基本的な書き方はこうだ。
Stream 変数名 = Stream.concat (Sterm変数名1, Stream変数名2)
詳細は「クラスライブラリ」のセクションで説明している。
System.arraycopyを使ったサンプルプログラム
それでは実際にサンプルプログラムを確認してみよう。
このサンプルプログラムは、最初に結合した結果を入れる配列を準備しておいて、そこに結合したいふたつの配列をコピーする。
配列要素がプリミティブ型
1 2 3 4 5 6 7 8 9 10 11 12 |
import java.util.Arrays; public class PrimitiveTypeArrayConcatenationByUsingJavaAPI { public static void main(String args[]) { int[] array1 = {0, 1 ,2};//[1] int[] array2 = {3, 4, 5, 6};//[2] int[] concatenatedArray = new int[array1.length + array2.length];//[3] System.arraycopy(array1, 0, concatenatedArray, 0, array1.length);//[4] System.arraycopy(array2, 0, concatenatedArray, array1.length, array2.length);//[5] System.out.println("[6] " + Arrays.toString(concatenatedArray)); } } |
実行結果
1 |
[6] [0, 1, 2, 3, 4, 5, 6] |
配列要素が参照型
1 2 3 4 5 6 7 8 9 10 11 12 |
import java.util.Arrays; public class ReferenceTypeArrayConcatenationByUsingJavaAPI { public static void main(String args[]) { String[] array1 = {"ab", "cd", "ef" };//[1] String[] array2 = {"gh", "ij", "kl", "mn"};//[2] String[] concatenatedArray = new String[array1.length + array2.length];//[3] System.arraycopy(array1, 0, concatenatedArray, 0, array1.length);//[4] System.arraycopy(array2, 0, concatenatedArray, array1.length, array2.length);//[5] System.out.println("[6] " + Arrays.toString(concatenatedArray)); } } |
実行結果
1 |
[6] [ab, cd, ef, gh, ij, kl, mn] |
サンプルプログラムの説明
それでは簡単にプログラムの解説をしてゆこう。
- [1] 配列array1を定義し、配列要素を代入する。
- [2] 配列array2を定義し、配列要素を代入する。
- [3] 配列concatenatedArrayをarray1のデータ数とarray2のデータ数の合計の大きさで定義する。
- [4] メソッドarraycopyでarray1をconcatenatedArrayの先頭からコピーする。
- [5] メソッドarraycopyでarray2をconcatenatedArrayにコピーしたarray1の後に続けてコピーする。
- [6] 配列concatenatedArrayの要素すべてを表示する。
ArrayUtils.addAllを使ったサンプルプログラム
このサンプルプログラムは、結合したいふたつの配列をメソッドの引数として渡している。結合した結果を入れる配列を準備しておく必要はない。addAllメソッドが新たに配列を作ってくれるからだ。
配列要素がプリミティブ型
1 2 3 4 5 6 7 8 9 10 11 |
import org.apache.commons.lang3.ArrayUtils; import java.util.Arrays; public class PrimitiveTypeArrayConcatenationByUsingApacheCommonsLang { public static void main(String args[]) { int[] array1 = {0, 1 ,2};//[1] int[] array2 = {3, 4, 5};//[2] int[] concatenatedArray = ArrayUtils.addAll(array1, array2);//[3] System.out.println("[4] " + Arrays.toString(concatenatedArray)); } } |
実行結果
1 |
[4] [0, 1, 2, 3, 4, 5] |
配列要素が参照型
1 2 3 4 5 6 7 8 9 10 11 |
import org.apache.commons.lang3.ArrayUtils; import java.util.Arrays; public class ReferenceTypeArrayConcatenationByUsingApacheCommonsLang { public static void main(String args[]) { String[] array1 = {"ab", "cd", "ef" };//[1] String[] array2 = {"gh", "ij", "kl", "mn"};//[2] String[] concatenatedArray = ArrayUtils.addAll(array1, array2);//[3] System.out.println("[4] " + Arrays.toString(concatenatedArray)); } } |
実行結果
1 |
[4] [ab, cd, ef, gh, ij, kl, mn] |
サンプルプログラムの説明
それでは簡単にプログラムの解説をしてゆこう。
- [1] 配列array1を定義し、配列要素を代入する。
- [2] 配列array2を定義し、配列要素を代入する。
- [3] メソッド;addAllでarray1とarray2を結合して新たな配列concatenatedArrayを生成する。
- [4][5] 配列concatenatedArrayの要素すべてを表示する。
Streamを使ったサンプルプログラム
このサンプルプログラムは、結合したいふたつの配列をSteamに変換して結合し、また配列に戻している。結合した結果を入れる配列を準備しておく必要はない。toArrayメソッドが新た配列を作ってくれるからだ。
配列要素がプリミティブ型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.util.Arrays; import java.util.stream.IntStream; public class PrimitiveTypeArrayConcatenationByUsingJava8 { public static void main(String args[]) { int[] array1 = {0, 1 ,2};//[1] int[] array2 = {3, 4, 5, 6};//[2] IntStream arrayStream1 = Arrays.stream(array1);//[3] IntStream arrayStream2 = Arrays.stream(array2);//[4] IntStream concatenatedArrayStream = IntStream.concat(arrayStream1, arrayStream2);//[5] int[] concatenatedArray = concatenatedArrayStream.toArray();//[6] System.out.println("[7] " + Arrays.toString(concatenatedArray)); } } |
実行結果
1 |
[7] [0, 1, 2, 3, 4, 5, 6] |
配列要素が参照型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.util.Arrays; import java.util.stream.Stream; public class ReferenceTypeArrayConcatenationByUsingJava8 { public static void main(String args[]) { String[] array1 = {"ab", "cd", "ef" };//[1] String[] array2 = {"gh", "ij", "kl", "mn"};//[2] Stream<String> arrayStream1 = Arrays.stream(array1);//[3] Stream<String> arrayStream2 = Arrays.stream(array2);//[4] Stream<String> concatenatedArrayStream = Stream.concat(arrayStream1, arrayStream2);//[5] String[] concatenatedArray = concatenatedArrayStream.toArray(String[]::new);//[6] System.out.println("[7] " + Arrays.toString(concatenatedArray)); } } |
実行結果
1 |
[7] [ab, cd, ef, gh, ij, kl, mn] |
サンプルプログラムの説明
それでは簡単にプログラムの解説をしてゆこう。
- [1] 配列array1を定義し、配列要素を代入する。
- [2] 配列array2を定義し、配列要素を代入する。
- [3] 配列array1をStream:arrayStream1に変換する。
- [4] 配列array2をStream:arrayStream2に変換する。
- [5] Stream.concatメソッドによりarrayStream1とarrayStream2を結合して新たなStream:concatenatedArrayを生成する。
- [6] Stream: concatenatedArrayを配列に変換する。
- [7] 配列concatenatedArrayの要素すべてを表示する。
クラスライブラリの詳細
サンプルプログラムの中で使っているふたつのメソッドのAPI仕様を見てみよう。
System.arraycopy
arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
戻り値の型 |
public static void |
内容 |
コピー元の配列の指定された位置から、コピー先の配列の指定された位置へ配列をコピーする。配列要素の一部がsrcによって参照されるコピー元の配列から、destによって参照されるコピー先の配列にコピーされる。コピーされる要素の数はlength引数と同じである。コピー元の配列の中のsrcPosからsrcPos+length-1の位置にある要素が、コピー先のdestPosからdestPos+length-1の位置にひとつひとつにコピーされる。
もし、srcとdest引数が同じ配列オブジェクトを参照しているならば、最初にsrcPosからsrcPos+length-1の位置にある要素が、長さの要素とともに一時的な配列にコピーされ、それから一時的な配列の内容がコピー先のdestPosからdestPos+length-1の位置の要素にコピーされる。 もしdestがnullならば、NullPointerExceptionを投げられる。 もしsrcがnullならば、NullPointerExceptionが投げられ、コピー先の配列は変更されない。
そうではなく、もし次のケースが成り立つならば、ArrayStoreException投げられ、コピー先配列は変更されない。 ・src引数が、配列でないオブジェクトを参照している。 ・dest引数が、配列でないオブジェクトを参照している。 ・src引数とdest引数が参照する配列の要素が、異なるプリミティブ型である。 ・src引数がプリミティブ要素型で配列を参照していて、dest引数が参照要素型で配列を参照している。 ・src引数が参照要素型で配列を参照していて、dest引数がプリミティブ要素型で配列を参照している。
そうではなく、もし次のケースが成り立つならば、IndexOutOfBoundsExceptionが投げられ、コピー先配列は変更されない。 ・src引数が、マイナス値である。 ・dest引数が、マイナス値である。 ・length引数が、マイナス値である。 ・srcPos+lengthが、src.length、つまりコピー元の配列の長さより大きい。 ・destPos +lengthが、dest.length、つまりコピー先の配列の長さより大きい。
そうではなく、もしsrcPosの位置からsrcPos+length-1までのどの配列要素も代入によって変換するとこができなければ、ArrayStoreExceptionが投げられる。 この場合、kをsrc[srcPos+k]がコピー先の要素型に変換できないような配列の長さより小さい正の整数の最小値とすると;例外が投げられた時、コピー元のsrcPosからsrcPos+k-1の位置の配列要素は、既にコピー先のdestPosからdestPos +k-1の位置の配列要素にコピーされてしまっている。そして、コピー先の配列のその他の位置の要素は変更されていない。 (既に取り上げた制約の理由で、この部分はふたつの配列が参照型の要素型を持つ場合に限って適用される。)
引数: src – コピー元配列 srcPos – コピー元の開始位置 array.dest – コピー先配列 destPos – コピー先データの開始位置 length – コピーする要素の数
例外; IndexOutOfBoundsException – コピーが配列の境界の外へのアクセスを起こした場合。 ArrayStoreException – 型の不一致によりsrc配列の要素がdest配列に保存できない場合。 NullPointerException – srcかdestがnull.の場合。 |
ArrayUtils.addAll
ここでは、配列要素が参照型の仕様を取り上げて説明する。プリミティブ型の要素の仕様もほぼ同じだが、詳しくは「Apache Commons Lang」にある。
addAll(T[] array1, T... array2)
戻り値の型 |
public static <T> T[] |
内容 |
与えられた配列群のすべての要素を新たな配列に追加する。 新たな配列はarray1に続いてarray2のすべての要素を含む。配列が戻された時、それはいつでも新たな配列である。
ArrayUtils.addAll(null, null) = null ArrayUtils.addAll(array1, null) = cloned copy of array1 ArrayUtils.addAll(null, array2) = cloned copy of array2 ArrayUtils.addAll([], []) = [] ArrayUtils.addAll([null], [null]) = [null, null] ArrayUtils.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"]
型 引数:T – Stream要素の型
引数; array1 – 新たな配列に追加される最初の配列。Nullかもしれない。 array2 – 新たな配列に追加される2番目の配列。Nullかもしれない。
戻り値:新たな配列、もし両方の配列がnullならばnullである。新しい配意列の型は、最初の配列がnullでない限り最初の配列の型である。そして、最初の配列がnullのなら、型は2番目の配列と同じになる。
以降:2.1 |
Java 8 Stream.concat
concat(Stream<? extends T> a, Stream<? extends T> b)
戻り値の型 |
static <T> Stream<T> |
内容 |
最初のStreamのすべての要素に続いて2番目のStreamのすべての要素を時間的な余裕をもって結合したStreamを生成する。もし両方の入力Streamがorderedであれば、結果のStreamもorderedになる。そして、もし入力Streamのどちらかがparallelであれば、結果のStreamもparallelになる。 結果のStreamがクローズした時、close handlerが両方の入力のために起動される。
実装上の注意点: 繰り返される結合からStreamを生成する場合の注意である。深く結合されたStream要素へのアクセスは、深い繋がりかStackOverflowExceptionを呼び出す。
型 引数:T – Stream要素の型
引数; a – 最初のStream b – 2番目のStream
戻り値:ふたつの入力Streamの結合 |
まとめ
このページでは配列の結合方法についてまとめてお伝えした。
ライブラリの解説含めて載せているので、使うときがあれば、参照していただければと思う。