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

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

新規登録して質問してみよう
ただいま回答率
85.47%
Java

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

Q&A

解決済

4回答

2355閲覧

【Java】Q.なぜvoidがダメなのか分かりません。

ZaigaKishitani

総合スコア1

Java

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

0グッド

1クリップ

投稿2022/05/24 04:34

編集2022/05/31 07:39

書籍「スッキリわかるJava入門第3版」の600ページの15章Javaを支えるクラスたちの練習問題15-2に以下の問題があります。

 ■問題文:フォルダ名が入っている変数folderとファイル名が入っている変数fileがあります。fileは必ず「readme.txt」のような形式をしてますが、folderは末尾に¥記号が付いている場合と付いていない場合の両方がありえます。たとえば、「c:¥javadev」や「c:
¥user¥」のどちらもfolderの値として考えられます。
folderとfileを連結して、「c:¥javadev¥readme.txt」のような完全なファイル名としての文字列を完成させるメソッドを作成してください。

模範解答(以下図1とす)が

public class Main { public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ } public String concatPath(String folder,String file) { if(!folder.endsWith("¥¥")) { folder += "¥¥"; } return folder + file; } }

でした。しかし、String concatPathの部分はvoid concatPathでもいいように思えます。具体的には以下のようなコード(以下図2とす)です。

public class Main{ public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ } pblic void concatPath() { String folder; String file; if(!folder.endsWith("¥¥")) { folder += "¥¥"; } System.out.println(folder + file); } }

eclipseで入力するとエラーの文章は出ませんが、図2の

if(!folder.endsWith("¥¥")) { folder += "¥¥"; } System.out.println(folder + file);

の「folder」と「 file」全ての部分の下に赤線が出てきて、それぞれにカーソルを合わせると、「ローカル変数folderが初期化されていない可能性があります」「ローカル変数fileが初期化されていない可能性があります」と出てきます。

Q.図1の

public String concatPath(String folder,String file) {


はいいのに、図2の

pblic void concatPath() { String folder; String file;


はダメなんでしょうか? 

 ちなみに、書籍「スッキリわかるJava入門第3版」の182Pで「メソッドとは」、200Pで「戻り値とは」などは既に学習しました。200Pではreturnの使い方も学びました。271P以降では「オブジェクト指向をはじめよう」も学習しました。グーグルで調べたり、書籍を読み返してもよくわかりません。
◆疑問1.私の予想としては、
■問題文中に「メソッドを作成してください」と記載があるので、mainメソッドでそれを呼び出すメソッドを作らないといけない
⇨だから、作成したメソッド、すなわち、concatPathメソッドには仮引数を作らないといけない
⇨仮引数は同じ型でないといけないからString型でないといけない

だから、模範解答の様になるんでしょうか?

◆疑問2.仮引数なしでもメソッドは作れるからreturnで返す必要はないのではないかと思うのですが違いますか? mainメソッドで呼び出しても、作成したメソッド、すなわち、concatPathメソッドで直接変数に代入すればいいと思うのですが違うんでしょうか?

長くなりましたが、ご指導ご回答よろしくお願い申し上げます。

追記:申し訳ありません。ご指摘いただいた箇所の訂正と理解等に時間がかかっています。申し訳ないです。

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

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

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

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

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

BeatStar

2022/05/24 06:27

コードはMarkdownを使いましょう。 https://teratail.com/help/question-tips#questionTips35 を参考にしてやってみましょう。 というか、ご自身の質問にあるコードと回答者のコードを比較して違和感を持たないのでしょうか。 初回らしいので仕方ないことかもしれませんが、何度も質問している人もこの手のやり方をするのが目立ちます…
BeatStar

2022/05/24 06:41

質問は編集できるので編集してください。
BeatStar

2022/05/30 09:37

編集を確認しました。 惜しいっ… 質問本文をご自分で見てください。 ちょっとずれていますよね。 恐らく、余計な「`」が付与されている可能性がありますね。もしくは開始と終了のやつが合っていないか。とにかくもうちょっとですよ。
ZaigaKishitani

2022/05/31 08:14

編集が滞って申し訳ないです。 Markdownでの修正を再度行いました。すいません、質問文の編集と返信を同時に行なった方がいいと思ったのですが、teratailは複数回の返信が可能でしたでしょうか? 可能なのでしたらもっとこまめに返信した方がよかったです。その場合は重ねてお詫びいたします。  また、Markdownでソースコードとして修正した部分を取り消す場合は「```ここに言語を入力」の部分を消せば良いんでしょうか? そこを消したりして3度ほど修正してみたのでご確認いただければ幸いです。ご返信が難しけれお目を通していただくだけでも大丈夫です。申し訳ないです。
BeatStar

2022/05/31 08:26

返信そのものは回数制限はありません。(関係のない話をだらだらと続けるのはアレだと思いますが) MarkdownについてはOKです。
guest

回答4

0

ベストアンサー

基礎からやるべきです

まず、メソッドの使い方がおかしいです。メソッドの基本構文は

[アクセス修飾子] メソッドの型 メソッド名( 引数 ... ){ // 何らかの処理 return 戻り値; }

です。

ちなみにアクセス修飾子とはメソッドの前についているpublicとかprivateとかのアレです。

ただし、「メソッドの型 = 戻り値の型」です。
では「戻り値」とはなんでしょうか。そもそも戻り値の役割はなんでしょうか。

今回の質問を別のもので表現するとしたらjava.lang.Math.max(int a, int b)メソッドを独自のメソッドとして組め。的な課題だったらどうしますか?
しかもそのメソッドを動かした後に計算した最大値を使って別の処理をするとか。

ヒント: Math.maxメソッド

質問にあるやり方(メソッド内で計算後にそのままSystem.out.printlnメソッドで表示する)だとどのように最大値を別の処理に使うのでしょうか?

メソッド(関数)は「処理をしてその結果を呼び出し側に返す」という目的のためです。
数学でいう f(x) = x^2 + 1 に x を代入した結果が返ってくる感じです。
現実世界でいえば自販機に貨幣と「どの商品を購入するか」の情報を入れた後に内部では計算や客に渡すために返却口じゃないけどあの部分に出す…みたいなアレです。
関数は計算してその結果を呼び出し側に返す。

その返される値が戻り値と呼ばれ、その戻り値を呼び出し側に渡す処理を戻り値を返すと表現します。
で、数学でいうf(x)のxの部分の値はその都度変わります。なので決め打ちはできませんから呼び出し側が指定してあげる必要があります。この指定される値を引数と呼ばれます。

だから関数は引数と呼ばれるものは引数を受け取って処理をして、その結果を戻り値として返す。
これが基本。そうすることで呼び出し側(mainメソッドとか)は内部で行われている処理内容はわからなくても「こいうデータを入れると○○という処理をして結果を返す」と分かっていればそのまま使える。

Math.maxメソッドが内部でどのように実装されているかわからなくても「引数として渡した二つの引数の最大値を返してくれる」ってことがわかっていれば使えるのです。

ですが質問にあるように内部でSystem.out.printlnメソッドとかで標準出力してしまったら呼び出し側は受け取れません。

だからメソッドの型がvoidだとダメなんです。voidでもいいのは、「処理をするだけで、結果は関係ない」か、「強制的にすべて行う処理ではあるが、もし失敗すれば例外として伝える」的なものか、「引数は(クラスオブジェクトのような)参照なので戻り値として返す必要が無い」とかぐらいのものでしょうか。

処理をするだけ…これはたとえばmainメソッドにある処理を分割してまとめるだけとか。
~失敗すれば例外として伝える…これはよっぽどの理由(「ファイルを読み込んで処理する」とかの場合でそもそもファイルが無いとかのように処理続行不可能とか)で例外を投げて「これ以上、処理するのは無理っす」と伝えるだけ。
~戻り値として返す必要が無い…たとえばC言語でいう「ポインタを用いて引数を戻り値扱いにする」とかみたいな感じ。

そういう特殊な場合は戻り値をvoidにしますが、「最大値を計算するメソッド」「学生達の国語や数学の点数から合計点を計算するメソッド」というような結果を呼び出し側に返すようなメソッドの場合はvoidにすると結果を返せません。結果を返せないのでダメです。

AさんがBさんに「この商品リストから欲しいものを選んで俺に教えてくれ。俺が買ってくるから」と頼んだけどBさんは頭の中で選んだだけでAさんに伝えません。Aさんはどうすればいいでしょうか。
みたいな状態です。Bさんが「これとこれが欲しい」と言わないとAさんは買いに行けませんよね。それと一緒です。

でも「このリストにある商品はあの店にあるから自分が好きなものを買ってきて」だったらBさんはAさんに何も言う必要はないですよね。この言う必要が無い場合はvoidです。

そして、

ローカル変数folderが初期化されていない可能性があります

ですが、質問にあるコードを見ると、

Java

1public void concatPath() { 2 String folder; 3 String file; 4 if(!folder.endsWith("¥¥")) { 5 folder += "¥¥"; 6 } 7 System.out.println(folder + file); 8}

とあります。

コードを読んでみましょう。コードを読むコツは「一行レベルで、その行が何をしているかを考えながら読む」ことと「変数等のデータの値を意識しながら読む」です。

Java

1public void concatPath() { 2 // folderというオブジェクトを用意 3 String folder; 4 // fileというオブジェクトを用意 5 String file; 6 // folderの中身が"\"で終わっていれば 7 if(!folder.endsWith("¥¥")) { 8 // 末尾に"\"を追加 9 folder += "¥¥"; 10 } 11 // 連結して表示 12 System.out.println(folder + file); 13}

このコメントにした部分を疑似コードとして抽出してみましょう。

1. folderというオブジェクトを用意 2. fileというオブジェクトを用意 3. folderの中身が"\"で終わっているなら 3.1. 末尾に"\"を追加 4. その結果を出力

となるはずです。これを手順書みたいな感じで手作業でやってみましょう。具体的なデータを入れてみたり。

(1)や(2)でfolderやfileをノートに用意しますがまだ値は分かっていません。
(3)でfolderの値をチェックしますが、値はまだせっていされていません。
ノートにはfolder = ????, file = ???のようになっているはずです。
そもそもわからない値を『末尾が""かどうか』なんてわからないはずです。そもそも対象物が無いから。
よって(3)で処理できないのです。他の言語(C言語とか)では「空(から)のデータ」として考えて『末尾には無いぞ』としますが、Javaだと値が設定されないために「データが設定されていないから出来ないぞ」とお節介を焼いてエラーを吐きます。

つまり「値が設定されていないから処理できない」というお節介です。

投稿2022/05/24 06:24

編集2022/05/31 08:35
BeatStar

総合スコア4958

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

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

ZaigaKishitani

2022/05/31 08:18

Voidでもいいパターンを並べていただきありがとうございます。参考にいたします。  すいません、どうしてもわからなかったのですが、 >>戻り値として返す必要が無い…たとえばC言語でいう「ポインタを用いて引数を戻り値扱いにする」とかみたいな感じ。  これは戻り値ではなくポインタを使い、引数を使って2つ以上の情報を返す時の様なことを仰ってるのでしょうか? Javaで普通に戻り値を使うと1つの情報しか返せないから。ポインタはC++の分野であっていますか? C++は10月くらいから学ぼうと思っていたので、断片的にしかまだ調べられてないのですが、そういったパターンということでしょうか?  今回の質問でメソッドを作る際は、仰っていただいた3つのパターンに当てはまらない場合はvoidは使わず、代わりに戻り値の型と引き数がつくことを前提にすればいいのかと思っていますが、それであっていますでしょうか? 長くなってしまっているので本当に申し訳ないです。簡略にでいいのでご指摘いただければありがたいです。申し訳ありません。 >>他の言語(C言語とか)では「空(から)のデータ」として考えて『末尾には無いぞ』としますが、Javaだと値が設定されないために「データが設定されていないから出来ないぞ」とお節介を焼いてエラーを吐きます。 の部分ですが、図2をイクリプスで書いてもコンパイルエラーは出ないです。代入してないので実行しても何も表示されませんが、folderやfileの部分にカーソルを合わせると「ローカル変数folderは初期化されてない可能性があります」と出ます。コンパイルエラーではないが、変数部分にカーソルを合わせるとエラー文(?)が出る、そのことを仰ってるんでしょうか?
BeatStar

2022/05/31 08:34

> これは戻り値ではなくポインタを使い、引数を使って2つ以上の情報を返す時の様なことを仰ってるのでしょうか? そうですね。それです。C言語でいえば void func( int *a, int *b ); の a,bのやつです。ただ、Javaでは仰るようにポインタが無いので(多分存在したとしても制限が付くかと思うが)できませんね。 > ポインタはC++の分野であっていますか? まあ、C言語とC++ですね。C++はC言語の内容にオブジェクト指向の考え方を取り入れた言語らしいので含んでいます。今回は言語がJavaなので関係のないC言語とかを出さない方がいいですが、説明しづらかったので… > 今回の質問でメソッドを作る際は、仰っていただいた3つのパターンに当てはまらない場合はvoidは使わず、代わりに戻り値の型と引き数がつくことを前提にすればいいのかと思っていますが 多分、本来はvoidを使わない方が正当というかそういう扱いで、『今回は不要だからvoidにするわw』ってことでvoidがあるんだと思いますよ。 > コンパイルエラーではないが、変数部分にカーソルを合わせるとエラー文(?)が出る、そのことを仰ってるんでしょうか? あ、多分それです。言語というか開発環境とかによってはコンパイラが吐くときとIDE側が教える場合があるようなので。どちらかと言えばお節介ですね。値を指定していないので実行時に何かしらのバグが出る可能性が高いので。
ZaigaKishitani

2022/06/01 06:43

ご返答ありがとうございます。 いずれC♯とC++も学習予定でしたので、C言語のお話は理解に少し時間がかかりましたが、全体を俯瞰しやすくなったのでむしろ助かりました。 本来はVOIDを使わない方が正当…ですね。記憶しておきます。 エラーはコンパイラが吐く時とIDE側が教える場合、二つあるということですね。テキストにもそういったことが書かれていたような気もしますが、量が膨大でうろ覚えでした。 懇切丁寧なご回答誠にありうがとうございました。BestStar様をベストアンサーとさせていただきたいと思います。時間がかかってしまい申し訳ありませんでした。基礎を振り返って学習していきたいと思います。今回の質疑を糧にちゃんとしたプログラマーになれる様に努めたいと思います。重ねてお礼申し上げます。ありがとうございました。
BeatStar

2022/06/01 07:03

エラーについてはちょっと違いますね。でも大体はそういう感じです。 細かく言えば、『コンパイルエラー』と『実行時エラー』とかみたいなものがあり、IDEは開発しやすくするためのサポート用プログラムで、コンパイル前とかに「なあ、これおかしくないか?」と同僚かだれかに指摘される感じです。あくまで楽に開発できるようにするためのものです。なのでお節介を焼くのです。 まあ頑張ってください。
ZaigaKishitani

2022/06/01 12:43

すいません、エラーについてももっと学びます…。 長々とありがとうございました!
guest

0

図1は双方の変数はその関数の引数です
そいつを呼び出す側が、その変数に値を設定して呼び出すんで、値が設定される、という前提で実行されます。
が、図2では変数が宣言されるだけでなにも代入されていません。
そんではダメ、といってますね

べつにvoidがだめ、ってわけじゃないです。

投稿2022/05/24 04:58

編集2022/05/24 04:59
y_waiwai

総合スコア87784

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

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

ZaigaKishitani

2022/05/31 08:20

申し訳ないです。違う方への返信をコメントしてしまいました。削除リクエストを行いました。ご迷惑おかけして大変申し訳ありません。 また、返信が遅くなり申し訳ないです。皆様方への返信とご指摘いただいた箇所への理解等に時間がかかりました。ご回答ありがとうございます。  Voidがダメでない理由もちゃんと理解します。すいません。
guest

0

ダメ元でも出版元や著者に質問を送っては如何でしょうか。

投稿2022/05/24 07:44

jimbe

総合スコア12696

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

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

ZaigaKishitani

2022/05/31 08:21

 .返信が遅くなり申し訳ありません。皆様方への返信とご指摘いただいた箇所への理解等に時間がかかりました。ご回答ありがとうございます。  問い合わせることを検討いたします。他の方のご回答で理解できそうなら頑張ってみます❕
guest

0

folder、fileの値が何処で設定されるか、作成されたメソッドが外部から呼ばれる可能性を考えてみてはいかがでしょうか。

投稿2022/05/24 05:02

javahack

総合スコア1088

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

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

ZaigaKishitani

2022/05/31 08:21

返信が遅くなり申し訳ありません。皆様方への返信とご指摘いただいた箇所への理解等に時間がかかりました。ご回答ありがとうございます。  はい、外部からメソッドが呼ばれるパターンを考えてみます❕
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問