Week 01: Introduction and Java Review

Overview

Welcome

Hello and welcome!

Welcome to our time of learning together.

Welcome to the many first-years in this classroom, who are physically attending their first day of college classes today. Welcome to returning students.

Welcome to people of all ages, all colors, all cultures, abilities, sexual orientations and gender identities.

Welcome to those who identify as biracial, multi-racial, or multi-ethnic.

Welcome to people from Massachusetts, from other states, and from countries all around the world.

Welcome to people of all political persuasions – or who abstain from politics. Welcome to people of all religions and of no religion.

Welcome to military veterans.

Welcome to people who live with mental illness.

Welcome to those of you who are financially broke, or those broken in spirit.

It is my firm belief that you all belong here, and I want you to feel welcome. Whoever you, wherever you are on your journey in computer science, you are welcome here.

I’m Marc Liberatore liberato@cs.umass.edu and I’m your instructor for this course, COMPSCI 186. Please call me Marc.

Administrivia

The most important thing to know today: the course web site is at http://people.cs.umass.edu/~liberato/courses/2021-spring-compsci186/. It includes the syllabus for this class and you are expected to read it in its entirety; it also includes all assignments, readings, and so on.

The course is not just me (of course). We have a fine TAs: Mehmet Savasci. TAs are graduate students in the department who have the side job of helping run courses. They hold office hours, run discussions and labs, do grading, answer questions online, and so on.

We also have several undergraduate course assistants, Grace, Yan, Isi, and Veronica, who will also be answering questions, holding office hours, and grading some of your work. They don’t start until next week, and their office hours will be online.

Public health

Face masks are required. Be sure to cover your nose and mouth with a well-fitting mask, and to wash your mask occasionally.

Maintain social distance (at least 6’) from others.

Follow traffic direction signs.

No eating or drinking in the classroom.

Get tested twice a week.

Complete your daily COVID-19 checklist before coming to class. We record lecture, so please do not come to class if you have any doubts about symptoms!

Wash and sanitize your hands frequently.

Other important announcements

There is a problem set due Friday!

And, there is a (short, and I hope simple) programming assignment due Friday!

Finally, there will be a start-of-semester “self-assessment” distributed and due next Monday! Your TA will be available during your regularly-scheduled lab time if questions come up during the self-assessment.

(It appears that I love exclamation points!!!)

That’s a typical week – Monday there is either a “self-assessment” that you have 24 hours to do, or a lab meeting during your scheduled time, but not both. Tuesday and Thursday, lectures. Friday, problem set and programming assignment due. Get in the habit of thinking about 186 all the time!

Seriously, 186 is a lot of work for many people. Especially if you haven’t done lots of programming before, this is a course where at least some of the training wheels come off. Set aside time – more than eight hours before assignments are due – to work on things, especially programming assignments.

What is this course?

What is this course? It’s a course about the who, what, when, and why of commonly-used data structures – we’ll learn their names and behavior well enough to know when to use which structures. We’ll only briefly touch on the how – how data structures are implemented – as COMPSCI 187 concerns itself deeply with this topic and is the next course in the COMPSCI sequence.

Speaking of 187, let’s confront the elephant in the room right now. 186 is an optional course between 121 and 187. Why does it exist, and why does it exist now? (And by implication, why are you here?) Two big reasons and one small one:

186 is an attempt to kill these two-and-a-half birds with one stone.

First, we conjecture that many students who do OK in 121 – a B- is nothing to be ashamed of – or who get a 3 on the CS AP exam, could pass 187 – if only they had a little more practice programming and exposure to various parts of the computer science ecosystem (especially the practical bits of Java). 186 is intended to guide you on a path toward programming mastery that’s more gentle than the current trajectory of 187. 187 has a bit of what I call the “eat your vegetables first” problem. It also has a bit of the “pie eating contest, where first prize is more pie” problem. Together this is a recipe for a lot of spinach pies, which maybe isn’t great if you’ve not been training in competitive spinach pie eating since you were a kid. 186 is an attempt to provide more reasonable portion sizes and to balance the diet.

Moving on from mixed metaphors, 187 is a prerequisite for all of the 200-level COMPSCI classes. Some upper-level COMPSCI classes are reasonable fits for Informatics majors (such as 326: Web Programming), but have prerequisites of either 187 or 220230. The reason for these prerequisites is, in some cases, programming maturity: we think you need more than just 121 to be ready for them. 186 will be, we hope, an alternative to 187 in giving you the experience you need to be ready for these courses (this may change someday, but right now is true – INFO students can take some CS300s without other prep than 186).

So, what’s our plan? We’ll start off with a review of some of the material from 121 or AP CS – mostly Java and how it works. We’ll spend a little time on Integrated Development Environments (IDEs); this semester, we’ll be using Visual Studio Code. We’ll begin with toy programs, and as the semester progresses, we’ll work our way up to more complicated programs. We’ll learn about and use many of the data structures available in the Java API to build these programs. Along the way, we’ll learn about some of the tooling you can expect to use as a working Java programmer (in 187, or in Informatics courses, or in internships). This is the part where I’m also supposed to say, “and we’ll have fun doing it,” but let’s not over-egg the pudding, shan’t we?

Java review

Bits and bytes

We’ll spend most of the next few weeks on a review of some 121 material (and some IDE and testing how-tos). Let’s get started.

The fundamental unit of information is the bit – a single, binary digit, of value 0 or 1.

Bits are organized into bytes: 8 bits in a byte. bits (the smaller unit) are abbreviated b; bytes (the bigger unit) are abbreviated B.

When we talk about computer memory and RAM, we’re talking about a large number of bytes that we use to store data. Data is thing that enables nontrivial, “stateful” programs — without (changeable) state, behavior is predetermined. But computers are generally useful to us because we can vary their behavior: we need data, and we need to be able to manipulate it.

How many bytes are we talking about? How much memory does your PC or Mac have? 4 GB? What’s a giga-?

A kilo / mega / giga are metric prefixes: multipliers of 10^3 (1,000), 10^6, and 10^9, respectively. Confusingly, in the land of computer science, they’re multipliers of 2^10 (1,024), 2^20, and 2^30 – each slightly larger than the corresponding metric prefix. Even more confusingly, that only applies to memory; network bandwidth and disk sizes usually use the metric meaning. (This fact is one of the reasons why when you buy a 500GB drive it usually shows up as significantly less: 500 x 10^9 ~= 465 x 2^30.)

These several billion bytes are like an enormous canvas that you, the programmer, can paint upon. Except the computer isn’t you, and can’t see them all at once: you have to precisely name the place in memory you care about. Modern CPUs number the bytes, starting at zero (‘cuz we start at zero in CS, of course) and working their way up to 4 x 2^30 - 1 (if you have 4GB of “addressable” memory). This number is called the byte’s address.

Modern CPUs usually work on larger units of information, called a word. Words on modern CPUs are typically 32 or 64 bits (4 or 8 bytes), and some special instructions can work on larger units still. A computer can have as much addressable memory as fits in a word. Thus, the address space is usually equal to 2^(word size) of the computer.

Right about now you’re probably like, “did I accidentally sign up for a Computer Systems Engineering course?” And the answer is no. But I do want to make sure you have some intuition for stuff that’s going to come up later in the course and 187. But I promise this is about as deep as we’ll go into computer organization.

Variables, data types, and assignment

OK, so another thing you might be thinking is, “Huh, I’ve never written any Java where I’ve worried about addressing memory directly.” To which I respond, “Eff yes! Ain’t it great?”

(Arguably) one of the greatest success stories of computer science is the development of high-level languages and runtimes to free programmers from worrying (too much) about nitty-gritty details like those above. Of course, sometimes you will need to do so, but for problems that don’t push the boundaries of what a computer can do, and that don’t need to scale to millions of machines, and so on, you can effectively ignore many little details and still be an extremely productive programmer.

For example, suppose we’re writing a web app for the PVTA: http://bustracker.pvta.com/infopoint/

We don’t need to worry about painstakingly laying out four bytes to represent a bus number, then eight bytes to represent a distance, and then remember their memory address each time we want to use them.

(on board)

Instead we might write:

int busNumber;
double distanceTraveled;

(on board)

And the computer (the compiler and the runtime) generate code that lays out memory for us, gives each variable a name, and even knows something about the variable – its type. The compiler can do “typechecking” to prevent us from attempting some impossible things, like, say, adding together a boolean and an integer. It can also use type information to make our lives easier: adding a floating-point number and an integer is actually non-trivial, but it’s transparent in Java. Similarly, we can “add” integers to strings to build a new string with the integer inserted.

There are roughly two kinds of types in Java: primitive types, and objects. (Arrays are kinda in between, but are actually an Object.)

What are the primitive types you know about?

Whenever you declare a variable of one of these types, Java lays out memory of the correct size and remembers the address, using the value stored in that memory address whenever you reference the variable. We blur the difference sometimes when speaking, but keeping the idea of a variable (a particular location in memory) and a value (in this context, the contents of a memory location) separate is very important.

A fundamental thing you can do with variables is assign to them. You can assign a literal value, like i = 3; to write a value directly to a memory location. You can assign from one variable to another, like i = j;. But let’s be clear about what’s happening: the computer isn’t “copying j into i,” even though that’s how you might say it. It’s looking up the value stored at the address of j, then storing that value in the address of i. This is more clear if you think about the result of a computation, like “i = j + k;”.

The primitive types support various kinds of computation using “operators”, which are built into the language (things like addition and subtraction).

What happens in the following code?

int i = 2;
int j;
j = i;
j = j + 1;

(on board) A memory location to hold an int is allocated, and initialized with the value 0. Another (different!) memory location is allocated. The value from the first location (i) is looked up; it’s then copied into the second location. Then, the value from the second location (‘j’) is looked up, incremented by 1, and written back into that location.

In-class exercise

int i = 5;
int j = i;
j = j + 2;
i = i + j

What are the values of i and j at the end of this code?

(on board) A memory location to hold an int is allocated, and initialized with the value 5. Another (different!) memory location is allocated. The value from the first location (i) is looked up; it’s then copied into the second location. Then, the value from the second location (j) is looked up, incremented by 2, and written back into that location. Finally, the value of each of i and j are looked up, summed, and stored in the location of i.

More administrivia

My office hours are Thursday at 9:30, via Zoom. Please come! I’m happy to answer questions, chat, review something from the lectures you didn’t understand, and so on. It’s your time, so you should come and make the most of it!

For those of you who are new to college, office hours are typically drop-in (no appointment necessary) and first-come, first-serve chances to come talk to a professor or TA / course assistant about anything in the course.

Usually, students come with specific questions, but general questions about course material are fine too. Come see us if something from lecture or an assignment is unclear, please! But don’t expect to just open your laptop and say, “my program doesn’t work, can you help me find the problem?” Be ready to tell us what you’ve tried and why you’re stuck.

TA and UCA office hours we’ll post online once they are finalized – UCAs don’t even start until next week, so I don’t have their hours yet.

There will also almost certainly be SI sessions, which are run in the LRC, located in the DuBois (tall brick tower) library, though I think they’re virtual this semester. Look into this if you need extra help in the course. Again, we’ll post details when they’re available.

Please use Campuswire for questions! You would be shocked (or maybe not) to know that many students will ask the same question; it saves everyone time if you check Campuswire to see if your question has already been asked and answered. And it saves us time if we only have to answer one question. Thus, we’re able to answer more questions, which everyone likes.

More Java!

Java review

Arrays

Arrays are a built-in form of “container” type – the first (non-primitive) data structure you likely learned about, and perhaps the first reference type. In particular, arrays are a linear sequence of values, all of the same type. In our examples today, they’ll be arrays of primitive-type values, but arrays can hold objects (actually refererences to objects) as well, as we’ll see. An array type is denoted with the [] suffix after a type. For example, an array of ints might be declared as int[] busNumbers;

(on board) The array type doesn’t tell you how many of the thing are in the array. This information exists only once the array is instantiated – the memory allocated for it: int[] busNumbers = new int[5]; What’s happening here? First, new int[5] creates a new space in memory for ten integers, one after another. Then, the address of this memory space is stored in busNumbers – arrays are a reference type, so they hold a reference (or address) to the thing, no the thing itself.

If you want to access a particular piece of the array, you must address it correctly, indexing from zero; the arrays indexing operator ([]) looks up the memory address of the array, then finds the offset to value you are interested in.

(on board) So, for example, busNumbers[1] = busNumbers[3]; means, in English, to look up the memory address of the array, then look up the value stored in the third (starting from zero, which we call the “zero-eth”) slot of the array, and store it in the “zero-eth” (aka first, in a zero-indexed array) slot of the array.

Arrays also support some useful methods and properties, such as .length.

You can have arrays of arrays, for example, int sudoku[][] is an array of arrays of ints; this kind of two (or more) dimensional array is sometimes a more intuitive way to represent a problem than a one-dimensional array.

In class exercise

What’s true about the two variables int busNumber and int[] busNumbers and their associated values?

Do they store ints?
Do they directly or indirectly (that is, by reference) store ints? Do they name values, or memory locations? Do they contain values, or memory locations? Are they primitive types, or reference types?

Methods and scope

Nothing lasts forever. Variables (the names, not the values) only live for as long as they are “in scope.” Suppose we have two methods:

int add(int i, int j) {
  return i + j;
}

void print() {
  System.out.println(i + " " j);
}

Will this compile? No. Why not? Because i and j are not defined within the print() method – in other words, they are not in scope. Scope means the portion of the program where a variable (again, not necessarily the value) is valid.

Within methods, any parameters are in scope for the entire method. A variable that’s declared inline:

void aMethod() {
  ...some stuff...
  int x = 12;
  ... some more stuff
}

is only valid from where it’s declared until the end of its current block – which as you may recall from 121 is denoted by the next closing curly brace }.

Variables declared by some constructs (such as for loops) are only valid within the body of those constructs.

The stack and the heap

When the JVM is executing some code, for example:

int compute(int x) {
  return doubled(x);
}

int doubled(int x) {
  return 2 * x;
}

How does it keep track of which x is which, and how do values move around? I’m going to simplify somewhat here, but essentially there are two regions of memory used to store values (and whose sections are named by variables): the stack and the heap.

As the JVM executes the code, it goes line-by-line, expression-by-expression, evaluating each expression and performing each statement. If someone somewhere called compute(3), the first thing that would happen is the JVM would lay out some memory in the stack for the result of the computation, and for each of the parameters, and for any variables that are in-scope for the whole method (none here, it turns out). Then the parameters would be copied into their spaces. Then the method would start.

Next, doubled(x) would be called. “On top” of the stack, more memory would be layed out, for the return value and for x, which would be copied in. Then doubled would execute, and copy the result into the right spot on the stack. Then control would return to compute, which would copy the value off the top of the stack and into the right spot. And so on. Notice that variables and values are automatically removed/reclaimed on the stack, and that we need only look at the top of the stack to find the current variable and value it holds.

“But Marc,” you might be thinking, “can a value that’s not the return value exists after a method ends?” Yes, those live on the heap, and the JVM is responsible for managing them dynamically via its garbage collection system. We’ll talk about this (again, at a high level) later.

Stack allocation

double quadratic(double a, double b, double x) {
  double firstTerm = 0.0;
  double result = 0.0;

  firstTerm = a + Math.pow(x, 2); // first computation
  result = firstTerm + b; // second computation
  return result;
}

How many doubles worth of space are allocated on the stack in just this method, including the parameters and return value?

Note our use of the Math class and its static method pow to square x.

More administrivia

Some words about assignments and grading.

There will be:

There will not be any graded lecture exercises. I didn’t know whether we’d be in person or remote, nor whether if we were in-person, how closely you could work together. So while I will be happy to interact with you (and I might set up a polling system a la iClickers), nothing graded will typically happen in lecture.

Several things to note:

Lab attendance (and group work – you must work in groups in the lab) is not optional! And lecture attendance is expected.

Assignments (problem sets and programming assignments) have a due date, clearly marked on the course web site. That is when they are due!

However, if you read the syllabus, you will see that there is a two-day, no-penalty extension available for you to grant to yourself for assignments if you need it; the flip side of this extension policy is that we do not accept things after that date. You already had two extra days! The exceptions will be at our discretion and with written documentation to support your reason.

This extension is only for programming assignments and problem sets, nothing else.

There are more details to some of this. I expect you to read the syllabus in its entirety and ask questions if you have them.

If you have an accommodation due to a recognized disability, you need to contact me to tell me if and how you plan to use it (after getting it recognized by Disability Services and having them send me a letter.) In particular, things like extra time on assignments need to be requested in advance of, not after, the due date. Or another example: if you need extra time on the final exam, I need time to figure out how and where you’ll take it.

End of class reminders

Read the Syllabus!

Assignments and their due date will go up on the web site as they become available. This includes the first programming assignment, and the first problem set, both of which are now available!

Suggested reading and lecture notes will also be posted to class web site.

Please ask questions on Campuswire (and check to make sure the question hasn’t already been asked). We’ll get the remaining office hours scheduled soon.

Finally, if you didn’t receive email invitations to CampusWire and/or Gradescope to your @umass.edu email address, please email me and let me know immediately. (This is most likely because you added the class after I did the import into those tools last week.)


Java and control flow

Control flow is the order in which statements in an imperative language are executed. By default, the program starts executing at the main method, and goes line by line, executing a sequence of statements. In Java, this default is overriden in one of several ways:

A method could be invoked. This unconditionally sends the flow of control into that method. Similarly, we can return control from a method to the method that invoked it.

Or, the flow of control could branch conditionally. Most commonly we think of if[/then] and if[/then]/else, but Java also also supports the switch statement as well. Probably you should never use the switch statement – let us never speak of them again! (Well, not much, anyway.)

Or, we could execute a sequence of statements zero, one, or more times, as in the while (or do/while, which we’ll also neglect) or for statements. Within these statements, we might break out of the loop, continue back to the top of the loop, or exit the loop and return from the entire method.

Or, we could throw an exception, unwinding the stack of method calls until either the exception is caught (in other words, control resumes in the exception handler’s except clause) or the main method is reached, in which case the JVM exits and outputs an error message. NullPointerException anyone?

There are a few other ways control flow can by modified, but the above hits most of the highlights.

Let’s talk about each of them in turn.

Method invocation

Method invocations usually looks something like method(parameter1, parameter2), in other words, the name of a method followed by its parameters (either variables or literal values). If there is no preceding variable name, e.g., anObject.method(), the method is resolved first in the context of the current object, then as a static method. Otherwise, the method is resolved in the context of the leading object name. You can also invoke static methods of other classes by prefixing with the class name; more about this in a bit.

return, no matter where it is, exits the current method. For example, you can return from within a loop and the loop will terminate immediately.

Conditional branches

if[/then]/else statements evaluate an expression as a boolean, then branch one way if it is true. If there’s an else, the other way is followed – but with no else and an expression that evaluates to false, the statements are just skipped over.

How does Java delimit which statements are part of the then or else? It executes only the following statement. “But Marc!” Yes, I know, curly braces.

If you enclose a sequence of statements in curly braces, you have created a block. In terms of control flow treats a block as a single statement, so that you can, for example, branch to a sequence of statements after an if. Blocks also serve the purpose of defining a lexical scope, as we mentioned last class.

Speaking of, the fact you don’t need to declare a block using {} after an if statement leads to one of the most common kinds of bugs that we see in first- and second-year programming classes. Students write code that looks like:

x = 5;
if (someCondition)
  x = x + 10;
else
  x = x - 10;
System.out.println(x);

And on its face, that’s fine. The problem is when you later realize you need to modify the stuff that happens on the basis of someCondition to include more statements:

x = 5;
if (someCondition)
  x = x + 10;
else
  x = x - 10;
  x = x * 2
System.out.println(x);

Do you see the problem? Just because you indent the code, and things look like a block, it doesn’t mean they are. Experienced programmers will insert the {} always, so that if later they modify the branch, things work correctly. Many style guides (e.g., Google’s) require this, and IDEs like Visual Studio Code can be set to enforce it (either through warnings or errors, or to just reformat automatically every time you save).

In-class exercise

boolean someCondition = true;
int x = 10;
if (someCondition)
  x = x + 2;
else
  x = x - 2;
  x = x / 2;
System.out.println(x);

What’s the output?

boolean someCondition = false;
int x = 10;
if (someCondition)
  x = x + 2;
else {
  x = x - 2;
  x = x / 2;
}
System.out.println(x);

What’s the output?

A little more on conditionals

So there’s two basic times you might use a conditional. One is when you might want to do a thing, or not. That’s a plain-old if statement.

if (isTime) {
  doTheThing();
}

But sometimes you want to do either one thing, or the other, but not both. That’s if/else.

if (isThingA) {
  doThingA()
} else {
  doTheOtherThing();
}

And sometimes, you want to do one, and only one, of multiple options. That’s a chained series of if-else statements – not just ifs! (Why not just multiple ifs? Because more than one could be, or become true – chained if-elses force only the first matching case to execute.)

if (caseA) {
  doCaseA();
} else if (caseB) {
  doCaseB()
}
} else if (caseC) {
  doCaseC()
} //... etc ...
else {
  // usually a good idea to have a catch-all -- if you should never
  // get here, then make that explicit with an error message
  throw new Exception("Programmer error, shouldn't get here!")
}

You could also use an equivalent switch statement, but they’re basically a footgun (that is, they help you shoot yourself in the foot) and should generally be avoided in Java.

Loops

Sometimes you want a statement to run zero or more times, as the result of a conditional. You want a while loop.

while (someCondition)
  doTheThing();

Of course, in the above example, doTheThing() had better change someCondition at some point, or the loop will never terminate (through normal means, anyway – it could throw an exception or otherwise exit the program, say, via System.exit()).

Also, why don’t we check if someCondition == true? Because we don’t need to: the if statement is checking if the condition is true already; there’s no need to duplicate the code here.

Just like if statement branches, it’s a super-good idea to always enclose loop bodies in a {} delimited block.

Note that there are three other ways, from within a loop, that we can change control flow. If we want to, we can immediately exit a loop with a break statement:

while (true) { // if you ever see this, you better see some way out of the loop, too
  boolean amDone = doTheThing();
  if (amDone) {
    break;
  }
}

In-class exercise

boolean done = false;
int x = 1;
while (!done) {
  x = x * 2;
  if (x > 10)
    break;
}

Will this loop terminate?

Loops, continued

continue returns to the top of the current loop; return exits loops (and the rest of the method!).

In addition, you can use the continue statement to return to the “top” of a loop (in a while, it forces re-evaluation of the condition):

int i = 0;
while (true) {
  i = i + 1;
  if (i < 10) {
    continue;
  }
  System.out.println(i);
  break;
}

This will repeatedly increment i and not reach the println until i == 10; then it will print i and exit the loop. What would happen if we removed the break?

What about this loop? What does it do?

int i = 0;
while (i < 10) {
  if (i % 2 == 0) {
    System.out.println(i);
    continue;
  }
  i = i + 1;
}

for loops

Finally, there’s the for loop.

IMHO, when possible, the best way to use a for loop is with the iterator syntax. Arrays (and more importantly, container types that implement the Iterable interface, support the iterator protocol. If you care about the contents of an array (or any iterable), but not about the indices, then you can use the enhanced for loop.

Suppose you have an array you want to iterate over and do something to, like print its members. You can do it the “old fashioned” way:

int[] array = {1, 3, 3, 7};

for (int i = 0; i < array.length; i++) {
  System.out.println(array[i]);
}

Or you could use the enhanced for loop:

int[] array = {1, 3, 3, 7};

for (int e : array) {
  System.out.println(e);
}

Notably, the enhanced for loop prevents you from making indexing errors – it guarantees that it will visit each element of the array exactly once, assigning it to the iterator variable you provide each time through the loop.

The other way (the “old fashioned” way) is more general: you specify an initial state, a termination condition, and an update statement. Unfortunately this is prone to errors:

void printInts(int[] theInts) {
  for (int i = 0; i <= theInts.length + 1; i++) {
    System.out.println(theInt[i]);
  }
}

See the error(s)? Hard to follow exactly what’s going on with that termination condition, huh?

In-class exercise

int sum(int[] array) {
  int total = 0;
  for (int i = 0; i <= array.length; i++) {
    total = total + array[i];
  }
  return total;
}

What will this method do?

More on for loops

But there are at least two major times when this “old-fashioned” style comes in handy.

The first is when you need access to the index, not just the element.

And the second (which is related) is when you need to compare different elements within the same array. For example, let’s say you wanted to write a method to check if an array of ints was sorted in ascending order. You’d need to make sure each element was less than or equal to the element after it (and make sure you didn’t check anything past the end of the array!):

boolean isSorted(int[] array) {
  for (int i = 0; i < array.length - 1; i++) {
    if (array[i] > array[i + 1]) {
      return false;
    }
  }
  return true;
}

In either style of for loop, you can, just as in while loops, modify the flow of control with break, continue (which performs the update and checks for termination), and return.

There are a few common patterns of for loops you should learn about and master, as they’ll make writing for loops easier for you. We’ve seen some of them already, but let’s talk about patterns. Here they are:

Doing something to every element of an iterable: Suppose we have an array of Things, and we want to doSomething to each one. The enhanced for loop lets us do so in a straightforward manner:

void doAll(Thing[] array) {
  for (Thing t: array) {
    doSomething(t);
  }
}

Testing that everything in an iterable satisfies a property:: Let’s say we want to check if every element in an array is even. The general idea here is to check each element one-by-one. As soon as one thing violates the property (that is, is odd), we can return false. If we get to the end, we can return true:

boolean allEven(int[] array) {
  for (int e : array) {
    if (e % 2 == 1) {
      return false;
    }
  }
  return true;
}

Another example is a linear search, where we scan every element of an iterable and do a thing if an element is found. We do a different thing if it’s not found:

boolean containsValue(int[] array, int value) {
  for (eint e : array) {
    if (e == value) {
      return true;
    }
  }
  return false;
}

The pattern is the same; the test and the return values differ.

Or if we wanted to see if a String contained a particular letter we can iterate over its contents. Probably the easiest way to do this is using the charAt member method of String, as Strings don’t directly support enhanced for loops:

boolean containsChar(String s, char c) {
  for (int i = 0; i < s.length(); i++) {
    if (s.charAt(i) == c) {
      return true;
    }
  }
  return false;
}

Again, the pattern is the same; the test and the return values differ.

Comparing elements in an array for some property: We saw this already in the isSorted method. Here, we cannot easily use the enhanced for loop, since we need access to the index (to check the current against the next value):

boolean isSorted(int[] array) {
  for (int i = 0; i < array.length - 1; i++) {
    if (array[i] > array[i + 1]) {
      return false;
    }
  }
  return true;
}

The pattern is similar to before, but we need to sure we access the right elements of the array, and we need to be careful with bounds. You could rewrite it as:

boolean isSorted(int[] array) {
  for (int i = 1; i < array.length; i++) {
    if (array[i - 1] > array[i]) {
      return false;
    }
  }
  return true;
}

but I find the former more natural.

Exceptions and other abnormal exits

We’ll cover these more later – for the first part of this course, I won’t be asking you to write code in this class that needs to do much with them. We’ll return to them in more detail when the need arises.

End of class reminders, again!

Final exam date is up – Thursday, May 6th, at 4:30pm, here. Mark your calendars now!

Read the syllabus and schedule!

Assignments and their due date will go up on the web site as they become available. This includes the first programming assignment, and the first problem set, both of which are now available!

Suggested reading and lecture notes will also be posted to class web site.

Please ask questions on Campuswire (and check to make sure the question hasn’t already been asked). We’ll get the remaining office hours scheduled soon.

Finally, if you didn’t receive email invitations to CampusWire and/or Gradescope to your @umass.edu email address, please email me and let me know immediately. (This is most likely because you added the class after I did the import into those tools last week.)