Learn Programming in Java


<<Previous | ToC | Next >>

Don't Get Too Creative

This is the last of four English programs you are translating to Java as a way to become familiar with the peculiarities of Java. Don't Make Unnecessary Changes (yet). If your browser has tabs or separate windows, open a new tab (or window) with this link to The Six Things in Java, so you can refer to it as often as needed. When this calculator works, you will be a Java programmer. You still need to learn about OOPS, but that's a way of organizing your code, not one of the essentials. Then you can be creative with our blessing 

The purpose of this assignment is to enlarge your comfort level in Java to include native Java input and exceptions. But fiirst we will start with a working Java program, the Calculator you did in English, translated to Java. The translation should be fairly straight-forward. The native Java input and exceptions are more challenging, so first get it working without them, then add them incrementally. You got this far, you can do this.

Simple Calculator

I may have told you "no math" up front, what gives with the calculator? Not to worry, the computer does the math. But instead you get to worry about reading keyboard input in the native Java manner (and coping nicely with typing errors) because my Zystem input methods don't read numbers with decimal points. It's good for you, you can't lean on my Zystem crutch forever. Well, you can, but other programmers will wonder about you. Anyway, later (perhaps tomorrow or next week, or else later today if you are in the summer program) you get to program exceptions properly.

The Calculator is the first "real" program you wrote in English, but it's much harder in Java, so we saved it for near the end. You could bring in your English program (or get it from the Done archive) to translate, but I wrote this before there was any English to work from, and it's pretty close. For a simple 4-function calculator we can do it as a simple loop:

while (true) {
  /// a. display the current result (initially =0)
  /// b. accept a command letter:
  /// c. if 'q' quit
  /// d. if 'c' clear
  /// e. accept a value
  /// f. if command is '+' add
  /// g. else if '-' subtract
  /// h. else if '*' multiply
  /// i. else if '/' divide
  /// j. otherwise print error message
  } // end of main loop
You should be able to write this whole program without any help, if you use the Zystem input methods you already know about. Try it now, before reading any farther.

Remember, you are working with an early version of this tutorial, so if it's not clear what to do, or why the Replit (or BlueJ) compiler doesn't like what you gave it, that's my fault, not yours. Summon a Mentor, and two things will happen:

1. Somebody will come and work with you to get past the problem.

2. I will make the documentation better -- maybe next week, more likely next term. We need your help. Really.

-- or use the "Ask" feature in Zoom.

What data type did you choose for your display value? If you chose "int" what happens when you input or calculate fractional numbers? Java has two data types that work with non-integer numbers, float and double, but nobody uses float any more, it was initially designed for computer hardware with limited memory and/or that ran double width numbers slower than single. The computer in your pocket (it's called a "smart phone") has a thousand times more computer memory than all the first-generation (model 704) super-computers IBM ever made put together, so that's no longer a problem. Most of the math hardware is "pipelined" so the extra time it takes to calculate the wider result is overlapped by other calculations and does not slow anything down most of the time. Because float and double are different internal formats, the programmers got lazy and programmed everything in double, so the hardware designers no longer do the arithmetic in the shorter format, they just convert everything to double, do the math, then convert the result back to float (if that's what you want).

Bottom line: you probably want to use double as the data type whenever your data could extend past a few million (seven decimal digits, or nine if integer) or involve fractions, like for your result and input values in this calculator. That almost never happens in the programs I write, so I mostly use integers for everything. One consequence is that I have no "safe" input routines ready for you to use, you must write your own. Like taking your vitamins, it builds strong healthy bones (in your code ;-)

You could build your calculator in the same Hello class we have been using all along, or else (if you are using Replit) go back to the NWAPW page and fork a new copy of my StartHere Repl (call it "Calculator" or some such). If you think you are ready to start making your own Java classes, you could just pop out to the top menu and create a new Repl, but it wouldn't have the Zystem class. Your calculator code will replace the familiar "Replace this line" (if you used mine) or else go in their main().

If you are using BlueJ, in the dashboard (the "StartHere" window with the yellow rectangles) right-click the blank space behind those rectangles, or else pull down the Edit menu, and choose "New Class". In the dialog that pops up, give it your class name, like "Calculator" (it must start with a capital letter), verify that it will be making a Java class (later versions of BlueJ have several irrelevant options) and hit OK. Then double-click the new yellow rectangle with your class name. BlueJ gives you is a green box outlining the class, with two yellow boxes for methods. I deleted both yellow boxes and in their place (in the white space inside the green box) made a single
public static void main() {

} // end of main

Just like in Hello. Notice that it made a new yellow box for you. This is where your calculator code will go, in the white space inside that yellow box.

You will declare your variables on the first few lines there, then put in our -- I mean your -- stub while loop and save it and make sure it compiles. You need to declare a char variable -- I called mine "optor" (short for "operator") but you can call yours anything you like, just when I talk about optor, you substitute your variable name.

OK, let's work on line (b), getting the operator input, for this first cut using Zystem.ReadLetter():

/// b. accept a command letter:
optor = Zystem.ReadLetter();
/// c. if 'q' quit
if (optor == 'q') return;
/// d. if 'c' clear
if (optor == 'c') {
  /// clear your result variable
  continue;} // back to the top of the loop

The user could type pretty much anything, and you (smart programmer that you are becoming) need to cope with it and do something reasonable and not too rude. Let's validate it:

if (optor != '+') if (optor != '-')
    if (optor != '*') if (optor != '/') {
  if (optor > ' ') // just ignore white space
    System.out.println("Please type an operator: + - * / c q");
Don't forget you will be getting the Enter key inputs also, and this "white space" test catches (and discards) them.

As I said above, we will start by using integer input, my Zystem.ReadInt(), reading it into either an int variable or a double. Let's start with int (that's the type of the variable on its declaration line). I called mine inval, but this is your program, you decide.

Now to read our input value:

inval = Zystem.ReadInt();

Do you think you can do the rest? Try it. If you have trouble making the calculation work, but it compiles, it will probably run, and you can use the debugger to see what's going wrong. If it won't compile, you will have a line number in the Replit console (or in BlueJ, those red bars in the margin and you can click the error count in the corner for a message). Always fix the first error; usually it's the only one that makes any sense.

After you have it working, you can test whether it's working correctly. Notice that if you give it a fractional value like 12.34, it only sees what's before the decimal point. That's because Zystem.ReadInt() stops reading at the decimal point. We'll fix that shortly. However, if you give it +1234, and then /100, the calculation is in double (you did declare the result that way, right?) so that gets you a fractional result.

What happens if you change the input variable (inval) to be double also?. Do you see any difference? Java automatically promotes integers to double when used in mixed-mode (both integer and double in the same) calculations, so when you read Zystem.ReadInt() into a double variable, it also gets promoted. Otherwise, if you are using a double for your result value, the (still integer) input value gets promoted when you do the arithmetic operation. You need to understand this, because the data types of the values you are using sometimes makes a difference, and sometimes promotion fixes it for you (like today). You need to understand why. If it's still foggy, ask the Mentor, that's what they are here for.

When I ran my version and gave it goofy inputs, it did unexpected things, probably because Java is filtering the keyboard input. But it worked OK when I gave it an operator and a number (with or without a space between them), followed by return ("Enter" on most keyboards). In the next lesson, when you replace my Zystem class with Scanner, you will need to type a space between the operator and its number.

By the way, did you try giving it "/ 0" (divide by zero)?

Next: Exceptions

<<Previous | ToC | Next >>

Revised: 2023 February 3