LoginSignup
2
3

More than 1 year has passed since last update.

【Java】実は難しいIntegerの配列(1~Nまでの初期化)

Posted at

はじめに

そもそもJavaでIntegerの配列を扱うことは少ないと思います。
java.util.Listを使うほうが一般的です。これはIntegerの配列をどうしても生成したかったため、筆者が試した記録です。

基本的な定義方法

要素数3のInteger配列の定義は以下のようになります。

要素数3のInteger配列の定義
Integer[] numbers = new Integer[3];

このときの配列の中身はnullが並びます。

出力
Integer[] numbers = new Integer[3];
Arrays.stream(numbers).forEach(System.out::println);
出力結果
null
null
null

1~NまでのInteger配列を作る

単純にやるのであれば以下の方法でいけます。

1~Nまでの配列を作るメソッド
private Integer[] createNumbers(int n){
  Integer[] numbers = new Integer[n];
  for (int i = 0; i < n; i++) {
    numbers[i] = Integer.valueOf(i + 1);
  }
  return numbers;
}

オートボクシングが働くのでInteger#valueOfはなくても動きます。

オートボクシング
private Integer[] createNumbers(int n){
  Integer[] numbers = new Integer[n];
  for (int i = 0; i < n; i++) {
    numbers[i] = i + 1;
  }
  return numbers;
}

Stream APIを使ってなんとかしたい!

さてintの配列であればStreamを使って作ることができます。

intの配列
private static int[] createNumbers(int n) {
  return IntStream.rangeClosed(1, n).toArray();
}

すっきりしたコードでかけますね。
Integerだとそもそも1~NまでのStreamを作ることが少しめんどくさいです。

Streamを使った例
private Integer[] createNumbers(int n){
  return IntStream.rangeClosed(1, n).mapToObj(Integer::valueOf).toArray(Integer[]::new);
}

以下の手順でIntegerの配列を作ることができます。

  1. IntStreamで1~NまでのStreamを作り、
  2. mapToObjでIntegerのStreamに変換し、
  3. toArrayで配列に変換

なお、toArrayを引数なしで呼び出すとObject[]が戻り値になってしまいます。

Stream#toArrayの引数

さてIntStream#toArrayの引数は配列の生成関数(IntFunction<A[]>)となっています。
これは以下のようなシグネイチャを指します。

A[] function(int i){
  return hoge; // A[]型
}

なおJavaDocを見ると、「要求された配列のサイズを表す整数を受け取り」とあります。
軽く検証するために以下のようなコードを実行してみました。

検証コード
IntStream.rangeClosed(1, n).mapToObj(Integer::valueOf).toArray(i -> {System.out.println(i);return new Integer[i];});

結果は当然nの値が表示されます。たとえばn=3であれば3です。
しかし10だけ余裕を持った配列を生成したい場合、以下のように処理を書けば良さそうですがそうはいきません。

private Integer[] createNumbers(int n){
  return IntStream.rangeClosed(1, n).mapToObj(Integer::valueOf).toArray(i -> new Integer[i + 10]);
}

実行時エラーとなり、n=3のときは以下のようなメッセージが出力されます。
java.lang.IllegalStateException: Begin size 3 is not equal to fixed size 13
要素に余裕がほしい場合、(Integerに限らず)Streamは使わないほうが賢明でしょう。

まとめ

普通にforを回す or IntStream.rangeClosed(1, n).mapToObj(Integer::valueOf).toArray(Integer[]::new)で生成できます。

Stream#toArrayは微妙に使いにくいという印象を受けました。
引数なしでStream<T>.toArray()の結果はT[]のほうがみんな幸せな気がしますがどういう経緯なんですかね?
初期化用の関数渡せるわりに要素数を指定できないのでT[]::new以外で使い道がほぼないのに・・・。

2
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3