🔥 🔥 Methods, Variables, Strings, Arrays, and Enums 🔥 🔥
- Join the Piazza (if you haven't already)
- Reminder: OH are
TH 11am - 4pm
in 34-303
- Open Terminal or Git Bash.
- Go to the directory where you keep 6.178 stuff (this is where the repository will go)
- Run:
git clone https://github.com/m-99/lec02.git
- After you have successfully cloned this repo, import
lec02
into Eclipse (instructions)
- Set up Java + Eclipse
- Set up Git
- Java basics
- Link to Lecture 1 (alternate link)
- Java Methods
- Writing specifications (code documentation)
- More about variables
- Arrays
- Enums
- Feedback 👈 (please do this at the end of lecture!)
- Extra Practice Problems
Methods are similar to functions in Python. They are attached to classes (which is why we call them methods and not functions). For example, here is a method named fahreneitToCelsius
:
public class UnitConverter {
// ... other variables and methods ...
public static double fahrenheitToCelsius(double temperatureFahrenheit) {
double ratio = 5.0 / 9.0;
double offset = 32.0;
return (temperatureFahrenheit - offset) * ratio;
}
// ... other variables and methods ...
}
A method is composed of 5 parts (in order): the modifiers, return type, method name, parameters, and the method body. (There is a 6th part, the exceptions list, which we won't talk about in this lecture.)
For the above example method:
- modifier -
public
,static
public
means the method is visible not just within this class, but to other classes in your program as well.- To prevent other classes from calling this method, we can make this
private
.
- To prevent other classes from calling this method, we can make this
static
means the method exists independently of any instance of the class - more on that in future lectures. For now, think of it as a method that you can call directly from themain
method.
- return type -
double
- This means that this method returns a value of type
double
.
- This means that this method returns a value of type
- method name -
fahrenheitToCelsius
- The name of the method.
- parameters -
(double temperatureFahrenheit)
- This method only has one parameter, but you can have multiple parameters separated by commas.
- Parameters are declared with types, similar to variables:
<parameterType> <parameterName>
- method body - code between the curly braces
- This code will be executed if the method is called.
To call this method from within the same class, just write the method name and provide the parameters necessary. Here we're storing the result of calling fahrenheitToCelsius
with the parameter temperatureFahrenheit
set to 32.0
in a double
named temperatureCelsius
:
double temperatureCelsius = fahrenheitToCelsius(32.0); // 0.0
Now let's look back at the special main
function:
public class Main {
// ... other variables and methods ...
public static void main(String[] args) {
}
// ... other variables and methods ...
}
- modifier -
public
,static
(visible to other classes, independent of instance) - return type -
void
(special return type representing nothing returned) - method name -
main
- parameters -
(String[] args)
(a String array) - method body - the code to execute when the program runs
Complete TODO #1 in Main.java
.
- Create a method called
estimateRidePrice
in the same class, and allow it to take all the parameters necessary to calculate the estimated price for a ride from either Uber or Lyft. - Modify the code in
main
to call that method instead of performing the calculations.
A method's specification (or spec) is a set of comments attached to the method that tells the user of the program everything they need to know about the method. Specs are important for software engineers because they allow us to understand and use other people's programs without reading the actual code.
The job of a specification is to describe the output of the method given the inputs. If the inputs satisfy the requirements outlined in the spec, then the method will produce an output that satisfies the requirements outlined in the spec.
An example spec for the fahrenheitToCelsius
method.
/**
* Converts the temperature in Fahrenheit to the temperature in Celsius
* @param temperatureFahrenheit the temperature in Fahrenheit
* @return the temperature in Celsius
*/
public static double fahrenheitToCelsius(double temperatureFahrenheit) {
...
}
The first line of the spec details what the method does in plain English. Each parameter, along with any constraints, is described in a @param
. The return value, along with any constraints, is described in the @return
.
Write a spec, formatted as above, for your estimateRidePrice
method.
Recall from Lecture 1 (alternate link) that variables in Java are statically typed, meaning the declaration must include the type of the variable.
int myAge = 23;
Java has a set of primitive types which represent very simple data. These types are lowercased. The ones that we will deal with the most:
boolean
(true or false)char
(single character)int
(integer within ± 2^31)double
(floating-point numbers)- a complete list
You can think of primitive types as having direct representation in the computer's memory. When you operate on a variable of type int
, the data that gets shuttled around your computer's circuitry is the literal binary representation of that integer.
Java also has more complex types called objects. These types are typically uppercased. Any type which is not a primitive is an object. The simplest examples:
- Strings (sequences of characters, like "Hello there")
- Arrays (sequences of values of any type; more in a bit)
- Enums (a finite set of named values; more in a bit)
Unlike primitives, which are represented as literal values in memory, variables of object types are represented as references to the location of their actual data. This data has a potentially complex structure and usually takes up more space.
A major, practical difference between primitives and objects is that objects (defined as classes - more in future lectures) can define their own operations, accessed via theObject.theOperation(parameters)
. For example, String has a .length()
operation which allows you to count its number of characters. Primitives have no operations of their own - they are all pre-defined by the Java language itself (+
, %
).
String myName = "Richard";
int charactersInName = myName.length(); // 7
char thirdCharacterInName = myName.charAt(2); // 'c'
int indexOfH = myName.indexOf('h'); // 3
Sometimes we want to check whether two variables have the same value. For primitives, we use ==
; for objects, we use .equals()
.
int a, b;
boolean aEqualsB = a == b;
String c, d;
boolean cEqualsD = c.equals(d);
One unfortunate side effect of representing object types as references is that the reference can point to nothing - or null
. You can't call operations on a variable whose value is null
, since there is no object there.
String myName = null;
int charactersInName = myName.length(); // Not allowed, will throw an error
Variable declarations can have additional keywords attached to them. final
is one such keyword, which means that the variable can only be assigned once. This is useful for defining constants whose values should never change.
final int myAge = 21;
...
myAge = 22; // Not allowed, won't compile
So far, we've dealt with variables defined within methods. We can also define variables within classes, outside of any method.
public class Main {
private static int counter = 0;
public static int count() {
counter++;
return counter;
}
}
The counter
variable is visible to any method within the Main
class. The private
modifier means it cannot be accessed by other classes. Removing the static
modifier would make it an instance variable, which we will discuss in a future class.
Generally, variables can be accessed anywhere within the closest enclosing set of curly braces {}.
- Variables declared in a method can only be accessed within the method.
- Variables declared in a class can be accessed within the class.
public
class variables can be accessed by other classes.private
class variables cannot be accessed by other classes.static
vs. non-static
has different semantics (future class).
Arrays represent fixed-size sequences of values. You can create arrays of any type, and they can be multidimensional:
String[] months; // 1d String array
int[][] coordinates; // 2d int array
Since arrays are fixed-size, you have to declare its size when you assign its initial value. The size can be obtained by .length
.
String[] months = new String[12];
char[] mit = new char[] {'I', 'H', 'T', 'F', 'P'};
int numberOfMonths = months.length; // 12
int mitLength = mit.length; // 5
You can obtain and assign values at specific indices in an array:
char middleChar = mit[2]; // 'T'
mit[3] = 'P'; // mit is now IHTPP
In a future lecture, we will explore additional types in Java which can represent dynamically-sized sequences.
Complete TODO #2: create an array of type String
called months
with size 12. Populate each element of the array with the name of the month as a String
.
What does this do?
int[] piDigits = new int[] {3, 1, 4, 1, 5, 9};
int[] myDigits = piDigits;
myDigits[3] = 7;
// What is the value of myDigits? What is the value of piDigits?
Enum is a special data type that allows a variable to take on one of a predefined set of values. Each of these values is named, and is typically ALL_UPPERCASE.
An enum representing Direction
:
public enum Direction {
NORTH, EAST, SOUTH, WEST
}
To declare a variable of type Direction
:
Direction direction = Direction.NORTH;
Create an enum called Day
, whose values are the days of the week. In Eclipse, select File > New > Enum. Make sure the package says lec02
.
Enums are useful for conditional statements. We can execute different instructions in our programs depending on the value of an enum.
Recall from Lecture 1 (alternate link) the syntax for writing conditional if-else statements.
Here's an example of a method that prints which direction you are facing depending on the value of the direction
.
if (direction.equals(Direction.NORTH)) {
System.out.println("You're heading north");
} else if (direction.equals(Direction.SOUTH)) {
System.out.println("You're heading south");
} else if (direction.equals(Direction.EAST)) {
System.out.println("You're heading east");
} else if (direction.equals(Direction.WEST)) {
System.out.println("You're heading west");
} else {
System.out.println("Unknown direction");
}
As you can see, this is verbose and repetitive. In situations like these, where we are only testing one value, we can use switch statements.
Switch statements are a convenient tool for us to quickly create conditional behavior in our programs in a readable block of code. You can use switch statements to conditionally execute a portion of code depending on the value of certain primitive data types, Strings, Enums, and a few other data types that you can find by reading documentation.
If you prefer to read the official Java documentation, you can find it here.
Here is an example of a switch statement that has the same behavior as the if-else statement above.
switch (direction) {
case NORTH:
System.out.println("You're heading north");
break;
case SOUTH:
System.out.println("You're heading south");
break;
case EAST:
System.out.println("You're heading east");
break;
case WEST:
System.out.println("You're heading west");
break;
default:
System.out.println("Unknown direction");
break;
}
A breakdown of the example:
- We begin switch statements with the keyword
switch
, followed by the value that we are testing. Here, we are testingdirection
. - Depending on the value of
direction
, the switch statement will go to thecase
labeled with the matching value (eitherNORTH
,SOUTH
,EAST
, orWEST
). Ifdirection
does not have any one of these values, the code under thedefault
case will be executed. - Each section of the switch statement ends with a
break
to indicate that the code that follows is not a part of the current section. Thebreak
keyword will stop the execution of any more code within the switch statement.`
Please share your thoughts about this lecture here. It's completely anonymous and will help us improve future lectures and gauge your understanding of the content.
If you are looking for a set of simple coding exercises to practice the basics of Java syntax, check out CodingBat. You can start doing problems right away without making an account, but if you would like to save progress (get green check marks next to completed problems) when you revisit the website, you have to have one.
At this point in our lectures, you are ready to try everything in the following sections:
- Warmup-1
- String-1
- Array-1
- Logic-1
Feel free to attempt harder sections if you are comfortable with these problems.
Later in the course, you might want to explore PracticeIt, which has longer problems that draw from more areas of knowledge. This website requires you to make an account.
Go to File > Import.
Select Existing Projects into Workspace under General. Then select Next.
Click on Browse and find the folder of the GitHub repo. The folder should be wherever you cloned the repo. Make sure the parent directory of the repo (the folder with the repo's name) is checkmarked and click Finish.
This is what Eclipse should look like for you after you successfully import the repo. The left panel is your Package Explorer. Here you can find all your packages (how Java organizes each program). Each package represents a different program in your workspace. The right panel is your Outline. The Outline tells you what methods, variables, etc. are in each file; you can quickly jump to them when you click on them. The bottom panel will be helpful for debugging as it has the Console. The center area is where you will be viewing files.