質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

コンストラクタ

オブジェクト指向言語において、オブジェクトを生成時に呼び出され、データの初期化などを行なう関数・メソッドのことである。

Q&A

解決済

2回答

577閲覧

[Java]指定された行、列サイズと入力された行列のサイズが異なる場合、エラー文を出力したい

karintage

総合スコア5

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

コンストラクタ

オブジェクト指向言語において、オブジェクトを生成時に呼び出され、データの初期化などを行なう関数・メソッドのことである。

0グッド

0クリップ

投稿2022/07/05 06:38

編集2022/07/05 06:52

前提

行列の値が保存されているテキストファイルを読み込み(テキストファイルは入力ストリームで指定、3つのファイルがある)、その内容を二次元配列に格納するプログラムを作成しています。

テキストファイルは

3 3
0.1 0.2 0.3
0.4 0.5 0.6
0.7 0.8 0.9

のように、1行目に行、列のサイズ、2行目以降が行列の内容となっています。
//追記
プログラム実行時に、以下のようにファイルを指定します。

javau Matrix A.txt B.txt C.txt

実現したいこと

以下の例のように、33行列と指定されているのに対し、実際の行列が23であるように、指定されたサイズと入力されたサイズが異なる場合、その旨("M×Nと行列のサイズが一致しません")を出力したいです。

3 3
1 2 3
1 2 3

発生している問題・エラーメッセージ

3 3
1 2 3
1 2 3
を入力した場合は

java.lang.NullPointerException at Matrix.read(Matrix.java:49) at Matrix.main(Matrix.java:154)

3 3
1 2
1 2
1 2
を入力した場合は

java.lang.ArrayIndexOutOfBoundsException: 2 at Matrix.read(Matrix.java:51) at Matrix.main(Matrix.java:154)

と出力されます。

該当のソースコード

Java

1/** 2 プログラム:ファイルの値を読み込み二次元配列に格納する 3 二次元配列を用いて行列積、和、差を計算する 4*/ 5import java.io.*; 6import java.text.Format;/* フォーマットのため */ 7import java.text.DateFormat;/* 日付のフォーマット用 */ 8import java.util.Calendar; 9import java.text.SimpleDateFormat; 10 11public class Matrix{ 12 13 private double[][] m;//条件(1)行列をprivate名,double型のメンバ変数とする 14 private int row, col;//行サイズと列サイズをprivateなint型のメンバー変数とする 15 16 /*条件(2)Matrixクラスのコンストラクタとして、無引数のものpublic Matrix()を作成 */ 17 public Matrix(){ 18 } 19 /*条件(2)Matrixクラスのコンストラクタとして、(1)で述べた行と列を引数で与える2引数のものを作成*/ 20 public Matrix(int M, int N){ 21 this.row=M; 22 this.col=N; 23 m=new double[M][N]; 24 25 } 26 27/*条件(6):M行N列の実数データ(スペース区切り)を記述したデータ用ファイルから読み込み、Matrixクラスのオブジェクトを生成する関数。*/ 28 public Matrix read(String filename){ 29 Matrix mat=new Matrix();//ダミーオブジェクトを作成 30 try { 31 BufferedReader br = new BufferedReader(new FileReader(filename)); 32 String[] rowcol = br.readLine().split(" ");//1行目読み込み(行と列のサイズが記述されている) 33 mat.row = Integer.parseInt(rowcol[0]);//行のサイズ 34 mat.col = Integer.parseInt(rowcol[1]);//列のサイズ 35 mat.m = new double[mat.row][mat.col];//配列のサイズを指定 36 37 for (int row_read = 0; row_read < mat.row; row_read++) {//読み込む行を指定 38 if(rowcol==null){ 39 System.err.println("M×Nと行列のサイズが一致しません"); 40 System.exit(1); 41 } 42 String[] record = br.readLine().split(" "); //(row_read)行の文字列を読み込み、空白で分割 43 for (int col_read = 0; col_read < mat.col; col_read++){//読み込む列を指定 44 if(record[col_read]==null){ 45 System.err.println("M×Nと行列のサイズが一致しません"); 46 System.exit(1); 47 } 48 mat.m[row_read][col_read] = Double.parseDouble(record[col_read]);//読み込んだ値をdouble型に変換して二次元配列に格納 49 } 50 } 51 br.close(); 52 } 53 /*ファイルが存在しない場合、エラーを出力しプログラム終了 */ 54 catch (FileNotFoundException e) { 55 e.printStackTrace(); 56 System.exit(1); 57 } 58 /*フォーマットエラーの場合、エラーを出力しプログラム終了 */ 59 catch (NumberFormatException e) { 60 e.printStackTrace(); 61 System.exit(1); 62 } 63 /*stackした場合、エラーを出力しプログラム終了 */ 64 catch (IOException e) { 65 e.printStackTrace(); 66 System.exit(1); 67 } 68 69 return mat;//作成したオブジェクトを返り値とする 70 } 71 72/*条件:(5)Matrixクラスが保持するM×N行列の中身の要素をプリントするvoid型のprint()関数*/ 73 public void print(){ 74 System.out.printf("サイズ:(%d,%d)\n",row,col);//行列のサイズを出力 75 /*2重ループで行、列を指定して行列の中身を出力 */ 76 for (int i = 0; i < row; i++) { 77 System.out.print("|"); 78 for (int j = 0; j < col; j++){ 79 System.out.print(" " + (String.format("%.6f",m[i][j])));//小数点7桁目を四捨五入して出力 80 } 81 System.out.println("|"); 82 } 83 System.out.println();//改行 84 } 85 86 /*条件(3) :行列の乗算を実行し、結果を別のMatrixクラスのオブジェクトとして返す関数*/ 87 public Matrix multiply(Matrix B) { 88 /*行列A:M×K,行列B:K×NのKが一致していない場合エラー文を出力し、プログラムを終了*/ 89 if (col != B.row){ 90 System.err.print("Aの列サイズとBの行サイズが一致しません"); 91 System.exit(1); 92 } 93 Matrix D = new Matrix(row, B.col);//乗算の結果を格納するオブジェクトDを作成 94 /*3重ループで行列積を計算 */ 95 for (int i = 0; i < row; i++){ 96 for (int j = 0; j < B.col; j++) { 97 for (int k = 0; k < B.row; k++){ 98 D.m[i][j] += m[i][k] * B.m[k][j]; 99 } 100 } 101 } 102 return D;//オブジェクトDを戻り値とする 103 } 104 105 /*条件(4):Matrixクラスの2つのサイズが一致するオブジェクトに対して、要素ごとの加算(add)を行う関数*/ 106 public Matrix add(Matrix B){ 107 /*条件(D):Matrixクラスの2つのサイズが一致しない場合プログラムを終了*/ 108 if(row != B.row || col != B.col){ 109 System.err.print("行列Cと行列Dの行、列のサイズが異なります"); 110 System.exit(1); 111 } 112 Matrix E = new Matrix(row,col);//加算の結果を格納するオブジェクトEを作成 113 /*2重ループで加算を行う */ 114 for(int i=0; i<row; i++){ 115 for(int j=0; j<col; j++){ 116 E.m[i][j]=m[i][j]+B.m[i][j]; 117 } 118 } 119 return E;//オブジェクトEを戻り値とする 120 } 121 122 /*条件(4):Matrixクラスの2つのサイズが一致するオブジェクトに対して、要素ごとの減算(subtraction)を行う関数*/ 123 public Matrix sub(Matrix B){ 124 /*条件(D):Matrixクラスの2つのサイズが一致しない場合プログラムを終了*/ 125 if(row != B.row || col != B.col){ 126 System.exit(1); 127 } 128 Matrix F = new Matrix(row,col);//減算の結果を格納するオブジェクトFを作成 129 /*2重ループで加算を行う */ 130 for(int i=0; i<row; i++){ 131 for(int j=0; j<col; j++){ 132 F.m[i][j]=m[i][j]-B.m[i][j]; 133 } 134 } 135 return F;//オブジェクトFを戻り値とする 136 } 137 138 /*main文 */ 139 public static void main(String[] args){ 140 try { 141 Matrix mat=new Matrix();//条件(A):main関数から無引数のMatrixのコンストラクタを呼び出し、Matrixオブジェクトを生成する 142 /*条件(B):コマンドラインからの引数(args[])を与え、個々のファイルを読み込み、行列の中身をプリントする 143 引数が3でないときは警告文を出力し、プログラム終了*/ 144 if(args.length != 3){ 145 System.err.println("「行列データファイルは3つ与えてください」"); 146 System.exit(1); 147 } 148 Matrix A=mat.read(args[0]);//args[0]から作成した配列を配列Aとする 149 System.out.print("入力行列A,"); 150 A.print();//配列Aを出力 151 152 Matrix B=mat.read(args[1]);//args[1]から作成した配列を配列Bとする 153 System.out.print("入力行列B,"); 154 B.print();//配列Bを出力 155 156 Matrix C=mat.read(args[2]);//args[2]から作成した配列を配列Cとする 157 System.out.print("入力行列C,"); 158 C.print();//配列Cを出力 159 160 /*条件(C):3=<M,N,K=<10を満たしていない場合は警告文を出力、プログラム終了*/ 161 if(A.row<3||A.row>10||A.col<3||A.col>10||B.col<3||B.col>10){ 162 System.err.println("3=<M,N,K=<10を満たしていません"); 163 System.exit(1); 164 } 165 /*条件(C):M,N,Kがすべて同じ場合、警告文を出力、プログラム終了 */ 166 if(A.row==A.col&&A.col==B.col&&A.row==B.row){ 167 System.err.println("M,N,Kのどれか一つは他と違う値にしてください"); 168 System.exit(1); 169 } 170 /*条件(C):乗算を実行する */ 171 Matrix D=A.multiply(B); 172 System.out.print("出力 積行列 D=A×B,"); 173 D.print(); 174 175 /*条件(D):行列Cと行列Dの要素ごとの加算、結果を出力*/ 176 Matrix E=C.add(D); 177 System.out.print("出力 要素和行列 E=C+(A×B),"); 178 E.print(); 179 /*条件(D):行列Cと行列Dの要素ごとの減算、結果を出力*/ 180 Matrix F=C.sub(D); 181 System.out.print("出力 要素差行列 F=C-(A×B),"); 182 F.print(); 183 184 185 } 186 catch (Exception e) { e.printStackTrace(); } 187 } 188}

試したこと

Matrix read 内で行を読み込むたびに、nullではないか確認し、行数の不一致を検知(指定されたサイズと一致していれば、nullになる前にfor文が終了しているはずと考えました)
列数の不一致に関してはわかりませんでした。

補足情報(FW/ツールのバージョンなど)

Java バージョン8

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/07/05 06:46

> テキストファイルは入力ストリームで指定 これはドコのことを言っているのでしょうか。 プログラムのパラメータとしてファイル名を 3 つ指定されているようですが。 また、コードが尻切れになっているようです。 全体をコピペして動作するよう、最後の } まで含むようにされたほうが良いように思います。 そして、このご質問は何方かの課題の回答を求めておられるように見えますが、他人に聞いて良い類でしょうか。
jimbe

2022/07/05 06:54 編集

行列指定とデータ数で、データ数が少ない場合を主にお考えのようですが、データ数が多い場合はどうされるつもりでしょうか。 >Matrix read 内で行を読み込むたびに、nullではないか確認し、行数の不一致を検知(指定されたサイズと一致していれば、nullになる前にfor文が終了しているはずと考えました) そのような部分が見当たりませんが、実際やってみてどうだったのでしょうか。もしダメだったのでしたら、なぜダメだったのかはどうお考えになりましたか。
karintage

2022/07/05 07:49

データ数が多い場合に関しては今回は考えていません。 >そのような部分が見当たりませんが、実際やってみてどうだったのでしょうか。もしダメだったのでしたら、なぜダメだったのかはどうお考えになりましたか。 if(rowcol==null){ System.err.println("M×Nと行列のサイズが一致しません"); System.exit(1); } の処理で行数の不一致を検知しているつもりです。 実行されない原因としては、ファイルの最後の行を読み込んだ後、br.ReadLine()==nullとなっているものの、rowcol==nullではないためと考えます。 しかし、 if(br.ReadLine()==null) とするとエラー(NullPointerException)となります。こちらの原因については理解できていません。
guest

回答2

0

こんな感じ等如何でしょう。
(メソッドの中で exit するのは良くありませんので例外を投げています)

java

1 Matrix read(String filename) throws IOException { 2 Matrix mat; 3 try(BufferedReader br = new BufferedReader(new FileReader(filename));) { 4 String line = br.readLine(); 5 if(line == null) throw new IOException("M×N の指定がありません"); 6 String[] mn = line.split(" "); 7 if(mn.length != 2) throw new IOException("M×N の指定に異常があります. line=" + line); 8 try { 9 int m = Integer.parseInt(mn[0]); 10 if(m <= 0) throw new NumberFormatException("M <= 0"); 11 int n = Integer.parseInt(mn[1]); 12 if(n <= 0) throw new NumberFormatException("N <= 0"); 13 mat = new Matrix(m, n); 14 } catch(NumberFormatException e) { 15 throw new IOException("M×N の指定に異常があります. line=" + line, e); 16 } 17 18 for(int i=0; i<mat.row; i++) { 19 line = br.readLine(); 20 if(line == null) throw new IOException("行が足りません. i=" + i); 21 String[] v = line.split(" "); 22 if(v.length != mat.col) throw new IOException("列が多いか足りません. i=" + i + ", line=" + line); 23 try { 24 for(int j=0; j<v.length; j++) mat.m[i][j] = Double.parseDouble(v[j]); 25 } catch(NumberFormatException e) { 26 throw new IOException("行列データ値に異常があります. i=" + i + ", line=" + line, e); 27 } 28 } 29 30 if(br.readLine() != null) throw new IOException("行が多すぎます"); 31 } 32 return mat; 33 }

投稿2022/07/05 08:33

jimbe

総合スコア12632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

karintage

2022/07/05 08:41

ありがとうございます! この場合、以下の処理を追加するとエラーが発生するのですが、追加することは可能でしょうか? /*ファイルが存在しない場合、エラーを出力しプログラム終了 */ catch (FileNotFoundException e) { e.printStackTrace(); System.exit(1); } /*stackした場合、エラーを出力しプログラム終了 */ catch (IOException e) { e.printStackTrace(); System.exit(1); }
jimbe

2022/07/05 10:18

どちらも read メソッド内にいれる必要は無いと思います。 read の呼び出しは main の try 内で行われていますので、例外情報はそちらで表示されます。 また、回答にも書いていますがメソッド内で exit はしない方が良いです。(それは、本件の現時点では問題が無いかもしれませんが、不要な潜在的問題を抱えることになる類いです。) 因みにどこに追加してどの様なエラーとなったのでしょうか。
karintage

2022/07/11 14:50

返信が遅くなり大変申し訳ございません。 上記のreadメソッド内 catch(NumberFormatException e) のあとに追加しました。 ご指摘の通り、mainのtryに対するcatchで FileNotFoundException IOException を実行することで解決しました。 ありがとうございます。
guest

0

ベストアンサー

なぜそうなるのかというと1行目の行、列のサイズが後のデータのサイズと一致しないケースを想定しているはずなのに
データを読み込む際には1行目で読み込んだ行、列のサイズを使ってループして読み込もうとしているからです。

行が足りないときはbr.readLine()はnullを返すのにbr.readLine().split(" ");でnullにアクセスして例外
列が足りないときは Double.parseDouble(record[col_read]); if(record[col_read]==null)で存在しない列の値を読もうとして例外
という感じになっています。

投稿2022/07/05 06:57

編集2022/07/05 07:34
RiaFeed

総合スコア2701

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

karintage

2022/07/05 07:14

ありがとうございます。原因についてはわかったのですが、行が足りないとき、br.readLine().split(" ");が実行される前に、if文によりプログラムを終了するとしているのですが、if文が実行されていない(条件が間違えている)ということでしょうか。
RiaFeed

2022/07/05 07:28

条件が間違っています。そもそもrowcolがnullだった場合その前のInteger.parseInt(rowcol[0]);で例外が出るのでこのifは何の意味もありません。(というかその前にbr.readLine().split(" ");で例外がでるか) br.readLine().split(" ");とひとまとめに実行するのではなく、splitする前にbr.readLine()でnullチェックをしてください。 ループ中にnullになったら行が足りないのでエラー扱いにしてください。 これだけでは行が多い場合は対応できないのでループ外でreadline()して読み込めたら行が多いのでエラーです。
RiaFeed

2022/07/05 07:40 編集

列のほうは配列の範囲外にアクセスしようとした時点で即例外になるので、 nullチェックではなく配列の長さを取得して1行目で取得した列数と異なっていたらエラー扱いしましょう。
shiketa

2022/07/05 08:04

横から失礼。 ファイルを開いて読みながら回すのではなく、すべてのレコードを最初に読み込んでしまったほうがロジックがすっきりするのではないでしょうか。もっとも、テキストファイルが1000万行もあるのであればおすすめはできませんが。 List<String> lines = new BufferedReader(new FileReader(filename)).lines().collect(Collectors.toList());
karintage

2022/07/05 08:31

先にnullチェックをして後から分割する処理にしたいのですが、以下の記述だと ・2行目をよみこんでnullチェック ・String[]recordに分割した値を格納するときに3行目を読みこむ となってしまいます 2行目のnullチェックを行った後、2行目を分割するためにはどのように記述すればよいでしょうか for (int row_read = 0; row_read < mat.row; row_read++) {//読み込む行を指定 br.readLine(); if(br.readLine()==null){ System.err.println("M×Nと行列のサイズが一致しません"); System.exit(1); } String[] record = br.readLine().split(" "); //(row_read)行の文字列を読み込み、空白で分割
RiaFeed

2022/07/05 08:42 編集

br.readLine();の戻り値を変数に入れないと1行読み飛ばすことになってしまいます。 nullチェックするなら。 String line = br.readLine(); if(line == null) { System.err.println("M×Nと行列のサイズが一致しません"); System.exit(1); } String[] record = line.split(" ");
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問