01 Prove
Learning Java with Three Examples
Objectives
Create a Simple Calculator in Java
Create a Form Letter in Java
-
Test and Modify an existing Encryption Program
The three programs that you will write in this first assignment are intended to be a tutorial of the Java language. All the steps for coding the solutions can be found in this assignment. You should follow all the steps and create all three programs as described. You will need to submit the code that you write.
Future assignments will not provide all of this specific detail. You will need to learn to find additional resources online and ask questions to your teacher and peers. You should also refer to the additional examples and notes provided as support each week. You can find these examples in the weekly modules within I-Learn.
Before starting this assignment, you should complete the 01 Teach: Team Activity individually and (if teams are established already) as a team to ensure you have IntelliJ working and can do "Hello World".
If you need a good and simple reference manual for Java, consider using the W3Schools Java Tutorial.
Problem 1: Simple Calculator
The purpose of this program is to write a simple four function calculator using two classes. The first class will be called Calculator and the second class will be called TestCalculator. The TestCalculator class will have the main function and will be used to test the Calculator.
Create a new project in ItelliJ called
Calculator.Create a new package inside the
srcfolder of your project. Use your last name for the package name.Create two new Java Classes in your package called
CalculatorandTestCalculator. Notice that IntelliJ will put thepackagestatement and the empty class definition in both of the files for you.Our calculator will maintain a current result and do basic math operations. Here is the summary of what you want in the class:
In the
Calculatorclass, first write the member data:If there is member data, then you need a constructor to initialize the member data. Constructors in Java are named the same as the class and should be public. Create a constructor for the
Calculatorclass after the member data. Note that0.0fmeans float and0.0means double.Implement the
add,subtract,multiply, anddividefunctions described in the table after the constructor. Note that each parameter includes the data type. Also note that the return type of the function is also specified. If the function does not return anything then you usevoid. Thedividefunction must use anifstatement to ensure you do not try division by zero.Implement the
resetfunction. This function has no inputs.Implement the
getResultfunction. This is called a getter function and will provide a copy of the private data. In IntelliJ, you can automatically create this function by going to menu option Code, select Generate, and select Getter.Now that you have the
Calculatorclass written, you will write some test code in theTestCalculatorclass. Create amainfunction in theTestCalculatorclass.In your
mainfunction, create aCalculatorobject using thenewkeyword. All objects are created dynamically on the heap in Java. You don't have to delete them when you are done. Java will use "garbage collection" to delete unused objects. TheCalculatorobject variable that you create is holding a reference or pointer to the object.Print out the current result of the calculator by calling the
getResultfunction.Run the program by pressing the green play button in IntelliJ to the left of the
mainfunction code. It should display "Result = 0.0".Change the code to add 5, multiply by 3, subtract 1, and then divide by 2. Run it again and you should get "Result = 7.0".
Create a
do whileloop in yourmainfunction (after the code you have already written) to allow the user to select an operation. Thedo whileloop will keep running until the user selects the exit option. Reading from the keyboard requires the use of theScannerclass provided by Java.Scannerallows you to read a line of text. Notice that when you create theScannerobject, IntelliJ will show an error until you provide theimportstatement. Java requires that you specify which libraries you are using. You only have to create theScannerobject once before the loop. When you ask for values from the user, we need to convert theStringto afloatusingFloat.parseFloat. Note thatparseFloatis a static function which is why you don't need aFloatobject to call it. Also note that you can not use==to compare strings in Java. You must use theequalsfunction.Test your code with different inputs to make sure everything works. Remember to test divide by 0.
| Member Data / Attributes | Data Type | Scope | Purpose |
|---|---|---|---|
| result | float | private | The current result stored in the calculator |
| Member Functions / Methods | Parameters | Return Type | Scope | Purpose |
|---|---|---|---|---|
| add | float value | void (don't return anything) | public | Add a value to the current result |
| subtract | float value | void | public | Subtract a value from the current result |
| multiply | float value | void | public | Multiply a value with the current result |
| divide | float value | void | public | Divide a value with the current result. If the value is 0, then set the result to 0. |
| reset | None | void | public | Reset the result back to 0 |
| getResult | None | float | public | Return a copy of the result |
public class Calculator {
private float result;
}
public Calculator() {
result = 0.0f;
}
public void add(float value) {
result += value;
}
public void subtract(float value) {
result -= value;
}
public void multiply(float value) {
result *= value;
}
public void divide(float value) {
/* Check for divide by zero */
if (value == 0.0f) {
result = 0.0f;
} else {
result /= value;
}
}
public void reset() {
result = 0.0f;
}
public float getResult() {
return result;
}
public class TestCalculator {
public static void main(String[] args) {
}
}
public static void main(String[] args) {
Calculator calc = new Calculator();
}
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println("Result = " + calc.getResult());
}
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println("Result = " + calc.getResult());
calc.add(5.0f);
calc.multiply(3.0f);
calc.subtract(1.0f);
calc.divide(2.0f);
System.out.println("Result = " + calc.getResult());
}
import java.util.Scanner;
public class TestCalculator {
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println("Result = " + calc.getResult());
calc.add(5.0f);
calc.multiply(3.0f);
calc.subtract(1.0f);
calc.divide(2.0f);
System.out.println("Result = " + calc.getResult());
Scanner scanner = new Scanner(System.in);
String choice;
do {
System.out.println();
System.out.println("Result = " + calc.getResult());
System.out.print("Operation (add, subtract, multiply, divide, reset, exit): ");
choice = scanner.nextLine();
if (choice.equals("add")) {
System.out.print("Enter value: ");
float value = Float.parseFloat(scanner.nextLine());
calc.add(value);
} else if (choice.equals("subtract")) {
System.out.print("Enter value: ");
float value = Float.parseFloat(scanner.nextLine());
calc.subtract(value);
} else if (choice.equals("multiply")) {
System.out.print("Enter value: ");
float value = Float.parseFloat(scanner.nextLine());
calc.multiply(value);
} else if (choice.equals("divide")) {
System.out.print("Enter value: ");
float value = Float.parseFloat(scanner.nextLine());
calc.divide(value);
} else if (choice.equals("reset")) {
calc.reset();
} else if (choice.equals("exit")) {
System.out.println("Goodbye!");
} else {
System.out.println("Invalid choice.");
}
} while (!choice.equals("exit"));
}
}
Problem 2: Form Letter
The purpose of this program is to learn how to use a simple data structure called the ArrayList. The ArrayList is like the Vector in C++ or the list in Python. When you create an ArrayList (like other data structures in Java) you have to specify what it will hold. You are going to hold an ArrayList of Account objects. You will use these Account objects to populate form letters. This will allow you to demonstrate loops.
Create a new project in ItelliJ called
FormLetter.Create a new package inside the
srcfolder of your project. Use your last name for the package name.Create two new Java Classes in your package called
AccountandLetterGenerator. Notice that IntelliJ will put thepackagestatement and the empty class definition in both of the files for you.The
AccountClass will contain the following member data.Write the member data in the
Accountclass and write a construtor to intialize all the member data. This time you want the constructor to accept the three pieces of member data as parameters. Just like the getters, you can use IntelliJ to auto-generate a constructor for the class. Specify that you want all three parametersname,lastPurchase, anddaysSincePurchaseto be included in the constructor. Note the use of the keywordthis. The keywordthisis used when you want to refer to your object. Python used the keywordself.Using IntelliJ, auto-generate the getters and the setters for the
Accountclass.The
LetterGeneratorclass will have the following member data and member functions:Add the member data and provide a constructor that initializes the
ArrayListto an empty list and theformLetterto a example letter. Notice that when you create theArrayList, IntelliJ will show an error until you provide theimportstatement. Java requires that you specify which libraries you are using.Implement the
addAcccountfunction. This function will use aScannerto read in the information and create anAccountobject. You will add theAccountobject to ouraccountslist by using theaddfunction.Start the implementation of the
generateLettersfunction. This function will loop through each account in the accounts list. Thefor loopdefines a variable calledcurrAccountwhich will be populated with the individualAccountobjects in the list.In the loop, replace "[name]" with the
namefromcurrAccount. To get thenamefrom thecurrAccount, call thegetNamefunction that you created in theAccountclass. Do the same for "[days]" and "[purchase]". Notice that you need to convert the daysintto aStringusingString.valueof. TheStringclass in Java has lots of functions available to use. Look in the JavaDoc to see more available functions (good place to bookmark).Create a
mainfunction in theLetterGeneratorto test out your code. CalladdAccountthree times with different information and then callgenerateLetters. Check to make sure the form letter is populated properly each time.
| Member Data / Attributes | Data Type | Scope | Purpose |
|---|---|---|---|
| name | String | private | The account holder name |
| lastPurchase | String | private | The name of the last thing purchased |
| daysSincePurchase | int | private | The number of days since the last purchase |
public class Account {
private String name;
private String lastPurchase;
private int daysSincePurchase;
public Account(String name, String lastPurchase, int daysSincePurchase) {
this.name = name;
this.lastPurchase = lastPurchase;
this.daysSincePurchase = daysSincePurchase;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastPurchase() {
return lastPurchase;
}
public void setLastPurchase(String lastPurchase) {
this.lastPurchase = lastPurchase;
}
public int getDaysSincePurchase() {
return daysSincePurchase;
}
public void setDaysSincePurchase(int daysSincePurchase) {
this.daysSincePurchase = daysSincePurchase;
}
| Member Data / Attributes | Data Type | Scope | Purpose |
|---|---|---|---|
| accounts | ArrayList<Account> | private | A collection of account objects. |
| formLetter | String | private | A form letter than contains replaceable tags |
| Member Functions / Methods | Parameters | Return Type | Scope | Purpose |
|---|---|---|---|---|
| addAccount | nothing | void | public | Prompt the user to enter in account information and then add it to the accounts list. |
| generateLetters | nothing | void | public | Generate the letters for each account in the list |
import java.util.ArrayList;
public class LetterGenerator {
private ArrayList<Account> accounts;
private String formLetter;
public LetterGenerator() {
accounts = new ArrayList<Account>();
formLetter = "Dear [name], its been [days] since your last purchase " +
"of the [purchase]. We hope to see you again soon!";
}
}
public void addAccount() {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter name: ");
String name = scanner.nextLine();
System.out.print("Enter last item purchased: ");
String item = scanner.nextLine();
System.out.print("Enter days since last purchase: ");
int days = Integer.parseInt(scanner.nextLine());
Account account = new Account(name, item, days);
accounts.add(account);
}
public void generateLetters() {
for (Account currAccount : accounts) {
}
}
public void generateLetters() {
for (Account currAccount : accounts) {
String letter = formLetter.replace("[name]", currAccount.getName());
letter = letter.replace("[days]", String.valueOf(currAccount.getDaysSincePurchase()));
letter = letter.replace("[purchase]", currAccount.getLastPurchase());
System.out.println(letter);
System.out.println();
}
}
public static void main(String [] args) {
LetterGenerator letterGenerator = new LetterGenerator();
letterGenerator.addAccount();
letterGenerator.addAccount();
letterGenerator.addAccount();
letterGenerator.generateLetters();
}
Problem 3: Enryption Code
The purpose of this problem is to practice using existing code. The existing code is a class called NSALoginController which will encrypt and validate passwords. Your first step will be to copy the code into your project. In the second step, you will write some test code to make sure the NSALoginController is working. In the third step, you will modify the NSALoginController to provide for more strict password requirements.
Part I - Import Existing Code
Start by creating a new Project in IntelliJ called
NSALoginCreate a package using your last name.
Download the files for this project. After unzipping this file, look for
NSALoginController.java. You can drag and drop this file into your package within IntelliJ. When you do this, it will change the package statement inNSALoginController.Browse through the code in the
NSALoginControllerclass to see what functions are available. Consider making a UML diagram to better understand the class. You don't need to understand how all this code works to do encryption. Take special note of thehashUserPasswordandverifyPasswordfunctions. You will be testing those in the next section. Also note that these functions arestatic. Astaticfunction does not require an object to call. Also note that each of these functions hasthrows Exceptionin the function declaration line. You will be required to catch these potential exceptions in your test code.The purpose of
hashUserPasswordis to take aUserobject (you will need to create that class later), read its password, and generate a salt and encrypted hashed password. The generated salt is used to encrypt the password. It will then delete the password for security. The salted and hashed password are the only things we need to save.The purpose of
verifyPasswordis to take aUserobject (with the salt and hashed password still populated along with the password we are testing) and return abooleanindicating whether or not the user's password is correct.
Part II - Test the EXISTING CODE
Create a new class called
Test. You will put yourmainfunction in here.Create a new class called
User. TheNSALoginControllerrequires that you have aUserobject with the member data shown in the table below. Note that theNSALoginControllerexpets these variables (and their getters and setters) to be correctly named.Create a constructor that passes in the
passwordand sets thesaltandhashedPasswordto empty strings. Use IntelliJ to auto-generate the getters and setters.In the
mainfunction of theTestclass, you will first test thehashUserPasswordfunction inNSALoginController. You will first need create aUserobject since both functions require aUserobject. You should add some debug code to make sure our user object was created correctly.Pass the
Userobject to thehashUserPassword. Since the function might throw anException, we are required tocatchthat potential exception. If something fails in thetryblock (e.g.hashUserPasswordthrows an exception) then execution will be immediately diverted to thecatchblock. Again, we should add some debug code to see if the hash operation worked. Take note that thepasswordshould be cleared after thehashUserPasswordfunction is called.To test the
verifyPassword, you will ask the user for theirpassword. We will add thepasswordinto our previously createdUserobject. That object still has thesaltandhashedUserPasswordpopulated. TheverifyPasswordfunction will compare thepasswordwith thesaltandhashedUserPasswordvalues. This function can throw an exception too so we will keep it in thetryblock. The function also returns aboolean. If it returnstrue, then the password matched.Run your code several times to prove that
NSALoginControlleris working properly.
public class Test {
public static void main(String[] args) {
}
| Member Data / Attributes | Data Type | Scope | Purpose |
|---|---|---|---|
| password | String | private | The raw password from the user |
| salt | String | private | A value generated for the user that provides variation in the hashedpassword generation. This is done for security. |
| hashedPassword | String | private | The encrypted version of the password generated with the salt. |
public class User {
private String password;
private String salt;
private String hashedPassword;
public User(String password) {
this.password = password;
this.salt = "";
this.hashedPassword = "";
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter password: ");
String password = scanner.nextLine();
User user = new User(password);
// Only Password should be set at this point
System.out.println("Password: " + user.getPassword());
System.out.println("Salt: " + user.getSalt());
System.out.println("Hashed Password: " + user.getHashedPassword());
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter password: ");
String password = scanner.nextLine();
User user = new User(password);
// Only Password should be set at this point
System.out.println("Password: " + user.getPassword());
System.out.println("Salt: " + user.getSalt());
System.out.println("Hashed Password: " + user.getHashedPassword());
try {
// hashUserPassword is a static function (no NSALoginController object needed)
// This function will set the salt and hashedPassword in the user object
NSALoginController.hashUserPassword(user);
// Only salt and hashed password set at this point
System.out.println("Password: " + user.getPassword());
System.out.println("Salt: " + user.getSalt());
System.out.println("Hashed Password: " + user.getHashedPassword());
}
catch(Exception e) {
System.out.println("General Exception: " + e.toString());
}
}
try {
// hashUserPassword is a static function (no NSALoginController object needed)
// This function will set the salt and hashedPassword in the user object
NSALoginController.hashUserPassword(user);
// Only salt and hashed password set at this point
System.out.println("Password: " + user.getPassword());
System.out.println("Salt: " + user.getSalt());
System.out.println("Hashed Password: " + user.getHashedPassword());
// Run a test of the hashed password.
// Ask the user for the password and set it in the user object
System.out.print("Enter password: ");
password = scanner.nextLine();
user.setPassword(password);
// verifyPassword will check the password in the user object against the salt
// and hashed password.
if (NSALoginController.verifyPassword(user))
{
System.out.println("Verified!");
}
else
{
System.out.println("Not Verified!");
}
}
catch(Exception e) {
System.out.println("General Exception: " + e.toString());
}
Part III - Modify the EXISTING CODE
Once you have proven that the
NSALoginControlleris working, you can now modify it. You need to change it to require a password length of at least 8 and a requirement to have at least one digit in the password. We can use the.lengthproperty on aStringto determine the length. To determine if there is a digit, we can loop through each letter of the password and use theCharacter.isDigitfunction.If password checking has failed, then we have to exit the function and notify the calling function. However, recall that this function is throwing exceptions (which we had to catch in our main function). One solution is to throw a new
Exceptionobject.In Java, it can be useful to create new exception classes for special scenarios like this one. Creating your own exception class provides for better readability of the code and allows you to respond to errors less generically. To create your own exception class, you have to inherit the base
Exceptionclass.Create a new class called
WeakPasswordException. When the class is created, modify it toextendstheExceptionclass. This is how you inherit a base class.This class will be very simple. It will not have any member data within it. You are allowed, but in this case you don't have any need. The only additional requirement is that you provide a constructor that will pass the customized error message up to the constructor of the
Exceptionbase class. You can call the parent constructor by usingsuper.With the creation of
WeakPasswordException, we can now use it in ourhashUserPasswordfunction. Note you also need to state that you canthrows Exception, WeakPasswordException.Since this function can throw multiple types of exceptions now, our
mainfunction code can list them out separately. You can have multiplecatchblocks in your code for a singletryblockTest out your code to make sure that the "Weak Password Error" message is displayed if a weak password is provided by the user.
public static void hashUserPassword(User user) throws Exception {
// Get the next random salt value to use for this password
byte[] salt = getNextSalt();
char[] password = user.getPassword().toCharArray();
// Verify password rules:
// 1) Length at least 8 characters
// 2) Contain at least one digit
if (password.length < 8) {
// Do Something!
}
boolean hasDigit = false;
for (Character c : password) {
if (Character.isDigit(c)) {
hasDigit = true;
}
}
if (!hasDigit) {
// Do Something!
}
public static void hashUserPassword(User user) throws Exception {
// Get the next random salt value to use for this password
byte[] salt = getNextSalt();
char[] password = user.getPassword().toCharArray();
// Verify password rules:
// 1) Length at least 8 characters
// 2) Contain at least one digit
if (password.length < 8) {
throw new Exception("Password must be at least 8 characters long.");
}
boolean hasDigit = false;
for (Character c : password) {
if (Character.isDigit(c)) {
hasDigit = true;
}
}
if (!hasDigit) {
throw new Exception("Password must contain at least 1 digit.");
}
public class WeakPasswordException extends Exception {
}
public class WeakPasswordException extends Exception {
public WeakPasswordException(String errorMessage)
{
super(errorMessage);
}
}
public static void hashUserPassword(User user) throws Exception, WeakPasswordException {
// Get the next random salt value to use for this password
byte[] salt = getNextSalt();
char[] password = user.getPassword().toCharArray();
// Verify password rules:
// 1) Length at least 8 characters
// 2) Contain at least one digit
if (password.length < 8) {
throw new WeakPasswordException("Password must be at least 8 characters long.");
}
boolean hasDigit = false;
for (Character c : password) {
if (Character.isDigit(c)) {
hasDigit = true;
}
}
if (!hasDigit) {
throw new WeakPasswordException("Password must contain at least 1 digit.");
}
try {
// Only Password should be set at this point
System.out.println("Password: " + user.getPassword());
System.out.println("Salt: " + user.getSalt());
System.out.println("Hashed Password: " + user.getHashedPassword());
// hashUserPassword is a static function (no NSALoginController object needed)
// This function will set the salt and hashedPassword in the user object
// We expect that the password will be cleared.
NSALoginController.hashUserPassword(user);
// Only salt and hashed password set at this point
System.out.println("Password: " + user.getPassword());
System.out.println("Salt: " + user.getSalt());
System.out.println("Hashed Password: " + user.getHashedPassword());
// Run a test of the hashed password.
// Ask the user for the password and set it in the user object
System.out.print("Enter password: ");
password = scanner.nextLine();
user.setPassword(password);
// verifyPassword will check the password in the user object against the salt
// and hashed password.
if (NSALoginController.verifyPassword(user)) {
System.out.println("Verified!");
}
else {
System.out.println("Not Verified!");
}
}
catch (WeakPasswordException e) {
System.out.println("Weak Password Error: " + e.getMessage());
}
catch(Exception e) {
System.out.println("General Exception: " + e.toString());
}
Submission
To submit this assignment (and future individual assignments), you need to use the following procedure:
Upload your code to the "Code Submission" assignment in I-Learn. You only need to submit your Java files. You can zip them up or submit them individually.
Take a multiple choice, self-evaluation "Assessment" of the functionality in I-Learn.
Once you have submitted the assessment, a link to the instructor's solution to this assignment becomes available. You are expected to look through the instructor's code, which is heavily commented to explain why certain choices were made. Keep in mind that this is not the only way to complete the assignment.
If desired, you can use the instructor's solution to help guide you through completing anything you were not able to finish. Then, you can re-submit the code and multiple choice assessment above, and an average of the two scores will be used. Thus, if you got 80% the first time, but after looking at the instructor's solution, you were able to complete everything for a 100%, your final score will be 90% for that portion.
Please note that the "Code Submission" element does not receive a score itself in the gradebook. It is provided so the instructor can refer to it, but the "score" is attached to the multiple choice self assessment.
Future assignments will follow this same procedure.