progate memo 3

Lv.3 メソッドとクラスを学ぼう
今まで：mainメソッドだけに処理を記述してきた
このレッスン：メソッドに切り分けていく

メソッドとは、何らかの処理を割り当てて、まとめた部品。Javaのファイルを実行すると、自動的にmainメソッドが実行される。
mainメソッドの処理をメソッドに切り分けると、mainメソッドが各メソッドに指示を出し、各メソッドが個々の処理を実行するという構造になる。
処理をメソッドに切り分けることで、それぞれのメソッドに役割分担をさせることが可能になる。
→一つのメソッドで複数の処理を書く酔いも処理の内容やまとまりがわかりやすい。

下のコードでは、helloというメソッドを定義し、mainメソッドでhelloメソッドを呼び出している。

class Main{
  public static void main(String[]args){　　…1:mainメソッドが呼ばれる
    hello();　…２：mainメソッドの中で、helloメソッドが呼ばれる
    }
  public static void hello(){
    System.out.println("Hello World");　
      …3：helloメソッドの中で、　System.out.println（"Hello World"）が実行される
    }
   }

メソッドについて詳しく学んでいく。
まずはメソッドの定義。「public static void」の部分はまだ定型。
ブロック（{}で囲まれた部分）の中に、そのメソッドが行う処理を記述する。メソッドの名前は好きに付けることができる。

public static void メソッド名(){
  実行する処理；
　}

メソッドはクラスの中に定義。下の具体例では、
helloメソッドはMainクラスのブロック（{}）の中に定義されている。
このようにクラスの中に定義しないとエラーになるので中が必要。

class Main{...ここからMainクラスのブロックがスタート
  public static void main(String[]args){
  public static void hello(){　…クラスの中でメソッドを定義
    System.out.println("Hello World");…上の続き
  }
}…Mainクラスのブロック終わり

メソッドを呼び出すためには、メソッド名()とするだけ。()を忘れないように！
class Main {
  public static void main(String[] args) {
    printData();// printDataメソッドを呼び出す。
  }
   public static void printData(){
   System.out.println("私の名前はKate Jonesです");  // printDataメソッドを定義している。
   }
}
引数（ひきすう）とはメソッドに与える追加情報のようなもの。
メソッドを呼び出すときに、一緒に引数を別のメソッドに渡すと、
渡された方のメソッドの中でその値を利用することができる。 

メソッドに引数を渡すには、まず引数を受け取れるメソッドを定義する必要がある。
そのためには、メソッドの定義部分で、引数を受け取るための箱となる変数（仮引数（かりひきすう））を指定する。 
下のコードのように、「public static void メソッド名()」の()に仮引数（変数定義と同様に、データ型も）を指定する必要あり。 

public static void メソッド名（引数のデータ型　引数を受け取る変数名）{
実行する処理；
}
public static void hello(String name){
}

メソッドに引数を渡すには、
1.メソッド名(引数)としてメソッドを呼び出す。
2.渡された引数は、メソッドの仮引数で指定した変数（この場合name）に代入され、
3.その変数はメソッドの処理の中で用いることができる。 


class Main{
  public static void main(String[]args{
    hello("Bob")
 }
  public static void hello(String name){

    System.out.println(name + "さんこんにちは")；

ーーー実践ーーー
class Main {
  public static void main(String[] args) {
    printData("Kate Jones"); // 引数に「Kate Jones」を渡す
    printData("John Christopher Smith"); // 引数に「John Christopher Smith」を渡す
  }
  public static void printData(String name) {  // 引数を受け取る
    System.out.println("私の名前は" + name + "です");  // 「私の名前は◯◯です」と出力される
  }
}
出力
私の名前はKate Jonesです
私の名前はJohn Christopher Smithです
ーーーーーー

引数は複数渡すこともできる。メソッドが複数の引数を受け取るためには
仮引数をコンマ（,）で区切って定義する。
異なるデータ型の引数を複数受け取ることもでき、引数を受け取る順番も任意に決めることができる。
*引数は左から順番に「第1引数、第2引数・・・」というように呼ぶ。

public static void メソッド名(データ型　変数名1,データ型　変数名2){
　実行する処理；
}

下のコードでは、引数と仮引数が（ピザ、コーラ＝String item　  3000、150がint price）繋がっている。
class Main{
  public static void main(String[] args){
    printPrice("ピザ", 3000);…引数
    printPrice("コーラ", 150);
}
  public static void printPrice(String item, int price){…仮引数
    System.out.println(item + ”は”　+ price + "円です");

ピザは３０００円です
コーラは１５０円です
＊仮引数は任意に順番を決められるが、メソッドを呼び出すときは、仮引数と引数の順番は揃える必要がある

ーーー実践ーーー
class Main {
  public static void main(String[] args) {
    printData("Kate Jones",27); // それぞれ年齢に関する引数を追加
    printData("John Christopher Smith",65);
  }

  public static void printData(String name, int age) {  // 年齢に関する引数を受け取れるようにする
    System.out.println("私の名前は" + name + "です");
    System.out.println("年齢は"+age+"歳です");
    
出力
私の名前はKate Jonesです
年齢は27歳です
私の名前はJohn Christopher Smithです
年齢は65歳です
ーーーーーー

メソッドの処理結果を、メソッドの呼び出し元で使いたい場合がある。
このようなときは、メソッドが戻り値（もどりち）を返すようにする。 
メソッドを工場に例えると、工場（メソッド）は、発注者（mainメソッド）から材料（引数）を受け取り、
決められた加工（処理）を行って完成品を発注者に返す。この完成品にあたるのが戻り値。

メソッドの中でreturnを使うと、returnの値をメソッドの呼び出し元に返すことができる。 
また、戻り値があるメソッドは、戻り値のデータ型を指定。
＊ここまで定型だった「public static void」のvoidの部分で指定。
下の図のaddメソッドは、戻り値が整数なので「public static int ...」となる。

public static 戻り値のデータ型　メソッド名(引数){
  return 戻り値;
}

public static int add(int a, int b){　…intは戻り値のデータ型
  return a + b; …returnは呼び出し元に値を返す役割、a+bは戻り値
}

戻り値がある場合、メソッドの呼び出し部分がそのまま値に変わる。
よって、下のようにメソッドの呼び出し部分を、変数に代入することができる。 

public static void main(String[] args){
  int total = add(7, 5);
  System.out.println(total);
}
public static int add(int a, int b){　//メソッドの呼び出し部分がそのまま値に変わる。
  return a + b;　…７＋５の結果が戻り値になる。
}
出力　１２

これまで定型だったvoidとはは戻り値がない、という意味。戻り値のない（returnがない）メソッドには、voidを指定する。

class Main {
  public static void main(String[] args) {    
    String name = fullName("Kate", "Jones"); // fullNameメソッドの結果を変数nameに代入
    printData(name, 27);    // printDataの引数を書き換えた
    printData("John Christopher Smith", 65);
  }
  public static void printData(String name, int age) {
    System.out.println("私の名前は" + name + "です");
    System.out.println("年齢は" + age + "歳です");
  }
  public static String fullName(String firstName, String lastName) {
    return firstName + " " + lastName;　  // fullNameメソッドを定義
  }  
}

出力
私の名前はKate Jonesです
年齢は27歳です
私の名前はJohn Christopher Smithです
年齢は65歳です。

出力の流れ
 1.fullNameメソッドの定義
  public static String fullName(String firstName, String lastName){
  return firstName + " " + lastName;

 2.fullNameメソッドの結果を変数nameに代入
  String name = fullName("Kate", "Jones");

 3.printDataの引数を参照（String name -> name　につながる）
  printData(name, 27);

 4.このname が最終的な出力につながる。
  public static void printData(String name, int age) {
    System.out.println("私の名前は" + name + "です");
    System.out.println("年齢は" + age + "歳です");

fullNameメソッドを作ったが、いまのままでは、
ミドルネームを持つ「John Christopher Smith」さんはfullNameメソッドが使えない。


同名のメソッドは原則として定義できない。
なぜなら同じメソッドが複数存在すると、メソッドを呼び出したときにどのメソッドを用いればいいのか、
コンピュータがわからなくなってしまうため。
ただ、引数の型や個数が違う場合は同名のメソッドを定義できる。
同名のメソッドがあっても、引数が違えばどれを呼べばいいのかコンピュータが判断できるため。
このように同名のメソッドを定義することを"オーバーロード"と言う。

ex.
public static void main(String[]args){
  hello(); ...引数のないHelloメソッド
  hello("Bob"); ...String型の引数を持るHelloメソッド
}
public static void hello(){
  System.out.println("こんにちは世界");
}
public static void hello(String name){
  System.out.println("こんにちは" + name + "さん");
}

結果： 
こんにちは世界
こんにちはBobさん

class Main {
  public static void main(String[] args) {
    printData(fullName("Kate", "Jones"), 27);
    
    // fullNameメソッドを用いて、printDataの引数を書き換えてください
    printData(fullName("John", "Christopher", "Smith"), 65);
  }

  public static void printData(String name, int age) {
    System.out.println("私の名前は" + name + "です");
    System.out.println("年齢は" + age + "歳です");
  }

  public static String fullName(String firstName, String lastName) {
    return firstName + " " + lastName;
  }
  
  // fullNameメソッドを定義してください
  public static String fullName(String firstName, String middleName, String lastName) {
    return firstName + " " + middleName + " " + lastName;
  }
}
---
私の名前はJohn Christopher Smithです
年齢は65歳です
---
1. fullNameメソッドを定義
  public static String fullName(String firstName, String middleName, String lastName) {
    return firstName + " " + middleName + " " + lastName;

2. fullNameメソッドを用いて、printDataの引数指定（上のメソッドの引数と、下の引数がつながる）
    printData(fullName("John", "Christopher", "Smith"), 65);
  }

3. 上のprintDataの引数(引数１ fullName　と　引数２ 65)　と　下の引数（引数１ name 引数2 age　）がつながる。 
  public static void printData(String name, int age) {
    System.out.println("私の名前は" + name + "です");
    System.out.println("年齢は" + age + "歳です");
  }


メソッドは、mainメソッド以外のメソッドから呼び出すことも可能。
プログラムの部品であるメソッドが、相互に助けあってプログラムを作る。

メソッドから他のメソッドを呼び出してみる。
averageメソッドは平均を求めるメソッドで、aとbの平均は「(a + b) / 2」で求められるが、
足し算の部分はaddメソッドを利用している。（(double)はキャストという型変換。） 

public static void main(String[] args){
  System.out.println(average(3,8));
}
public static double average(int a, int b){
  int total = add(a,b);
  return(double)total /2;
}
public static int add(int a, int b){
  return a + b;

---
結果　5．５
---
1.addメソッドの定義
public static int add(int a, int b){
  return a + b;

2.addというのは、上の定義通り足している結果を表す。それをtotalとする。
　　　total/2　をしたのを　戻り値として、次の処理に行く　　
public static double average(int a, int b){
  int total = add(a,b);
  return(double)total /2;

3.結局a、bの正体は３と８である。それを出力する。
  System.out.println(average(3,8));

ーーー

class Main {
  public static void main(String[] args) {
    printData(fullName("Kate", "Jones"), 27, 1.6, 50.0);
    printData(fullName("John", "Christopher", "Smith"), 65, 1.75, 80.0);
  }

  public static void printData(String name, int age, double height, double weight) {
    System.out.println("私の名前は" + name + "です");
    System.out.println("年齢は" + age + "歳です");
    System.out.println("身長は" + height + "mです");
    System.out.println("体重は" + weight + "kgです");
    
    // 変数bmiに、bmiメソッドを用いてBMIを代入してください
    double bmi = bmi(height, weight);
    
    // 変数bmiを用いて、「BMIは◯◯です」と出力してください
    System.out.println("BMIは" + bmi + "です");    
  }
  public static String fullName(String firstName, String lastName) {
    return firstName + " " + lastName;
  } 
  public static String fullName(String firstName, String middleName, String lastName) {
    return firstName + " " + middleName + " " + lastName;
  }
  // bmiメソッドを定義してください
  public static double bmi(double height, double weight) {
    return weight / height / height;
  }
  
}

-真偽値を返す
真偽値を返すメソッドを作って見る。真偽値のデータ型はbooleanなので、メソッド定義は以下のようになる。
＊isEvenメソッドは引数の値が偶数かどうかを調べ、偶数であればtrue、奇数であればfalseを返す。 

public static boolean isEven(int a){
  return a % 2 ==0 ...2で割った余りが０であればtrue

実際にisEvenメソッドを用いてみる。
publuc static void main(String[]args){
  int number = 9
  if (isEven(number)){
    System.out.println(number + "は偶数です");
  }else{
    System.out.println*number + "は奇数です");
  }
}
  public static boolean isEven(int a){
    return a % 2 ==0

結果：9は奇数です

class Main {
  public static void main(String[] args) {
    printData(fullName("Kate", "Jones"), 27, 1.6, 50.0);
    printData(fullName("John", "Christopher", "Smith"), 65, 1.75, 80.0);
  }
  public static void printData(String name, int age, double height, double weight) {
    System.out.println("私の名前は" + name + "です");
    System.out.println("年齢は" + age + "歳です");
    System.out.println("身長は" + height + "mです");
    System.out.println("体重は" + weight + "kgです");
    double bmi = bmi(height, weight);
    System.out.println("BMIは" + bmi + "です");
  
    if (isHealthy(bmi)){  // isHealthyメソッドの結果で条件分岐
      System.out.println("健康です");
    }else{
      System.out.println("健康ではありません"); 
    }        
  }
  public static String fullName(String firstName, String lastName) {
    return firstName + " " + lastName;
  }
  public static String fullName(String firstName, String middleName, String lastName) {
    return firstName + " " + middleName + " " + lastName;
  }
  public static double bmi(double height, double weight) {
    return weight / height / height;
  }
    public static boolean isHealthy(double bmi){// isHealthyメソッドを定義
    return  18.5<= bmi&&   bmi< 25.0;
  }  
}

結果
私の名前はKate Jonesです
年齢は27歳です身長は1.6mです
体重は50.0kgです
BMIは19.53125です健康です
私の名前はJohn Christopher Smithです
年齢は65歳です
身長は1.75mです体重は80.0kgです
BMIは26.122448979591837です
健康ではありません

●今までメソッドの分け方をやってきたがMainクラス内にメソッドが多くなってしまった。
これからはメソッドの切り分け方を学んでいく。
クラスは、メソッドという小さな部品をまとめる、より大きな部品。これまではmainメソッドと
同じクラス（Mainクラス）のメソッドを使ってきたが、他のクラスのメソッドを利用することも可能。

下の例には、MainクラスとPersonクラスの2つのクラスがあり、
MainクラスのmainメソッドでPerson.hello()としている。
このようにクラス名.メソッド名()とすることで、他のクラスのメソッドを呼び出すことができる。

//main.java
class Main {
  public static void main(String[]args){
    Person.hello();..."."でPersonクラスのhelloメソッドを呼び出す
  }

//Person.java
class Person{
  public static void hello(){
  System.out.println("Hello World");
 }
}
クラスの定義は「class クラス名」とする。また、クラス名の最初の文字は大文字にし、
ファイル名は「クラス名.java」としなければならない。
クラスの分割することのメリットは分割することで、例えばMainクラスは実行用のクラス、
Personクラスはロジックをまとめるクラスというような役割分担が明確になる。
次にMainクラスのmainメソッドから、Personクラスのメソッドを呼び出してみる。

//Main.java
class Main{
  public static void main(String[]args){
    String name = Person.fullName("Kate","Jones");...Personクラスのメソッドを呼び出し
    System.out.println(name);
  }
}
//Person.java
class Person{
  public static String fullName(String firstName, String lastName){
  return firstName + ""+ lastName;
}
}
Javaは、ファイルではなくクラスを実行する。
また実行時にmainメソッドが呼ばれる、
正確にはmainメソッドを持つクラスしか実行できない（mainメソッドのないクラスは、他クラスから呼び出して使う）。 
またクラス名に関係なく、実行時にはmainメソッドが呼ばれる
（Mainクラスだからmainメソッドが呼ばれる、というわけではないので注意）。

//Main.java
public class Main {
  public static void main(String[] args) {
    Person.printData(Person.fullName("Kate", "Jones"), 27, 1.6, 50.0);
    Person.printData(Person.fullName("John", "Christopher", "Smith"), 65, 1.75, 80.0);
  }    
}
//Person.java
class Person{// Personクラスを定義
  public static void printData(String name, int age, double height, double weight) {
    System.out.println("私の名前は" + name + "です");
    System.out.println("年齢は" + age + "歳です");
    System.out.println("身長は" + height + "mです");
    System.out.println("体重は" + weight + "kgです");

    double bmi = bmi(height, weight);
    System.out.println("BMIは" + bmi + "です");

    if (isHealthy(bmi)) {
      System.out.println("健康です");
    } else {
      System.out.println("健康ではありません");
    }
  }

●外部ライブラリ
Javaでは、他人が作ったクラスを利用することもできる。
このようなクラスを外部ライブラリと呼び、自分のプログラムに読み込むことで利用できるようになる。

外部ライブラリを自分のプログラムに読み込む（使えるようにする）には、importを用いる。
数学的なメソッドを持つMathというクラス（ライブラリ）を読み込むには、
class定義より上で「import java.lang.Math」とする。
「java.lang」の部分は、Mathクラスの場所を示しているという程度でよい。

//Main.java
import java.lang.Math; ...外部ライブラリを読み込む。
class Main{
 public static void main(String[]args){
....
  }
}
Mathクラスのmaxメソッドを使ってみる。
maxメソッドは、引数に渡した2つの数値の大きい方を返してくれるメソッド。
外部ライブラリをうまく活用すれば、自分で実装する手間が省けるので便利である。
演習では、引数の小数点以下を四捨五入して返すroundメソッドを使う。
これはdouble型の引数を渡し、Math.round(引数)のように使うことができる。

「java.lang.Math」はよく利用されるため、
実は特別にimportせずに自動で読み込まれるようになっている。
Mathクラス以外にも「java.lang.クラス名」となる外部ライブラリはすべて自動で読み込まれる。

//import java.lang.Math;...importしなくても使える
class Main{
  public static void main(String[]args){
    int max = Math.max(3,8); ...外部から読み込んだMathクラス。
  System.out.println("最大値は" + max + "です");
  }
}
これまではコンソールに値を「出力」してきたが、実はコンソールに値を「入力」し、
その値をプログラム内で使うこともできる。
コンソールへの入力を受け取るにはScannerというライブラリを用いる。
Scannerは「import java.util.Scanner」と読み込む。
ライブラリは、Googleで検索すれば使い方がわかるので覚える必要なし。 

import java.util.Scanner; ...外部ライブラリ「Scanner」を読み込む。
class Main{
  public static void main (String[]args){
...
 }
}
Scannerの使い方を見てみる。まずScannerを初期化しscannerという変数にいれている。
詳しくはまだ知らなくて大丈夫だが、Scannerではこの初期化したものを代入した変数を使ってメソッドを呼び出す。
scanner.next()とすると（＊Scanner.next()ではない）、コンソールに入力された文字列を受け取ることができる。

import java util.Scanner;
class Main{
  public static void main(String[]args){
    Scanner scanner = new Scanner(System.in); ...Scannerの初期化
    String name = scanner.next();　...文字列の入力を受け取る
  }
}

Scannerの処理の流れを下のコードから確認する。
scanner.next()が呼ばれると、一旦処理が中断しコンソールに値が入力されるのを待つ。
コンソールに入力された値をscanner.next()が受け取り、変数nameに代入している。
（図中のSystem.out.printは、改行せずに値を出力する命令です）

public static void main(String[]args){
  Scanner scanner = new Scanner(System.in);
  System.out.print("あなたの名前:");
  String name = scanner.next();...一旦処理を中断し、値が入力されたら次の処理に進む。↓
  
  System.out.println("あなたの名前は" +　name +"です");
  }
}
結果：
あなたの名前：にんじゃわんこ
あなたの名前はにんじゃわんこです

import java.util.Scanner;

class Main {
  public static void main (String[] args) {
    Scanner scanner = new Scanner(System.in);
    System.out.print("名前： ");
    String name = scanner.next();  // 変数nameを定義し、コンソールから文字列を受け取って代入する    
    System.out.println("こんにちは" + name + "さん");
  }
}
結果
名前：sibasaki
こんにちはsibasaki さん

Scannerを用いて、整数と小数を受け取る方法は以下のコード。
整数を受け取るメソッドはnextIntメソッド、小数を受け取るメソッドはnextDoubleメソッド。 

public static void main(String[]args){
  Scanner scanner = new Scanner(System.in);
  System.out.print("年齢:");
  int age = scanner.nextInt();...整数を受け取る
  System.out.print("体重:");
  double weight = scanner.nextDouble(); ...小数を受け取る
  System.out.println("あなたの年齢は"　+ age + "歳です" );
  System.out.println("あなたの体重は"　+ weight + "kgです" );
 }

-----実践ーーーーー
import java.util.Scanner;
class Main {
  public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    System.out.print("名前：");
    String firstName = scanner.next();
    System.out.print("名字：");
    String lastName = scanner.next();
    System.out.print("年齢：");
    int age = scanner.nextInt();
    System.out.print("身長(m)：");
    double height = scanner.nextDouble();
    System.out.print("体重(kg)：");
    double weight = scanner.nextDouble();
    printData(firstName, lastName, age, height, weight);
  }
  public static void printData(String firstName, String lastName, int age, double height, double weight) {
    System.out.println("名前は" + fullName(firstName, lastName) + "です");
    System.out.println("年齢は" + age + "歳です");
    if (age >= 20) {
      System.out.println("成年者です");
    } else {
      System.out.println("未成年者です");
    }
    System.out.println("身長は" + height + "mです");
    System.out.println("体重は" + weight + "kgです");
  }
  public static String fullName(String firstName, String lastName) {
    return firstName + " " + lastName;
  }
}