「プロになるJava」の第3部「Javaの文法」の練習問題の解答です。
※ 2023/10/03 Streamの練習問題の答えが抜けていたので追加しています。
「プロになるJava」 第2部「Javaの基本」の練習問題解答 - きしだのHatena
「プロになるJava」 第3部「Javaの文法」の練習問題解答 - きしだのHatena
「プロになるJava」 第4部「高度なプログラミング」の練習問題解答 - きしだのHatena
第7章 条件分岐
論理型
1. 「test」に「st」が含まれているかどうかcontainsメソッドで確認してみましょう
jshell> "test".contains("st")
$1 ==> true
値の比較
1. 12と35を<
演算子を使って大小比較を行ってみましょう
jshell> 12 < 35
$2 ==> true
2. 12と35を<=
演算子を使って等しいかどうか比較を行ってみましょう
jshell> 12 <= 35
$3 ==> true
3. 12と35を==
演算子を使って等しいかどうか比較を行ってみましょう
jshell> 12 == 35
$4 ==> false
4. 12と35を!=
演算子を使って等しいかどうか比較を行ってみましょう
jshell> 12 != 35
$5 ==> true
オブジェクトの大小比較
1. "test"
と"TEST"
をcompareTo
メソッドで比較してみましょう。
jshell> "test".compareTo("TEST")
$6 ==> 32
解説:
一致しない最初の文字の差を結果として返します。
jshell> "test".compareTo("tdST")
$9 ==> 1
片方の文字列がもう片方の文字列の先頭部分の場合、長さの差を返します。
jshell> "test".compareTo("tester")
$14 ==> -2
2. 今日の日付と2022年3月15日をcompareTo
メソッドで比較してみましょう
jshell> LocalDate.now().compareTo(LocalDate.of(2022, 3, 15))
$11 ==> 15
Javadocでの明確な記述は見つけれませんでしたが、日数の差が返ってきますね。
これを書いているのは3月30日です。
jshell> LocalDate.now()
$12 ==> 2022-03-30
3. 今日の日付が2022年3月15日よりも前かどうかisBefore
メソッドで確認してみましょう
jshell> LocalDate.now().isBefore(LocalDate.of(2022, 3, 15))
$13 ==> false
オブジェクトが等しいかどうかの比較
1. 文字列「hello」にtoUpperCase
メソッドを呼び出した結果が「HELLO」であるかどうか確認してみましょう
jshell> "hello".toUpperCase().equals("HELLO")
$16 ==> true
equals
メソッドを使わず==
で判定すると、内容は同じだけど別オブジェクトであるということでfalse
になります。
jshell> "hello".toUpperCase() == "HELLO"
$17 ==> false
2. 2021年9月14日をLocalDate
で表したときに、plusDays
メソッドで10日足した結果が2021年9月24日であるかどうか確認してみましょう
jshell> LocalDate.of(2021, 9, 14).plusDays(10).equals(LocalDate.of(2021, 9, 24))
$18 ==> true
equals
メソッドを使わず==
で判定すると、内容は同じだけど別オブジェクトであるということでfalse
になります。
jshell> LocalDate.of(2021, 9, 14).plusDays(10) == LocalDate.of(2021, 9, 24)
$19 ==> false
if文での条件分岐
if文
1. 変数a
に割り当てる値を変えてみて、表示が変わることを確認しましょう。
変数a
に0を割り当てると、0は3よりも小さいので「小さい」が表示されます。
var a = 0;
if (a < 3) {
System.out.println("小さい");
}
変数a
に0を割り当てると、0は3よりも小さいので「小さい」が表示されます。
var a = 0;
if (a < 3) {
System.out.println("小さい");
}
変数a
に5を割り当てると、5は3よりも小さくないので何も表示されなくなります。
var a = 5;
if (a < 3) {
System.out.println("小さい");
}
変数a
に3を割り当てると、3は3よりも小さくないので何も表示されなくなります。
var a = 3;
if (a < 3) {
System.out.println("小さい");
}
else
1. 変数a
に割り当てる値を変えてみて、表示が変わることを確認しましょう。
変数a
に0を割り当てると、0は3よりも小さいので「小さい」が表示されます。
var a = 0;
if (a < 3) {
System.out.println("小さい");
} else {
System.out.println("大きい");
}
変数a
に5を割り当てると、5は3よりも小さくないので「大きい」が表示されます。
var a = 5;
if (a < 3) {
System.out.println("小さい");
} else {
System.out.println("大きい");
}
変数a
に3を割り当てると、3は3よりも小さくないので「大きい」が表示されます。
var a = 3;
if (a < 3) {
System.out.println("小さい");
} else {
System.out.println("大きい");
}
else if
1. 変数a
に割り当てる値を変えてみて、表示が変わることを確認しましょう。
変数a
に0を割り当てると、0は3よりも小さいので「小さい」が表示されます。
var a = 0;
if (a < 3) {
System.out.println("小さい");
} else if (a < 7) {
System.out.println("中くらい");
} else {
System.out.println("大きい");
}
変数a
に5を割り当てると、5は3よりも小さくなく、7よりも小さいので「中くらい」が表示されます。
var a = 5;
if (a < 3) {
System.out.println("小さい");
} else if (a < 7) {
System.out.println("中くらい");
} else {
System.out.println("大きい");
}
変数a
に10を割り当てると、10は3よりも小さくなく、7よりも小さくないので「大きい」が表示されます。
var a = 10;
if (a < 3) {
System.out.println("小さい");
} else if (a < 7) {
System.out.println("中くらい");
} else {
System.out.println("大きい");
}
変数a
に7を割り当てると、7は3よりも小さくなく、7よりも小さくないので「大きい」が表示されます。
var a = 7;
if (a < 3) {
System.out.println("小さい");
} else if (a < 7) {
System.out.println("中くらい");
} else {
System.out.println("大きい");
}
変数a
に3を割り当てると、3は3よりも小さくなく、7よりも小さいので「中くらい」が表示されます。
var a = 3;
if (a < 3) {
System.out.println("小さい");
} else if (a < 7) {
System.out.println("中くらい");
} else {
System.out.println("大きい");
}
switchでの条件分岐
switch
文
1. 変数a
の値が5だった場合に「five」と表示するようにcase
句を追加してみましょう
switch (a) {
case 1, 2 -> System.out.println("one-two");
case 3 -> System.out.println("three");
case 4 -> System.out.println("four");
case 5 -> System.out.println("five");
}
第8章 データ構造
Listで値をまとめる
List
1. LocalDate型であらわした2021年9月14日と2021年3月15日が格納されたListを用意してみましょう
(importが必要になるので注意してください)
jshell> import java.time.*
jshell> var dates = List.of(LocalDate.of(2021, 9, 14), LocalDate.of(2021, 3, 15))
dates ==> [2021-09-14, 2021-03-15]
2. 用意したList
から2番目の要素を表示してみましょう(2021-03-15が表示されるはずです)
jshell> dates.get(1)
$3 ==> 2021-03-15
変更のできるList
1. authors
に「hosoya」を追加してみましょう
jshell> authors.add("hosoya")
$6 ==> true
jshell> authors
authors ==> [yamamoto, naoki, sugiyama, hosoya]
2. authors
の2番目の要素を「kishida」に戻してみましょう
jshell> authors
authors ==> [yamamoto, naoki, sugiyama, hosoya]
jshell> authors.set(1, "kishida")
$8 ==> "naoki"
jshell> authors
authors ==> [yamamoto, kishida, sugiyama, hosoya]
3. LocalDate
を格納できるArrayList
を用意してdates
という変数に割り当ててみましょう
jshell> var dates = new ArrayList<LocalDate>()
dates ==> []
4. 変数dates
に割り当てたArrayList
に2021年9月14日を追加してみましょう
jshell> dates.add(LocalDate.of(2021, 9, 14))
$11 ==> true
jshell> dates
dates ==> [2021-09-14]
配列
配列の要素の利用
1. 要素が5つのint型の配列を用意してみましょう
jshell> var nums = new int[5]
nums ==> int[5] { 0, 0, 0, 0, 0 }
2. 用意した配列の3番目の要素に2を入れてみましょう
jshell> nums[2] = 2
$14 ==> 2
jshell> nums
nums ==> int[5] { 0, 0, 2, 0, 0 }
3. [2, 3, 5, 7]が入ったint型の配列を用意してみましょう
jshell> var nums2 = new int[]{2, 3, 5, 7}
nums2 ==> int[4] { 2, 3, 5, 7 }
4. 用意した配列の4番目の要素を得てみましょう(7が入っているはずです)
jshell> nums2[3]
$17 ==> 7
レコードで違う種類の値を組み合わせる
レコードのオブジェクトを生成する
1. String型のenglish、String型のjapaneseをコンポーネントにもったレコードWordを定義しましょう。
jshell> record Word(String english, String japanese){}
| 次を作成しました: レコード Word
2. Wordレコードのオブジェクトをいくつか作ってみましょう。
jshell> var apple = new Word("apple", "りんご")
apple ==> Word[english=apple, japanese=りんご]
jshell> var grape = new Word("grape", "ぶどう")
grape ==> Word[english=grape, japanese=ぶどう]
3. LocalDate型のdate、int型のprice、String型のmemoをコンポーネントにもったレコードSpendingを定義しましょう。
jshell> record Spending(LocalDate date, int price, String memo) {}
| 次を作成しました: レコード Spending
4. Spendingレコードのオブジェクトをいくつか作ってみましょう。
jshell> var s1 = new Spending(LocalDate.of(2022, 4, 6), 200, "たまご")
s1 ==> Spending[date=2022-04-06, price=200, memo=たまご]
jshell> var s2 = new Spending(LocalDate.of(2022, 3, 19), 3278, "プロになるJava")
s2 ==> Spending[date=2022-03-19, price=3278, memo=プロになるJava]
Mapで辞書をつくる
Map
変更可能なMap
1. 「dog」に対応する値をget
メソッドで取ってみましょう。
jshell> animals.get("dog")
$25 ==> "いぬ"
2. 「horse」に対して「うま」をput
メソッドで格納してみましょう。
jshell> animals.put("horse", "うま")
$26 ==> null
jshell> animals
animals ==> {horse=うま, dog=いぬ, fox=きつね, cat=猫}
HashMap
は順番を気にしないため、順番はここで示したものと違うことがあります。もし追加した順を保ちたい場合にはLinkedHashMap
を使います。
3. size
メソッドで件数を確認してみましょう。
jshell> animals.size()
$28 ==> 4
第9章 繰り返し
ループ構文
for文の基本
1. 3回「Hello」と表示するプログラムをForHelloというクラス名で作ってみましょう。
package projava;
public class ForHello {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
System.out.println("Hello");
}
}
}
2. 今回のサンプルプログラムの変数i
の名前をn
に変えてみましょう。
public static void main(String[] args) {
for (int n = 0; n < 5; n++) {
System.out.println(n);
}
}
こういった場合、変数i
に入力カーソルを置いて[Shift] + [F6]を押すと、利用箇所を含めまとめて名前を変更することができます。
3. 今回のサンプルプログラムを0から9まで表示するようにしてみましょう。
for (int n = 0; n <= 9; n++) {
System.out.println(n);
}
次のようにしても動作は同じですが、やりたいことに出てくる数字がそのままコードに出てくるほうが望ましいです。
for (int n = 0; n < 10; n++) {
System.out.println(n);
}
4. 今回のサンプルプログラムを1から10まで表示するようにしてみましょう。
for (int n = 1; n <= 10; n++) {
System.out.println(n);
}
次のようにしても動作は同じですが、やりたいことに出てくる数字がそのままコードに出てくるほうが望ましいです。
for (int n = 0; n < 10; n++) {
System.out.println(n + 1);
}
for文の応用
1. 0から35まで5ずつ増やしながら表示してみましょう
for (int i = 0; i <= 35; i += 5) {
System.out.println(i);
}
2. 20から0まで3ずつ減らしながら表示してみましょう
for (int i = 20; i >= 0; i -= 3) {
System.out.println(i);
}
結果は次のようになります。
20
17
14
11
8
5
2
ループのcontinueとbreak
continue文
1. 0から9まで表示してください。ただし3は表示を飛ばしてください
for (int i = 0; i <= 9; i++) {
if (i == 3) {
continue;
}
System.out.println(i);
}
2. 0から9まで表示してください。ただし3と5は表示を飛ばしてください
for (int i = 0; i <= 9; i++) {
if (i == 3 || i == 5) {
continue;
}
System.out.println(i);
}
switch
を使うと次のようになります。
for (int i = 0; i <= 9; i++) {
switch(i) {
case 3, 5: continue;
}
System.out.println(i);
}
->
を使って書く場合には、continue
文は中カッコで囲む必要があります。
for (int i = 0; i <= 9; i++) {
switch(i) {
case 3, 5 -> {
continue;
}
}
System.out.println(i);
}
3. 0から9まで表示してください。ただし3から6は表示を飛ばしてください
for (int i = 0; i <= 9; i++) {
if (i >= 3 && i <= 6) {
continue;
}
System.out.println(i);
}
break文
ここでの練習問題は、編集作業の不整合で意味のないものになってしまっています。本来の意図になるように書き換えています。
1. projava.BreakSample
という名前でクラスを作って次のループを動かしてみましょう。
for (int i = 0; i < 5; i++) {
System.out.println(i);
if (i < 3) {
continue;
}
System.out.println("finish");
break;
}
2. この例を動かすとどうなるか考えてみましょう。
3. 実際に動かしてみましょう。
ループに慣れる
デバッガでループを覗く
1. ほかのコードについてもデバッガ―で動作を確認してみましょう
解答略
2重ループ
1. この表は5x9までしか表示されていません。9x9が表示されるようにしてみましょう。
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
System.out.printf("%2d | ", i * j);
}
System.out.println();
}
次のように表示されます。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 |
3 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 |
4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 |
5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 |
6 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 |
7 | 14 | 21 | 28 | 35 | 42 | 49 | 56 | 63 |
8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 |
9 | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 |
内側のループ回数が変わる場合
1. 次のように表示されるようにしてみましょう
OOOOO
OOOO
OOO
OO
O
for (int i = 5; i >= 1; i--) {
for (int j = 0; j < i; j++) {
System.out.print("O");
}
System.out.println();
}
もう少しループの練習
丸を並べる
1. 上から4番目を赤くしてみましょう。
for (int x = 0; x < 12; x++) {
for (int y = 0; y < 12; y++) {
if (y == 3) {
g.setColor(Color.RED);
} else {
g.setColor(Color.WHITE);
}
g.fillOval(x * 30 + 50, y * 30 + 20, 25, 25);
}
}
2. ななめに赤くしてみましょう。
for (int x = 0; x < 12; x++) {
for (int y = 0; y < 12; y++) {
if (x == y) {
g.setColor(Color.RED);
} else {
g.setColor(Color.WHITE);
}
g.fillOval(x * 30 + 50, y * 30 + 20, 25, 25);
}
}
迷路ゲームをつくる
1. 右上がゴールになるようにしてみましょう
変数goal
の初期値を次のようにします。
var goal = new Position(4, 1);
2. 左下がスタートになるようにしてみましょう
変数current
の初期値を次のようにします。
var current = new Position(1, 3);
3. もっと大きい迷路を定義してみましょう
略
4. waszが上左右下になっていますが、uhjnを上左右下になるようにしてみましょう。
switch
式を次のように変更します。
var next = switch(ch) {
case 'h' -> new Position(current.x()-1, current.y());
case 'u' -> new Position(current.x() , current.y()-1);
case 'j' -> new Position(current.x()+1, current.y());
case 'n' -> new Position(current.x() , current.y()+1);
default -> current;
};
5. ゴールの位置にGと表示するようにしてみましょう
変数goal
と変数x
、y
を比較するelse if
を挿入します。
} else if (map[y][x] == 1) {
System.out.print("*");
} else if (y == goal.y() && x == goal.x()) {
System.out.print("G");
} else {
System.out.print(".");
}
次のようになります。
******
*.*.G*
*...**
*o*..*
******
6. 一歩進むごとに現在位置の表示を「o」と「O」で切り替えるようにしてみましょう。
これは少し難しいです。作戦には2通りあるのですが、まずは正攻法を紹介します。
現在の状態をあらわす変数を用意します。ここでは大文字かどうかをあらわすということでupper
とします。初期値にはfalse
を割り当てます。
var current = new Position(1, 3);
var upper = false;
表示のとき、upper
がtrue
であればO
、false
であればo
を表示するようにします。ここでは条件演算子を使っています。
if (y == current.y() && x == current.x()) {
System.out.print(upper ? "O" : "o");
そして、移動するときにupper
を反転するようにします。
if (map[next.y()][next.x()] == 0) {
if (!current.equals(next)) {
upper = !upper;
}
current = next;
}
これで移動するごとにo
とO
が切り替わります。
さてもうひとつの方法です。
今回は1マス動くごとに切り替わり、斜めには動けないので、マップ上でo
かO
のどちらが表示されるかは固定で、次のような感じになります。
oOoOoOo
OoOoOoO
oOoOoOo
OoOoOoO
oOoOoOo
そうすると、横位置と縦位置の合計が偶数のときにo
、奇数のときにO
を表示すれば移動ごとに切り替わるようになります。
System.out.print((x + y) % 2 == 0 ? "o" : "O");
7. 現在地のまわり2マスだけ表示するようにしてみましょう。つまり5x5マスが表示されるようにします。
ループの範囲をcurrent
の前後2つになるようにします。
そしてmap
からはみ出したときの処理を加えます。なにも表示しないという手もありますが、なにかを表示するようにすると自分が必ず中心になるので、よりゲームらしさが出ます。ここでは#を表示します。
for (int y = current.y() - 2; y <= current.y() + 2; ++y) {
for (int x = current.x() - 2; x <= current.x() + 2; ++x) {
if (y < 0 || y >= map.length || x < 0 || x >= map[y].length) {
System.out.print("#");
}else if (y == current.y() && x == current.x()) {
map
のデータを次のように壁を厚くして、map
からはみ出す部分が表示されることがないようにすると、「map
からはみ出したときの処理」を省けます。処理スピードが求められる場合に使われるテクニックです。
int[][] map = {
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 0, 1, 0, 0, 1, 1},
{1, 1, 0, 0, 0, 1, 1, 1},
{1, 1, 0, 1, 0, 0, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1}
};
このように、処理がはみださないように置かれるデータを番兵と呼ぶことがあります。番兵を置くことで処理を効率化します。
8. なにも入力せずに「Enter]キーを押したり、2文字入力して[Enter]キーを押したりすると、[z]キーなどを押しても移動しなくなります。どのような操作をすれば移動が行えるようになるか考えてみましょう。
[Enter]キーを押します。
次のように、文字を取得したあと[Enter]キーを表す\n
を受け取った場合に処理を飛ばすようにすると、文字を入力しても動かないということが起きなくなります。
int ch = System.in.read();
if (ch == '\n') continue;
第10章 データ構造の処理
データ構造を拡張for文で扱う
基本for文でのListの要素の処理
1. 次のように用意されたList
のすべての要素を表示するプログラムを基本for文を使って書いてみましょう。
var names = List.of("yusuke", "kis", "sugiyama");
package projava;
import java.util.List;
public class ExListForBasic {
public static void main(String[] args) {
var names = List.of("yusuke", "kis", "sugiyama");
for (int i = 0; i < names.size(); i++) {
System.out.println(names.get(i));
}
}
}
拡張for文でのListの要素の処理
1. 次のように用意されたListのすべての要素を拡張for文を使って表示するプログラムを書いてみましょう。
var names = List.of("yusuke", "kis", "sugiyama");
package projava;
import java.util.List;
public class ExListForExtended {
public static void main(String[] args) {
var names = List.of("yusuke", "kis", "sugiyama");
for (String name : names) {
System.out.println(name);
}
}
}
拡張for文での配列の要素の処理
1. 次の配列のすべての要素を表示するプログラムを拡張for文を使って書いてみましょう。
var names = new String[]{"yusuke", "kis", "sugiyama"};
package projava;
public class ExArrayForExtended {
public static void main(String[] args) {
var names = new String[]{"yusuke", "kis", "sugiyama"};
for (String name : names) {
System.out.println(name);
}
}
}
値の集合の処理のパターン
共通するパターン
1. List.of("apple", "banana", "grape")
について、次の処理を考えてみましょう。
var data = List.of("apple", "banana", "grape");
for (var fruit : data) {
if (fruit.length() == 5) {
System.out.println(fruit);
}
}
- 5文字ちょうどの文字列を取り出した新たなListを作る
var data = List.of("apple", "banana", "grape");
var result = new ArrayList<String>();
for (var fruit : data) {
if (fruit.length() == 5) {
result.add(fruit);
}
}
System.out.println(result);
var data = List.of("apple", "banana", "grape");
var result = 0;
for (var fruit : data) {
if (fruit.length() == 5) {
result++;
}
}
System.out.println(result);
- 5文字ちょうどの文字列のすべてが「p」を含むか確認する
まず「共通するパターン」に沿って書くと次のようになります。
var data = List.of("apple", "banana", "grape");
var result = true;
for (var fruit : data) {
if (!fruit.contains("p")) {
result &= false;
}
}
System.out.println(result);
「初期値」がtrue
、「結果を加える処理」が&=
になっています。
初期値には、計算の結果に影響がない値を設定することになります。足し算の場合は、0を足しても計算の結果に影響を与えません。掛け算の場合は1を掛けても計算の結果に影響を与えません。Listの場合は空のリストを追加しても影響がない、という考え方です。
このように、計算の結果に影響を与えない値を、その計算の単位元 といいます。
この場合、&
演算での単位元はtrue
になります。
「加える処理」なので&=
にしましたが、この場合は=
で構いません。
また、一度p
が含まれない文字列が来ると次以降のデータを確認しなくても「すべてがp
を含む」が満たされないことになるので、次以降のループの処理は不要になります。
for (var fruit : data) {
if (!fruit.contains("p")) {
result = false;
break;
}
}
- 5文字ちょうどの文字列のどれがひとつでも「p」を含むか確認する
var data = List.of("apple", "banana", "grape");
var result = false;
for (var fruit : data) {
if (fruit.contains("p")) {
result |= true;
}
}
System.out.println(result);
「初期値」がfalse
で、「結果を加える処理」が|=
になっています。
|
演算の単位元はfalse
になります。
また、一度p
が含まれる文字列が来ると次以降のデータを確認しなくても「どれがひとつでもp
を含む」が満たされることになるので、次以降のループの処理は不要になります。
for (var fruit : data) {
if (fruit.contains("p")) {
result = true;
break;
}
}
Stream
全体に対する処理
1. var strs = List.of("apple", "banana", "orange", "pineapple");があるとき、次の処理をStreamを使って書いてみましょう。
・6文字以上のものを大文字にして表示
jshell> strs.stream().
...> filter(s -> s.length() >= 6).
...> map(String::toUpperCase).
...> forEach(System.out::println)
APPLE
BANANA
ORANGE
PINEAPPLE
・6文字以上のものの文字数の合計を表示
数値での合計にはCollectors.summingInt
を使います。
jshell> strs.stream().
...> filter(s -> s.length() >= 6).
...> collect(Collectors.summingInt(String::length))
$2 ==> 21
String::length
はs -> s.length()
をメソッド参照の形にしたものです。
あとの章ででてくるmapToInt
を使うこともできます。
jshell> strs.stream().
...> mapToInt(String::length).
...> filter(l -> l >= 6).
...> sum()
$3 ==> 21
・すべての文字列がaを含んでるかどうか判定
jshell> strs.stream().allMatch(s -> s.contains("a"))
$4 ==> true
・cを含むものがひとつでもあるかどうか判定
jshell> strs.stream().anyMatch(s -> s.contains("c"))
$5 ==> false
基本型でのStream
StreamとIntStreamの行き来
1. String
クラスのrepeat
メソッドはJava 11で導入されたためJava 8では使えません。IntStream
を利用して"test"
を3回連結して"testtesttest"
を出力する処理を実装してみましょう。
package projava;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ExRepeat {
public static void main(String[] args) {
var result = IntStream.range(0, 3)
.mapToObj(n -> "test")
.collect(Collectors.joining());
System.out.println(result);
}
}
第11章 メソッド
メソッドの宣言
JShellでのメソッド宣言
基本的なメソッド
1. 「Hi!」と表示するhi
メソッドを宣言してみましょう
jshell> void hi() { System.out.println("Hi!");}
| 次を作成しました: メソッド hi()
2. 宣言したhi
メソッドを呼び出してみましょう。
jshell> hi()
Hi!
引数のあるメソッド
1. greetingメソッドとまったく同じく、"Hello "に続いて受け取った引数を表示するメソッドを`void salutation(String person)に続けて宣言してみましょう。
salutationもgreetingと同じく挨拶という意味です。
jshell> void salutation(String person) { System.out.println("Hello " + person);}
| 次を作成しました: メソッド salutation(String)
jshell> salutation("kis")
Hello kis
2. 引数として数値を受け取って、その回数だけ「Hello」と表示するメソッドを宣言してみましょう。hellohello(1)
として呼び出すと「Hello」、hellohello(2)
として呼び出すと「hellohello」が表示されます。
jshell> void hellohello(int count) { System.out.println("hello".repeat(count));}
| 次を作成しました: メソッド hellohello(int)
jshell> hellohello(1)
hello
jshell> hellohello(2)
hellohello
3. hellohello(3)
として呼び出して動きを確認してみましょう。
jshell> hellohello(3)
hellohellohello
戻り値のあるメソッド
1. 与えられた数字を2倍するメソッドを int dbl(int n)
から始めて宣言してみましょう。(doubleは「予約語」となっていてメソッド名に使えません)
jshell> int dbl(int n) { return n * 2;}
| 次を作成しました: メソッド dbl(int)
2. 宣言したメソッドdbl
を呼び出してみましょう。
jshell> dbl(3)
$10 ==> 6
jshell> dbl(5)
$11 ==> 10
3. 与えられた数字を3倍するメソッドtriple
を宣言して呼び出してみましょう。
jshell> int triple(int n) { return n * 3;}
| 次を作成しました: メソッド triple(int)
jshell> triple(3)
$13 ==> 9
jshell> triple(5)
$14 ==> 15
4. 与えられた文字列を2回繰り返すメソッドを宣言して呼び出してみましょう。
jshell> String twice(String s) { return s.repeat(2);}
| 次を作成しました: メソッド twice(String)
jshell> twice("Hello")
$16 ==> "HelloHello"
5. 与えられた2つの整数のうち大きいほうを返すメソッドmax2
を宣言してみましょう。条件演算子を使います。
jshell> int max2(int n, int m) { return n > m ? n : m;}
| 次を作成しました: メソッド max2(int,int)
jshell> max2(5, 3)
$18 ==> 5
jshell> max2(1, 4)
$19 ==> 4
6. 与えられた3つの整数のうち一番大きい数値を返すメソッドmax3
を宣言してみましょう。
jshell> int max3(int n, int m, int l) { return max2(n, max2(m, l));}
| 次を作成しました: メソッド max3(int,int,int)
jshell> max3(1, 4, 5)
$21 ==> 5
jshell> max3(5, 1, 4)
$22 ==> 5
jshell> max3(4, 5, 1)
$23 ==> 5
1. 「(名前)さんの平均点は(平均)点です」と表示するshowResult
メソッドをStudent
レコードに用意してみましょう。
record Student(String name, int englishScore, int mathScore){
int average() {
return (this.englishScore() + this.mathScore()) / 2;
}
void showResult() {
System.out.println("%sさんの平均点は%d点です".formatted(name(), average()));
}
}
1. 次のメソッドをラムダ式で表してみましょう。
boolean check(String s) {
return s.contains("y");
}
s -> s.contains("y")
2. 次のメソッドをラムダ式で表してみましょう。
void print(String s) {
System.out.println(s);
}
s -> System.out.println(s);
3. 次のラムダ式をupper
という名前のメソッドにしてみましょう。引数と戻り値の型はどちらもString
です。
s -> s.toUpperCase()
String upper(String s) {
return s.toUpperCase();
}
4. 次のラムダ式をemptyという名前のメソッドにしてみましょう。引数の型はString、戻り値の型はbooleanです。
s -> s.isEmpty()
boolean empty(String s) {
return s.isEmpty();
}
メソッド参照
1. 次のコードをメソッド参照を使って書き換えてみましょう
IntStream.of(nums).mapToObj(n -> "*".repeat(n)).toList()
IntStream.of(nums).mapToObj("*"::repeat).toList()
1. 次のラムダ式をメソッド参照を使って書き換えましょう
names.stream().map(s -> s.toUpperCase()).toList()
names.stream().map(String::toUpperCase).toList()
2. 次のラムダ式をメソッド参照を使って書き換えましょう
names.stream().map(s -> "%sさん".formatted(s)).toList()
names.stream().map("%sさん"::formatted).toList()
3. メソッド参照をラムダ式を使って書き換えましょう
names.stream().map(String::toLowerCase).toList()
names.stream().map(s -> s.toLowerCase()).toList()
メソッド使いこなし
メソッド呼び出しの組み合わせ
変数を使ってメソッド呼び出しの組み合わせを分解する
1. "three times".repeat("abc".length())
を変数を使って分解してみましょう。
var length = "abc".length();
"three times".repeat(length);
再帰とスタック
再帰によるループ
1. 次のforループでの処理を再帰に書き換えてみましょう。
for (int i = 3; i > 0; i--) {
System.out.println(i);
}
次のようになります。
public class ExRecLoop {
public static void main(String[] args) {
loop(3);
}
static void loop(int i) {
if (i <= 0) {
return;
}
System.out.println(i);
loop(i - 1);
}
}