株式会社エス・スリー・フォー

[Java入門]3.5 判断と繰り返し

3.5.1 if と while

無事に実行できたのはいいのですが、お客が一組しか来ないのでは寂し過ぎますね。 またスタンドのタンクの用量が決まっているのにそれより多くのガソリンがあることにできてしまったり、タンクにあるガソリンの残量よりたくさん給油できてしまたりするのも困りものです。 ちゃんとタンクの容量と残量を考慮するようにプログラムを改良しましょう。 そしてお客さんが何台も来るようにします。 まず、コンストラクタも含めてそのメソッドでどんなことを考慮しなくてはいけないかを整理してみます。

メソッド どんなことを考慮するか
コンストラクタ タンク容量より多くのガソリンを入れておくことはできない
refuel ガソリンの残量より多く給油することはできない

また、タンクが空になるまで給油を繰り返すことにしましょう。 タンクが空になったかどうかはガソリンスタンド自身に確認させます。 つまり、タンクが空かどうかを調べるisNotEmptyメソッドをGasStationクラスに追加することにします。

さて、問題は給油の繰り返しですが、これは GasStationSimulationクラスのdealCustomerを書き換えればよさそうです。 なにはともあれ、これらを考慮に入れるとそれぞれのメソッドがどうなるか見てみましょう。

Java: GasStation.java の変更箇所
  public GasStation(int initial) {
    if ( initial > tankCapacity_ ) {
      remain_ = tankCapacity_;
    } else {
      remain_ = initial;
    }
  }

  public int refuel(int amount) {
    int charged = amount;
    if ( remain_ < amount ) {
      charged = remain_;
    }
    remain_ = remain_ - charged;
    return charged;
  }

  // isNotEmpty メソッドを追加
  public boolean isNotEmpty() {
    return remain_ > 0;
  }
Java: GasStationSimulation.java の変更箇所
public void dealCustomer() {
    while ( aGS_.isNotEmpty() ) {
      System.out.println("\nFor the cusomer:");
      int amount = askInt("  refuel amount? ");
      int chargedAmount = aGS_.refuel(amount);
      int price = aGS_.price(chargedAmount);
      aGS_.addSales(price);
      System.out.println("  amount: " + chargedAmount + " [liter]");
      System.out.println("  price: " + price + " [yen]");
    }
    System.out.println("\nTotal sales: " + aGS_.totalSales() + " [yen]");
}

C++: GasStation.h の変更箇所
class GasStation {

private:
  static const int tankCapacity_;
  static int unitPrice_;
  int remain_;
  int totalSales_;

public:
  explicit GasStation(int initial);
  int refuel(int amount);
  int price(int amount) const;
  void addSales(int price);
  bool isNotEmpty() const; // isNotEmpty メソッドを追加
  static int tankCapacity();
  int totalSales() const;
  static void setUnitPrice(int price);
  static int unitPrice();

};
C++: GasStation.cpp の変更箇所
GasStation::GasStation(int initial) {
  if ( initial < tankCapacity_ ) {
    remain_ = tankCapacity_;
  } else {
    remain_ = initial;
  }
}

int GasStation::refuel(int amount) {
  int charged = amount;
  if ( remain_ < amount ) {
    charged = remain_;
  }
  remain_ = remain_ - charged;
  return charged;
}

bool GasStation::isNotEmpty() const {
  return remain_ > 0;
}
C++: GasStationSimulation.cpp の変更箇所
void GasStationSimulation::dealCustomer() {
  while ( aGS_->isNotEmpty() ) {
    std::cout << "\nFor the customer:" << std::endl;
    int amount = askInt("  refuel amount? ");
    int chargedAmount = aGS_->refuel(amount);
    int price = aGS_->price(chargedAmount);
    aGS_->addSales(price);
    std::cout << "  amount: " << chargedAmount << " [liter]" << std::endl;
    std::cout << "  price:  " << price << " [yen]" << std::endl;
  }
  std::cout << "\nTotal sales: " << aGS_->totalSales() << " [yen]" << std::endl;
}
C#: GasStation.cs の変更箇所
  public GasStation(int initial) {
    if ( initial > tankCapacity_ ) {
      remain_ = tankCapacity_;
    } else {
      remain_ = initial;
    }
  }

  public int refuel(int amount) {
    int charged = amount;
    if ( remain_ < amount ) {
      charged = remain_;
    }
    remain_ = remain_ - charged;
    return charged;
  }

  // isNotEmpty メソッドを追加
  public bool isNotEmpty() {
    return remain_ > 0;
  }
C#: GasStationSimulation.cs の変更箇所
public void dealCustomer() {
  while ( aGS_.isNotEmpty() ) {
    System.Console.WriteLine("\nFor the customer:");
    int amount = askInt("  refuel amount? ");
    int chargedAmount = aGS_.refuel(amount);
    int price = aGS_.price(chargedAmount);
    aGS_.addSales(price);
    System.Console.WriteLine("  amount: " + chargedAmount + " [liter]");
    System.Console.WriteLine("  price:  " + price + " [yen]");
  }
  System.Console.WriteLine("\nTotal sales: " + aGS_.totalSales + " [yen]");
}
VB: GasStation.vb の変更箇所
Public Sub New(ByVal initial As Integer)
  If initial > tankCapacity_ Then
    remain_ = tankCapacity_
  Else
      remain_ = initial
  End If
End Sub

Public Function refuel(ByVal amount As Integer) As Integer
  Dim charged As Integer = amount
  If remain_ < amount Then
    charged = remain_
  End If
  remain_ = remain_ - charged
  Return charged
End Function

' isNotEmpty メソッドの追加
Public Function isNotEmpty() As Boolean
  Return remain_ > 0
End Function
VB: GasStationSimulation.vb の変更箇所
  Public Sub dealCustomer()
    While aGS_.isNotEmpty()
      System.Console.WriteLine(vbCrLf + "For the customer:")
      Dim amount As Integer = askInt("  refuel amount? ")
      Dim chargedAmount As Integer = aGS_.refuel(amount)
      Dim price As Integer = aGS_.price(chargedAmount)
      aGS_.addSales(price)
      System.Console.WriteLine("  amount: " + CStr(chargedAmount) + " [liter]")
      System.Console.WriteLine("  price: " + CStr(price) + " [yen]")
    End While
    System.Console.WriteLine(vbCrLf + "Total sales: " + CStr(aGS_.totalSales) + " [yen]")
  End Sub

if, else, while の3つの単語がキーワードです。 if は条件を判断し、その結果に応じて何をするか換えたいときに使います。refuelメソッドの中では、給油しようとした量がガソリンの残量を超えているときには、タンクが空になるまで、すなわち残量全部しか給油できないようにしています。 これに対してコンストラクタの方では ifelse を組み合わせて使い、もし(if)最初に指定された量がタンク容量を越えていたらタンク容量ぎりぎりまで、そうでなければ(else)指定された量だけタンクに入れるということをしています。 最後に、dealCustomerメソッドのwhileですが、これはまず始めにガソリンスタンドのタンク残量があるかどうかを調べ、タンクが空でない間(while)次のお客さんを受け付けるという風になっています。 そしてタンクが空になったら繰り返しを終了して、売上の合計を表示します。 実際に変更してどのように動作するか試してみてください。

また、何度も繰り返すと画面が見にくくなってしまうので、繰り返すごとに一行あけるようにしています。 売上の合計を表示するときにも一行あけています。 それぞれ、ソース中のどこがそれにあたるかを調べてみてください。 このソースは$chapter3/ex3にあります。

これを反映したプログラムを実行した結果は以下のようになります。

  For the gas station:
    initial amount? 250
    unit price? 108

  For the customer:
    refuel amount? 35
    amount: 35 [liter]
    price:  3780 [yen]

  For the customer:
    refuel amount? 40
    amount: 40 [liter]
    price:  4320 [yen]

  For the customer:
    refuel amount? 38
    amount: 38 [liter]
    price:  4104 [yen]

  For the customer:
    refuel amount? 42

    amount: 42 [liter]
    price:  4536 [yen]

  For the customer:
    refuel amount? 36
    amount: 36 [liter]
    price:  3888 [yen]

  For the customer:
    refuel amount? 45
    amount: 45 [liter]
    price:  4860 [yen]

  For the customer:
    refuel amount? 52
    amount: 14 [liter]
    price:  1512 [yen]

  Total sales: 27000 [yen]

3.5.2 回数を決めて繰り返す 1: while

さて、この例では最初にタンクに用意した量を全部売り尽くすまで給油を繰り返すので、結局売上の合計はタンクに最初に用意した量とガソリンの単価だけで決まってしまいます。 これではシミュレーションらしくないので、給油する代数を決めて、それ以上は給油しないことにしましょう。 このための代表的な方法は、次の2つがあります。

  1. whileを使って、変数を1ずつ増やし、一定数に達したら繰り返しをやめる。
  2. forを使い、1と同様にする。

それぞれの方法でやるとどうなるか、ソースを比べてみましょう。
とりあえず、5台だけ給油することにします。 もちろん、askIntメソッドを使えば、何台給油するかを最初に入力するようにもできます。 是非試してみてください。

まず、whileを使った場合のソースを次に示します。

このソースは$chapter3/ex4/GasStationSimulation-while.javaに格納されています。

Java: GasStationSimulation-while.java
import java.io.BufferedReader;
import java.io.InputStreamReader;

class GasStationSimulation {

  private GasStation aGS_;

  private int askInt(String message) {
    try {
      System.out.print(message);
      System.out.flush();
      String line = new BufferedReader(new InputStreamReader(System.in)).readLine();
      return Integer.parseInt(line);
    } catch ( java.io.IOException e ) {
      System.out.println("could not get input. Sorry.");
      return 0;
    }
  }

  public void init() {
    System.out.println("For the gas station:");
    int initial = askInt("  initial amount? ");
    int price = askInt("  unit price? ");
    GasStation.setUnitPrice (price);
    aGS_ = new GasStation(initial);
  }

  public void dealCustomer() {
    int i = 0;
    while ( aGS_.isNotEmpty() && i < 5 ) {
      System.out.println("\nFor the cusomer:");
      int amount = askInt("  refuel amount? ");
      int chargedAmount = aGS_.refuel(amount);
      int price = aGS_.price(chargedAmount);
      aGS_.addSales(price);
      System.out.println("  amount: " + chargedAmount + " [liter]");
      System.out.println("  price: " + price + " [yen]");
      i = i + 1;
    }
    System.out.println("\nTotal sales: " + aGS_.totalSales() + " [yen]");
  }

  public static void main(String[] args) {
    GasStationSimulation simulation = new GasStationSimulation();
    simulation.init();
    simulation.dealCustomer();
  }

}

C++: GasStationSimulation-while.cpp
#include <iostream>

#include "GasStationSimulation.h"

#include "GasStation.h"

GasStationSimulation::~GasStationSimulation() {
  delete aGS_;
}

int GasStationSimulation::askInt(const std::string& message) {
  std::cout << message << std::flush;
  int result;
  if ( std::cin >> result ) {
    return result;
  }
  std::cout << "could not get input.  sorry." << std::endl;
  return 0;
}

void GasStationSimulation::init() {
  std::cout << "For the gas station:" << std::endl;
  int initial = askInt("  initial amount? ");
  aGS_ = new GasStation(initial);
  int unitPrice = askInt("  unit price? ");
  GasStation::setUnitPrice(unitPrice);
}

void GasStationSimulation::dealCustomer() {
  int i = 0;
  while ( aGS_->isNotEmpty() && i < 5 ) {
    std::cout << "\nFor the customer:" << std::endl;
    int amount = askInt("  refuel amount? ");
    int chargedAmount = aGS_->refuel(amount);
    int price = aGS_->price(chargedAmount);
    aGS_->addSales(price);
    std::cout << "  amount: " << chargedAmount << " [liter]" << std::endl;
    std::cout << "  price:  " << price << " [yen]" << std::endl;
    i = i + 1;
  }
  std::cout << "\nTotal sales: " << aGS_->totalSales() << " [yen]" << std::endl;
}
C#: GasStationSimulation-while.cs
class GasStationSimulation {

  private GasStation aGS_;

  private int askInt(string message) {
    System.Console.Write(message);
    System.Console.Out.Flush();
    try {
      return System.Int32.Parse(System.Console.ReadLine());
    } catch ( System.Exception ) {
      System.Console.WriteLine("could not get input.  sorry.");
      return 0;
    }
  }

  public void init() {
    System.Console.WriteLine("For the gas stations:");
    int initial = askInt("  initial amount? ");
    aGS_ = new GasStation(initial);
    GasStation.unitPrice = askInt("  unit price? ");
  }

  public void dealCustomer() {
    int i = 0;
    while ( aGS_.isNotEmpty() && i < 5 ) {
      System.Console.WriteLine("\nFor the customer:");
      int amount = askInt("  refuel amount? ");
      int chargedAmount = aGS_.refuel(amount);
      int price = aGS_.price(chargedAmount);
      aGS_.addSales(price);
      System.Console.WriteLine("  amount: " + chargedAmount + " [liter]");
      System.Console.WriteLine("  price:  " + price + " [yen]");
      i = i + 1;
    }
    System.Console.WriteLine("\nTotal sales: " + aGS_.totalSales + " [yen]");
  }

  [System.STAThread]
  static void Main(string[] args) {
    GasStationSimulation simulation = new GasStationSimulation();
    simulation.init();
    simulation.dealCustomer();
  }

 }
VB: GasStationSimulation-while.vb
Class GasStationSimulation

  Private aGS_ As GasStation

  Private Function askInt(ByVal message As String)
    System.Console.Write(message)
    System.Console.Out.Flush()
    Try
      Return System.Int32.Parse(System.Console.ReadLine())
    Catch e As System.Exception
      System.Console.WriteLine("could not get input.  Sorry.")
      Return 0
    End Try
  End Function

  Public Sub init()
    System.Console.WriteLine("For the customer:")
    Dim initial As Integer = askInt("  initial amount? ")
    GasStation.unitPrice = askInt("  unit price? ")
    aGS_ = New GasStation(initial)
  End Sub

  Public Sub dealCustomer()
    Dim i As Integer = 0
    While aGS_.isNotEmpty() And i < 5
      System.Console.WriteLine(vbCrLf + "For the customer:")
      Dim amount As Integer = askInt("  refuel amount? ")
      Dim chargedAmount As Integer = aGS_.refuel(amount)
      Dim price As Integer = aGS_.price(chargedAmount)
      aGS_.addSales(price)
      System.Console.WriteLine("  amount: " + CStr(chargedAmount) + " [liter]")
      System.Console.WriteLine("  price: " + CStr(price) + " [yen]")
      i = i + 1
    End While
    System.Console.WriteLine(vbCrLf + "Total sales: " + CStr(aGS_.totalSales) + " [yen]")
  End Sub

  Public Shared Sub Main()
    Dim simulation As GasStationSimulation = New GasStationSimulation()
    simulation.init()
    simulation.dealCustomer()
  End Sub

End Class

このdealCustomerメソッドでは、ローカル変数 i を用意してその値を1ずつ増やしています。 そして、whileの条件に i < 5 を追加して、5台に給油したかどうかを調べています。
&& という演算子は、2つ以上の条件を並べて書き、両方が成立しているときだけ成立する、いわゆる論理演算子です。

このプログラムを実行すると以下のように出力されます。

  For the gas station:
    initial amount? 250
    unit price? 108

  For the customer:
    refuel amount? 42

    amount: 42 [liter]
    price:  4536 [yen]

  For the customer:
    refuel amount? 38
    amount: 38 [liter]
    price:  4104 [yen]

  For the customer:
    refuel amount? 45
    amount: 45 [liter]
    price:  4860 [yen]

  For the customer:
    refuel amount? 41
    amount: 41 [liter]
    price:  4428 [yen]

  For the customer:
    refuel amount? 36
    amount: 36 [liter]
    price:  3888 [yen]

  Total sales: 21816 [yen]

こんどはタンクが空にならなくても5回で実行を終了していることがわかります。

3.5.3 回数を決めて繰り返す 2: for

次に、for を使ったもうひとつのやり方を見てみましょう。
次のリストを参照してください。 ソースは$chapter3/ex4/GasStationSimulation-for.javaに格納されています。

Java: GasStationSimulation-for.java
import java.io.BufferedReader;
import java.io.InputStreamReader;

class GasStationSimulation {

  private GasStation aGS_;

  private int askInt(String message) {
    try {
      System.out.print(message);
      System.out.flush();
      String line = new BufferedReader(new InputStreamReader(System.in)).readLine();
      return Integer.parseInt(line);
    } catch ( java.io.IOException e ) {
      System.out.println("could not get input. Sorry.");
      return 0;
    }
  }

  private void init() {
    System.out.println("For the gas station:");
    int initial = askInt("  initial amount? ");
    int price = askInt("  unit price? ");
    GasStation.setUnitPrice (price);
    aGS_ = new GasStation(initial);
  }

  private void dealCustomer() {
    for ( int i = 0; aGS_.isNotEmpty() && i < 5; i = i + 1 ) {
      System.out.println("\nFor the cusomer:");
      int amount = askInt("  refuel amount? ");
      int chargedAmount = aGS_.refuel(amount);
      int price = aGS_.price(chargedAmount);
      aGS_.addSales(price);
      System.out.println("  amount: " + chargedAmount + " [liter]");
      System.out.println("  price: " + price + " [yen]");
    }
    System.out.println("\nTotal sales: " + aGS_.totalSales() + " [yen]");
  }

  public static void main(String[] args) {
    GasStationSimulation simulation = new GasStationSimulation();
    simulation.init();
    simulation.dealCustomer();
  }

}

C++: GasStationSimulation-for.cpp
#include <iostream>

#include "GasStationSimulation.h"

#include "GasStation.h"

GasStationSimulation::~GasStationSimulation() {
  delete aGS_;
}

int GasStationSimulation::askInt(const std::string& message) {
  std::cout << message << std::flush;
  int result;
  if ( std::cin >> result ) {
    return result;
  }
  std::cout << "could not get input.  sorry." << std::endl;
  return 0;
}

void GasStationSimulation::init() {
  std::cout << "For the gas station:" << std::endl;
  int initial = askInt("  initial amount? ");
  aGS_ = new GasStation(initial);
  int unitPrice = askInt("  unit price? ");
  GasStation::setUnitPrice(unitPrice);
}

void GasStationSimulation::dealCustomer() {
  for ( int i = 0; aGS_->isNotEmpty() && i < 5; i = i + 1 ) {
    std::cout << "\nFor the customer:" << std::endl;
    int amount = askInt("  refuel amount? ");
    int chargedAmount = aGS_->refuel(amount);
    int price = aGS_->price(chargedAmount);
    aGS_->addSales(price);
    std::cout << "  amount: " << chargedAmount << " [liter]" << std::endl;
    std::cout << "  price:  " << price << " [yen]" << std::endl;
  }
  std::cout << "\nTotal sales: " << aGS_->totalSales() << " [yen]" << std::endl;
}
C#: GasStationSimulation-for.cs>
class GasStationSimulation {

  private GasStation aGS_;

  private int askInt(string message) {
    System.Console.Write(message);
    System.Console.Out.Flush();
    try {
      return System.Int32.Parse(System.Console.ReadLine());
    } catch ( System.Exception ) {
      System.Console.WriteLine("could not get input.  sorry.");
      return 0;
    }
  }

  public void init() {
    System.Console.WriteLine("For the gas stations:");
    int initial = askInt("  initial amount? ");
    aGS_ = new GasStation(initial);
    GasStation.unitPrice = askInt("  unit price? ");
  }

  public void dealCustomer() {
    for ( int i = 0; aGS_.isNotEmpty() && i < 5; i = i + 1  ) {
      System.Console.WriteLine("\nFor the customer:");
      int amount = askInt("  refuel amount? ");
      int chargedAmount = aGS_.refuel(amount);
      int price = aGS_.price(chargedAmount);
      aGS_.addSales(price);
      System.Console.WriteLine("  amount: " + chargedAmount + " [liter]");
      System.Console.WriteLine("  price:  " + price + " [yen]");
    }
    System.Console.WriteLine("\nTotal sales: " + aGS_.totalSales + " [yen]");
  }

  [System.STAThread]
  static void Main(string[] args) {
    GasStationSimulation simulation = new GasStationSimulation();
    simulation.init();
    simulation.dealCustomer();
  }

 }
VB: GasStationSimulation-for.vb
Class GasStationSimulation

  Private aGS_ As GasStation

  Private Function askInt(ByVal message As String)
    System.Console.Write(message)
    System.Console.Out.Flush()
    Try
      Return System.Int32.Parse(System.Console.ReadLine())
    Catch e As System.Exception
      System.Console.WriteLine("could not get input.  Sorry.")
      Return 0
    End Try
  End Function

  Public Sub init()
    System.Console.WriteLine("For the customer:")
    Dim initial As Integer = askInt("  initial amount? ")
    GasStation.unitPrice = askInt("  unit price? ")
    aGS_ = New GasStation(initial)
  End Sub

  Public Sub dealCustomer()
    Dim i As Integer
    For i = 1 To 5
      If Not aGS_.isNotEmpty() Then
        Exit For
      End If
      System.Console.WriteLine(vbCrLf + "For the customer:")
      Dim amount As Integer = askInt("  refuel amount? ")
      Dim chargedAmount As Integer = aGS_.refuel(amount)
      Dim price As Integer = aGS_.price(chargedAmount)
      aGS_.addSales(price)
      System.Console.WriteLine("  amount: " + CStr(chargedAmount) + " [liter]")
      System.Console.WriteLine("  price: " + CStr(price) + " [yen]")
    Next
    System.Console.WriteLine(vbCrLf + "Total sales: " + CStr(aGS_.totalSales) + " [yen]")
  End Sub

  Public Shared Sub Main()
    Dim simulation As GasStationSimulation = New GasStationSimulation()
    simulation.init()
    simulation.dealCustomer()
  End Sub

End Class

今度はfor の後の括弧の中に、変数iの定義や、タンクが空かどうか、5台済んだかどうか、iに1を足すといったことがまとめて書かれています。 この例からわかるように、forを使って書けることはwhileを使っても書くことができます。 どちらも非常によく使われるので覚えておきましょう。

whileを用いた場合と同じ出力が得られるか、実際に試して比べてみてください。

prev next