Flutter Tips
【Java超初心者編 #7】実はややこしくないif文(後編)

※この記事は、「実はややこしくないif文(前編)」の続きです。

if文の練習:比較演算

涼羽18
……え、if文これで終わりですか!? イメージよりもだいぶ簡単で拍子抜けしちゃいました。
先生01
プログラミングにおいて、if文で躓く方は少なくないように思います。しかし、if文自体は本当に単純で、問題はifの中に何を書くかなのです。
涼羽19
なるほど……?
先生02
if文の理解のために、今回も問題を用意しました。今までのことを思い出しながら取り組んでみましょう。
涼羽02
はい!
先生01
まずは比較演算のif文です。次のプログラムの実行結果を予想してみてください。
int number1 = 100;
int number2 = 100;
if(number1 <= number2){
	System.out.println("yes");
} else{
	System.out.println("no");
}
涼羽01
丸括弧の中がtrueかfalseか、ってことですよね。number1もnumber2も中身は100だから、「100 <= 100」は「100は100以下ですか」って読めて、100は100を含んでるので、丸括弧の中はtrueですね。……ってことは、答えは「yes」です!
実行結果yes
先生02
その調子です。では2問目。
int number1 = 100;
int number2 = 100;
if(number1 < number2){
	System.out.println("yes");
} else {
	System.out.println("no");
}
涼羽02
「100は100より小さいですか」だけど、100は100より小さくない! つまり……falseだ! 答えは「no」です!
実行結果no
先生05
素晴らしいです。「<=」「>=」「<」「>」の使い方をきちんと覚えていますね。
涼羽18
比較演算はちょっとこんがらがったので、何回か復習し直しました。
先生01
では、もう1問だけ比較演算の問題を出しましょう。
int number1 = 200;
int number2 = 100;
if(number1 >= number2){
	System.out.println("yes");
} else {
	System.out.println("no");
}
涼羽08
number1は200でnumber2は100だから、「200は100以上ですか」になるので、文句なしのtrue。文句なしのyes。
実行結果yes
先生05
いいですね。
涼羽04
(そろそろ「天才の姫野さん」って言ってくれないかなー)
先生01
このように、比較演算は演算結果がtrueまたはfalseとなるので、丸括弧内に記述することができます。同様に、論理演算も丸括弧内に記述可能です。

if文の練習:論理演算

涼羽11
ってことは、次は論理演算とif文を組み合わせた問題をやるんですね!?
先生02
はい。実用的な例を挙げてみます。「東京または大阪在住のプレミアム会員向けの、期間限定キャンペーン」があるとして、その対象かどうかを判定するプログラムです。
boolean isPremiumMember = true;	//プレミアム会員:true
boolean isExpired = false;		//期限切れ:false
boolean isLiveInTokyo = true;	//東京在住:true
boolean isLiveInOsaka = false;	//大阪在住:false
if(isPremiumMember && !isExpired && ( isLiveInTokyo || isLiveInOsaka ) ){
	System.out.println("キャンペーン対象");
} else {
	System.out.println("キャンペーン対象でない");
}
涼羽25
何か一気にすごくカッコいいプログラムになりましたね!?
先生01
変数は効率的に用いましょう。まずはどこから演算すると思いますか?
涼羽09
ええと……。ifの丸括弧の中にある、( )の中でしょうか? ( )は優先順位が高いから。
先生02
その通りです。(isLiveInTokyo || isLiveInOsaka)はどうなるでしょうか。
涼羽01
バーバーは確か、「東京在住true」と「大阪在住false」にはtrueが含まれますか……ですよね。東京在住のほうにtrueが含まれてるから、trueを返します!
先生01
この時の状況はif(isPremiumMember && !isExpired && true)になりますね。
涼羽21
はい。それで次に計算するのは、「!」の演算子がついてる!isExpiredです! 期限切れfalseを逆転させるので、trueになりますね。そうすると、if(isPremiumMember && true && true)になるから……。
先生02
いい調子です。
涼羽20
まずは左側の「&&」から考えるとして、「プレミアム会員true」と「true」は両方ともtrueですか……。答えはtrueです。そうするとif(true && true)になりますよね。
先生02
仰る通りです。
涼羽25
「true」と「true」は両方ともtrueだから、if(true)ってことになりますね! そうしたら、ifのすぐ後ろの中括弧を実行するから、実行結果は「キャンペーン対象」です!
実行結果キャンペーン対象
涼羽08
(ドヤァ)
先生05
さすがは天才の姫野さんですね。
涼羽28
(「天才の姫野さん」やっときたー!)
先生02
ここで、「東京または大阪在住のプレミアム会員向けの、期間限定キャンペーン」 のif文の組み立て方を考えてみましょう。

まずは日本語で考えます。
if(東京または大阪在住でかつ、プレミアム会員でかつ、期間限定である)

ここから、「かつ」と「または」を「&&」と「||」に置き換えます。「||」は計算の優先順位の観点から、丸括弧で括っておくと間違いがありません。
if( (東京在住 || 大阪在住) && プレミアム会員である && 有効期限内である)

これを変数に置き換えていきます。
有効期限に関しては、変数の作り方が「有効期限内である」、例えばisValidDateのようなポジティブなネーミングになっていれば、以下のように書きます。
if( (isLiveInTokyo || isLiveInOsaka) && isPremiumMember && isValidDate)

逆に、変数の作り方が「期限切れである」、例えばisExpiredDateのようなネガティブなネーミングになっていれば、以下のように「!」で否定しつつ書きます。
if( (isLiveInTokyo || isLiveInOsaka) && isPremiumMember && !isExpiredDate)

涼羽23
あれ? 問題のコードと順序が違いますよね? でも、A && BとB && Aは実質一緒だから書く順番は別に気にしなくてもいっか。
先生02
基本的にはそう理解していただいて構いません。
涼羽17
基本的には?
先生04
はい。応用的な話になるので聞き流してもらっても構いませんが、厳密に言うと順番が大切になる場合があります。

※以下、今後「メソッド」の記事にて解説予定

「&&」「||」は厳密には「短絡演算子」という分類に含まれ、演算子の左側だけで結果がわかる場合、演算子の右側の計算を省略するように出来ています。

X && YのXがfalseの時 …Yは計算しなくても、X && Y → falseが確定する
X || YのXがtrueの時 …Yは計算しなくても、X || Y→trueが確定する

X側を軽い処理、Y側を重い処理にすることで処理時間を短縮できます。

涼羽22
なるほど? 天才なので何となくわかった気がします。

if文の練習:入れ子

先生01
では、そんな天才の姫野さんには、もう少し難しい問題を解いて頂きましょう。
涼羽02
天才の姫野さんにお任せあれ!
先生02
こちらはif文の中にif文が入っている、「入れ子」の問題です。
boolean readable = true; //読込可能    
boolean writable = false; //書込不可

if(readable){
	System.out.println("読込可能");
	if(writable){
		System.out.println("読込可能・書込可能");
	} else {
		System.out.println("読込可能・書込不可");
	}
} else {
	System.out.println("読込不可");
	if(writable){
		System.out.println("読込不可・書込可能");
	} else {
		System.out.println("読込不可・書込不可");
	}
}
涼羽14
えー、何ですかこれー! すごく複雑そう。
先生01
先程言った通り、if文そのものは単純です。実行結果はどうなると思いますか?
涼羽18
ぱっと見た印象なんですけど、多分「読込可能・書込不可」的なのが表示されるんですよね?
先生02
姫野さんは勘が鋭いですね。なぜそのように表示されるのか、考えてみましょう。
涼羽23
うーんと……。4行目のifから考えていくんですよね。readableはtrueだから、trueの時に実行する中括弧の中身も見なくちゃいけないわけですね。
先生02
はい。ですから、初めに「読込可能」を表示します。
涼羽21
で、その次に6行目の、入れ子になってるifを考えるんでしょうか。writableはfalseだから、elseより後ろの中括弧の中身を見るんですよね。そうしたら、「読込可能・書込不可」ですか?
先生01
そうなります。とすると、最終的な実行結果は?
涼羽24
「読込可能」と「読込可能・書込不可」の2つが出るんでしょうか?
実行結果読込可能
読込可能・書込不可
先生02
その通りです。では、類題として、readableをfalseに、writableをtrueに書き換えたものはどうなるでしょうか?
readable = false; //読込不可
writable = true; //書込可能  

if(readable){
	System.out.println("読込可能");
	if(writable){
		System.out.println("読込可能・書込可能");
	} else {
		System.out.println("読込可能・書込不可");
	}
} else {
	System.out.println("読込不可");
	if(writable){
		System.out.println("読込不可・書込可能");
	} else {
		System.out.println("読込不可・書込不可");
	}
}
涼羽03
今の話の流れだと、「読込不可」「読込不可・書込可能」になりますかね。
先生01
そうですね。理由も説明してみてください。
涼羽05
4行目のreadableがfalseだから、5行目から10行目までは無視して、11行目にあるelseの後の中括弧の中身を実行します。そうするとまず「読込不可」って出て……。その後、writableを見るわけですが、これはtrueだから、ifの直後の中括弧の中身「読込不可・書込可能」が出ます。
実行結果読込不可
読込不可・書込可能
先生05
素晴らしいです。
涼羽02
中括弧の中身がどこまでなのかを意識したら、意外と簡単にできました!
先生02
姫野さんの仰る通りで、if文では中括弧の範囲を把握することがとても重要です。複雑な入れ子構造になったプログラムはあまりいいプログラムとはいえないのですが、if文を実際に扱うと、入れ子が複雑になる場合があります。しかし、その場合でも、中括弧の範囲を意識していれば、苦労することはありません。
涼羽26
if文、楽しいですね! readableとwritableのやつって、変数のtrueとfalseをちょっといじるだけで、表示させるものを自由に変えられるんですよね。おもしろいなあ。
先生02
はい。元々組み立てておいた式と結果が正しければ、変数を変えても結果は正しいままです。
涼羽27
なんだかわくわくしちゃいます! カッコいいプログラムって感じがします!
先生04
(姫野さんの言う「カッコいいプログラム」って何なんだろう)

if文の実際:検索プログラム

涼羽23
先生、if文って実際にどんな感じで使われてるんですか?
先生02
例えば検索アプリで使われます。
涼羽02
そうなんですか? ちょっと書いてみたいです。どうやればいいでしょう?
先生01
それでは、テキストnekoの中に特定の言葉keywordが含まれているかどうかを検索するプログラムを組んでみましょうか。
涼羽09
検索するのって何を使えばいいんでしょうか?
先生02
containsを用います。A.contains(B)は「AにはBが含まれます」と翻訳でき、AにBが含まれていればtrueを、そうでなければfalseを返します。このcontainsを用いて、検索アプリを再現してみましょう。
涼羽26
なるほど! containsは文字列の検索で使える子なんですね!
先生01
以下に変数を用意しました。ifとcontainsを用いて、keyword1~3を検索するプログラムを書いてみてください。
String neko = "吾輩は猫である。名前はまだ無い。"
	+ "どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所で"
	+ "ニャーニャー泣いていた事だけは記憶している。";

String keyword1 = "猫";
String keyword2 = "ニャー";
String keyword3 = "にゃー";
涼羽20
頑張ってみます! containsは真偽値を出すからifの丸括弧の中に入れて……。else ifを使えばいいのかな? 便利だし。
if(neko.contains(keyword1)) {
	System.out.println(keyword1 + "を含みます");
} else if(neko.contains(keyword2)) {
	System.out.println(keyword2 + "を含みます");
} else if(neko.contains(keyword3)) {
	System.out.println(keyword3 + "を含みます");
} else {System.out.println("いずれの検索ワードも含みません");
}
実行結果猫を含みます
涼羽13
あれー!? 本当は「ニャー」も含んでるのに、猫しか含んでない!
先生04
else ifを用いたからですね。else ifでは、ifの内容が実行される場合に、それ以降のelse ifの内容が実行されません。
涼羽09
そっか……。そうすると、普通にifを3つ使えばいいんでしょうか?
if(neko.contains(keyword1)) {
	System.out.println(keyword1 + "を含みます");
}
if(neko.contains(keyword2)) {
	System.out.println(keyword2 + "を含みます");
}
if(neko.contains(keyword3)) {
	System.out.println(keyword3 + "を含みます");
}
実行結果猫を含みます
ニャーを含みます
先生01
その通りです。
涼羽10
やったー! でも、言葉を1つだけ検索するときはこれでいいですけど、例えば「猫」「ニャー」「にゃー」のどれかが入ってるかとか、全部入ってるかとか知りたい時って、どうするんでしょう?
先生02
いい質問です。先程のプログラムに論理演算を少し組み込めば、AND検索やOR検索を行うこともできます。こちらがAND検索です。
if(neko.contains(keyword1) && neko.contains(keyword2) && neko.contains(keyword3)) {
	System.out.println("「" + keyword1 + "」「" + keyword2 + "」「" + keyword3 + "」を全て含みます");
} else {
	System.out.println("「" + keyword1 + "」「" + keyword2 + "」「" + keyword3 + "」を全ては含みません");
}
実行結果「猫」「ニャー」「にゃー」を全ては含みません
涼羽23
すごい! AND検索では「&&」が使えるんですね! ってことは、OR検索をしたかったら、「&&」を「||」に変えればいいんでしょうか? こんな感じで……。
if(neko.contains(keyword1) || neko.contains(keyword2) || neko.contains(keyword3)) {
	System.out.println("「" + keyword1 + "」「" + keyword2 + "」「" + keyword3 + "」のいずれかを含みます");
} else {
	System.out.println("「" + keyword1 + "」「" + keyword2 + "」「" + keyword3 + "」のいずれも含みません");
}
実行結果「猫」「ニャー」「にゃー」のいずれかを含みます
先生02
はい、「||」を用いるとOR検索ができます。
ここで注意しておきたいのが、AND検索とOR検索の特徴です。AND検索の例では「全て含む/そうではない」ということは判別できますが、「全ては含みません」と表示された時の理由(どのキーワードが含まれていなかったのか?)はわかりません。同様にOR検索の例では「いずれかを含みます」と表示された時の理由(どのキーワードが含まれていたのか?)はわかりません。この特徴を理解して、先程のif文を3つ使う場合と上手く使い分けたり、組み合わせて使ったりしてくださいね。
涼羽24
わかりました! AND検索とOR検索を上手く使えば、例えばですけど、知り合いの男の子がどんな子なのかを登録しておいて検索するみたいなアプリも作れるんですかね?
先生10
……はい?
涼羽03
検索ワードに「イケメン」とか「天才」とか「料理上手」って入れると、「イケメンの検索結果:Aくん」「天才の検索結果:Bくん」「料理上手の検索結果:Cくん」「全てに該当:Dくん」みたいに出る感じの……。
先生09
なるほど……。でしたら、このようなプログラムはいかがでしょうか。
//検索ワード
String word1, word2, word3;
word1 = "イケメン";
word2 = "天才";
word3 = "料理上手";

//検索対象
String manA, manB, manC, manD;
manA = "Aくんはイケメンでお金持ち";
manB = "Bくんは天才で何でも卒なくこなす";
manC = "Cくんは料理上手で家庭的";
manD = "Dくんはお金持ちでイケメンで天才で料理上手だけど、ちょっとヴァイオレンス";

//word1の単体検索 
System.out.println("「" + word1 + "」の検索結果");
if(manA.contains(word1)) { System.out.println("Aくんが該当します"); }
if(manB.contains(word1)) { System.out.println("Bくんが該当します"); }
if(manC.contains(word1)) { System.out.println("Cくんが該当します"); }
if(manD.contains(word1)) { System.out.println("Dくんが該当します"); }
実行結果Aくんが該当します
Dくんが該当します
先生02
キーワードword1~word3を入力すると、その性質を持つ人物をmanA~manDから検索します。検索したい人物が増える度、変数などを入力し直す必要がありますが。
涼羽06
Dくんあなた……!
先生03
世の中に完全無欠な人はいないと僕は考えています。
涼羽15
(何か先生の闇を見た気がする)
先生01
「word1の単体検索」を参考にして、「word2, word3のAND検索」のプログラムを書いてみましょう。
涼羽01
頑張ってみます! まずは // でコメントを書いて……。改行したら、「「word2」かつ「word3」の検索結果」が出るように文字列結合。かぎ括弧に1つずつダブルクォーテーションを入れてくの地味にめんど……大変ですけど、Eclipseで"を打つと自動的にもう1個"を打ってくれるのは嬉しいですね。
先生02
その調子です。if以下は「word1の単体検索」をコピーして改変するとよいでしょう。
涼羽09
そうします。word2とword3のAND検索だから「&&」で繋ぐとして……Aくんのifの中身、if(manA.contains(word2) && manA.contains(word3))で大丈夫ですか?
先生02
はい、合っていますよ。その次の中括弧はコピー元と同じままで結構です。
涼羽23
そしたらBくん以下も同じようにする、と。こんな感じでどうでしょう?
//word2,word3のAND検索
System.out.println("「" + word2 + "」かつ「" + word3 + "」の検索結果");
if(manA.contains(word2) && manA.contains(word3)) { System.out.println("Aくんが該当します"); }
if(manB.contains(word2) && manB.contains(word3)) { System.out.println("Bくんが該当します"); }
if(manC.contains(word2) && manC.contains(word3)) { System.out.println("Cくんが該当します"); }
if(manD.contains(word2) && manD.contains(word3)) { System.out.println("Dくんが該当します"); }
先生01
大変よくできています。実行結果は何になると思いますか?
涼羽26
天才で料理上手なのはDくんだけなので、「Dくんが該当します」が出ると思います。
実行結果Dくんが該当します
涼羽18
個人的にはDくんのこと検索結果から除外したいですね。
先生03
彼のような人材が必要になる場合もあります。
涼羽21
(また先生の闇が垣間見えた気が……)
先生02
では最後に、「word1, word3のOR検索」にも取り組んでみましょう。先程作成したコードをコピーして改変してみてください。
涼羽26
わかりました! まずはコメントと「検索結果」のところを変えて……。次はword2をword1にして、「&&」を「||」にする。これでどうでしょう! これは多分、AくんCくんDくんが出ますね!
//word1,word3のOR検索
System.out.println("「" + word1 + "」または「" + word3 + "」の検索結果");
if(manA.contains(word1) || manA.contains(word3)) { System.out.println("Aくんが該当します"); }
if(manB.contains(word1) || manB.contains(word3)) { System.out.println("Bくんが該当します"); }
if(manC.contains(word1) || manC.contains(word3)) { System.out.println("Cくんが該当します"); }
if(manD.contains(word1) || manD.contains(word3)) { System.out.println("Dくんが該当します"); }
実行結果

Aくんが該当します
Cくんが該当します
Dくんが該当します

先生05
非常に素晴らしいです。
涼羽09
やっぱりDくんは除外したい気もしますけど。むしろ「要注意人物」みたいに表示させたい気もしますけど。そういうのって作れますか?
先生01
可能ですよ。姫野さんは当初、「プログラミングでハッカーのようなことがしてみたい」と仰っていたかと思いますが、今はもう少し具体的に、例えば、複雑な検索をおこなうプログラムを組んでみたいと思いますか?
涼羽03
ちょっと興味あるかも……?
先生02
目標があることはとてもよいことです。次回は検索とも関連してくる「リスト」についてお話ししようと思っています。
涼羽02
ちょっと難しそうな気配もしますが、楽しみです!
先生02
if文の復習もお忘れなく。
涼羽27
わかりました!

今回のまとめ

①if文とは
if(条件式){A} は、「もし条件式がtrueならAを実行する」と翻訳できる。
丸括弧内には、比較演算や論理演算など、最終的に真偽値になるものを記述する。
中括弧内にはtrueの時に何を実行するかを記述する(この中括弧内の記述は、falseの時には実行されない)。
・視認性のため、中括弧が増えたらタブを1つ増やす。また、中括弧閉じ } はifのiの位置に合わせる。

②elseについて
if(条件式){A} else {B}は、「もし条件式がtrueならAを実行する。そうでなければ(条件式がfalseならば)Bを実行する」と翻訳できる。
・丸括弧の真偽値がtrueなら前半の中括弧、falseなら後半の中括弧を実行する。
・elseは省略することが可能。
・前半の中括弧は不要で後半の中括弧のみを記述したい場合、元の条件式や真偽値を「!」で否定することで、else以降を省略することが可能。 

③else ifについて
if(条件式1){A} else if (条件式2){B}は、「もし条件式1がtrueならAを実行する。そうでなければ(条件式1がfalseという前提で)、もし条件式2がtrueならBを実行する」と翻訳できる。
ifの丸括弧内がtrueである時、より下にあるelse ifの丸括弧内の条件を満たしていても、その際の中括弧内は実行されない
・最後にelse{}を記述することで、全ての丸括弧内の真偽値がfalseである場合の実行内容を規定することができる。

④if文の練習
・if文自体は単純。if文の中に何を書くかが問題。
・if文が入れ子になった場合は特に、中括弧の範囲を把握することが肝要。

【付録】ジャンケンゲーム

先生02
最後に、if文を用いた実用的なプログラムを用意しました。ジャンケンゲームです。
涼羽24
えっ、if文だけでジャンケンできちゃうんですか!?
先生01
if文だけではありませんが、その解説は追々。以下のプログラムを、「入力」タブで0〜2の好きな数字を入力してから、実行してみてください。

涼羽11
すごい! 数字を入れるとジャンケンできるんですね! 3回連続で負けました。勝てるまでやりたくなっちゃう。
涼羽09
でもこれ、どういう仕組みなんですか?
先生02
以下にコードを示します。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;

public class Main {

	public static void main(String[] args) {
		int cpuHand = new Random().nextInt(3);
		int myHand = Integer.parseInt(keyboardInput("グーなら0 チョキなら1 パーなら2を入力:"));

		//入力ミス検知
		if(myHand < 0 || myHand > 2) {
			System.out.println("不正な値が入力されました");

			//プログラム終了
			return;
		}

		//CPUの出した手「0〜2」を「グー・チョキ・パー」に変換
		String cpuHandString = "";
		if(cpuHand == 0) {
			cpuHandString = "グー";
		} else if(cpuHand == 1) {
			cpuHandString = "チョキ";
		} else if(cpuHand == 2) {
			cpuHandString = "パー";
		}

		//自分の出した手「0〜2」を「グー・チョキ・パー」に変換
		String myHandString = "";
		if(myHand == 0) {
			myHandString = "グー";
		} else if(myHand == 1) {
			myHandString = "チョキ";
		} else if(myHand == 2) {
			myHandString = "パー";
		}

		System.out.println("あなたが出した手は:" + myHandString);
		System.out.println("CPUが出した手は:" + cpuHandString);

		if(cpuHand == myHand) {
			System.out.println("あいこです");
		} else if(cpuHand == 0) {
			if(myHand == 1) {
				System.out.println("CPUの勝ちです");
			} else {
				System.out.println("あなたの勝ちです");
			}
		} else if(cpuHand == 1) {
			if(myHand == 2) {
				System.out.println("CPUの勝ちです");
			} else {
				System.out.println("あなたの勝ちです");
			}
		} else if(cpuHand == 2) {
			if(myHand == 0) {
				System.out.println("CPUの勝ちです");
			} else {
				System.out.println("あなたの勝ちです");
			}
		}
	}

	//キーボード入力処理用
	private static String keyboardInput(String message) {
		String ret = "";

		try {
			System.out.print(message);
			ret = new BufferedReader(new InputStreamReader(System.in)).readLine();
		} catch(IOException e){
			e.printStackTrace();
		}

		return ret;
	}
}
涼羽28
カッコいいー!!
先生02
if文が随所で用いられていることが確認できたでしょうか?
涼羽26
思ってた以上にifだらけでした! 「あなたの勝ちです」とかエラーっぽいのとかを表示するのはイメージしやすいですけど、グー、チョキ、パーのどれを出すかもelse ifで決められるんですね!
先生01
はい。if文はそれ単体ではなく、様々な構文と組み合わせて用いられることが多いですね。
涼羽23
あ、よく見たら勝ち負けのところでelse ifの中にif elseが入ってます!
先生05
さすがは天才の姫野さん、ご慧眼です。勝敗判定は特にこだわったポイントで、else ifの中にif elseを入れ込んだ構造にしてあります。変数cpuHandの値を0、1、2と順番に表記してあり、変数myHandとの組み合わせ方や、どちらが勝つのかが一目瞭然です。else if の中でif elseを用いずに全ての勝敗パターンを列挙する方法もありますが、こちらのほうがシンプルで美しいと思いませんか? また、タブがあると見やすいというのもよくわかるかと思います。
涼羽03
(先生がかつてないほどに生き生きとしている……!)
先生05
姫野さん、いかがでしょうか?
涼羽02
すごいです。カッコいいです。こういうの、わたしも書けるようになれるでしょうか?
先生01
可能ですよ。一つ一つ積み重ねていくことが重要です。一緒に頑張っていきましょう。
涼羽27
はい、頑張ります!
おすすめの記事