96
BASIC CONCEPTS IN JAVA Software Engineering Lecture 1 Annatala Wolf

BASIC CONCEPTS IN JAVA Software Engineering Lecture 1 Annatala Wolf

Embed Size (px)

Citation preview

BASIC CONCEPTSIN JAVASoftware Engineering Lecture 1

Annatala Wolf

Variables• A variable is a name for a piece of data.

• Java variables each have a data type associated with them. Whenever you use a type, the compiler checks to make sure it is compatible with the way you’re using it. Typically this involves matching two types to see if they’re the same. This helps prevent errors in data use.

• There are eight primitive types in Java. These are the simplest and fastest types.

Primitive Types

• We’ll use the four most common primitives:• boolean: can only hold true or false• char: a number that stands for a Unicode character• int: signed integer (up to about +/- two billion)• double: floating-point value (a real number)

Java’s eight primitive types are: boolean, byte, short, char, int, long, float, and double. Most of these hold various integer sizes.

Primitive Literals• Any data that a primitive type can hold can also be

represented as a literal value in code:• boolean: true, false (reserved words in

Java)• char: ‘a’, ‘&’, ‘3’, ‘\t’, ‘\n’, ‘\\’ • int: +3, 0, -56, 15163, -9000• double:0.0, -35.0, 3.14159, +0.000007

• In Java, literals can be used anywhere a declared variable of that type could be used. Note: all literals have a type!• 0 means integer zero and uses integer math• 0.0 means floating-point zero and uses floating-point math

Escape Codes• Since some characters can’t be represented in text

format, the following two-character escape codes represent special literals:• \0 null character (value zero)• \’ single quote• \” double quote• \t tab• \\ backslash

• Beware of using anynewlines or carriagereturns, however…

Line Delimiters• Unfortunately, different platforms (different operating

systems and environments) use different markers to stand for “go to the next line”.• Some use newline ‘\n’, some use carriage return ‘\r’, some both…

• If you want your code to work in any system (which you do if you program in Java!) you need to make a call to a static System method to get the right version.

• But if you use our components, just rely on println() to tack on the correct delimiter for you. Much simpler!

Identifiers*• The names of variables, methods, classes, generic

parameters, and so on are defined by the programmer, in your code. The names we use for all these things are called identifiers.

• Identifiers may contain letters, numbers, and the underscore and dollar-sign characters. However, they may not begin with a number. • The number rule prevents any confusion with int literals.

Choosing Identifier Names*• Over time, programming standards have evolved to

favor descriptive identifiers:

indexnodeCount

getSalary() subsetSumoldTree isDefined()

• Good identifier names are called self-documenting. This means the name itself describes what’s happening in code, so fewer informal comments may be needed.

C/Java Naming Conventions*• Variables and operations use camelCase. Start in

lowercase and capitalize each new word (or initial): hint, i, testRun(), $mLP.

• Class and interface names (and constructors) use UpperCamelCase (start in uppercase).

• Constants (primitive type variables that may not be changed once set) use ALL_CAPS, with words separated by an underscore, unless they are local (in a single operation).

• Templates use a single capital letter: E, K, V.

Bad Identifier Names*• Uninformative names (like these examples) are

generally bad, unless the variable is intended to be highly generic.

tempdoStuff() foo Thing x

• Java Code Conventions recommends against any single-letter variable or operation names!• Two exceptions: i, j, and k (for deterministic

loops only), and c and d (char manipulation).• While this may seem rather extreme, it’s not a

bad practice to adopt.

Identifier Warning*• Much of the code in our library contains what I would consider to be poor choices for identifier names, particularly for method parameters.• In part this is because the program is math-centered,

and in mathematics we commonly user single-letter variables because we can tell them apart from English words in written proofs.

• I strongly advise that you attempt to use more descriptive variable names, as they will make it much easier to trace code and detect errors. Identifiers like base, baseCopy, and power are far better choices than n, temp, and p.

Variable Consistency*• It’s possible to reuse variables for multiple purposes,

but this can be bad if it obscures what the program is actually doing.• A variable named sum should contain a partial or total sum at

all times. If you want an average, make another variable.

for (int i = 0; i < mass.length; i++) { massSum += mass[i];}double meanMass = massSum / (double) mass.length;

You Are NotAn Optimizer*

• But wait; won’t makingextra variables make my program run slower…?

• Almost never! The compiler uses an optimizer that will rewrite your code for efficiency.• The optimizer is smarter than you are when it comes to

organizing code. Inventive tricks rarely improve anything.• There are still a few slowdowns you need to avoid, like

bad algorithmic run-times and excessive file access; but these problems are not fixed by writing dirty code.

• You will never know where the bottlenecks in your program really are until performance testing. So always write for clarity first!

String• String is a reference type (that is, a non-primitive

type) that is part of the default Java language. It gets a bunch of special features that no other reference type does (though arrays also get some special features).• Each String represents a fixed string of characters.

• String is the only reference type that has a literal in code (double-quoted text): “Hello!\t:)”• Notice that escape codes may also appear in String literals.

• String also gets access to two operators (described later) not used by other reference types: + and +=.

What is an “Object”?• Having heard the term “object-oriented programming” you

probably wonder what an object actually is.

• An object is the data you access through a variable of reference type.• Primitive type variables have values you access directly.• Reference type variables are connected to objects. (They can

also be set to connect to “nothing”, in which case they hold the special value called null. We’ll discuss this in detail later on.)

• Objects are more complicated than primitive variable values. We’ll discuss them when we describe instance methods, and much later when we cover references.

Expressions• An expression is a portion of a statement in code that

evaluates to a value when it runs.

• The type of an expression is known at compile-time. If an expression contains incompatible types, it won’t compile.

• There are several kinds of Java expressions:• Variables and literals are the simplest kind: single values.• Function calls are an expression of the type the function returns.• Numeric, boolean, and String values can use special operators to

combine small expressions into much larger expressions.

Numeric Expressions• The operators +, -, *, /, and % (modulus) can combine

expressions of char, int, or double types into larger numeric expressions.

• Expressions have types, just like literals. The type of an expression depends on the types of the values used to compose it. If types are mixed, Java uses the most “precise” type.• int expressions: 3 * 4 count % 5• double expressions: 3 + 2.0 Math.PI * 2

Type Matching• Types in expressions and method calls must match the

expected type. Although numeric types can be automatically converted, this can be dangerous and lead to errors. The compiler will warn you if you’re losing precision with an implicit conversion.

// OK: a char (2 bytes) can fit into an int.int unicodeValueOf_X = ‘X’;

// Java will warn you about this one, however.int uhOh = doubleVar; // DANGER: precision loss!

Magic Numbers

• A magic number is anywhere a numeric literal appears in your code outside of a constant, and one of two things is also true:• It’s not obvious what the value represents.• You use the same value in more than one place.

• It’s “magic” because, well,where did this numbercome from? What inthe hay does it mean?

Magic Number Examples

while (foo < 38) { index = index + 3;}

// This is the Star-Swirl Equation.approx = (4 * oldApprox + 10) % 6;

These two are magic numbers. They are probably copied else-where in code, and no explanation is given.

These three are not magic numbers! They’re only used once, and a comment tells you exactly whatthe numbers mean (they’re part of an equation).

Still, CheckStyle will bitch at you. You can ignore it.

Use Constants Instead• Instead of magic numbers, use constants.

• This reduces dependency to one spot in code!• Usually you must assign a constant on the line you declare it.

// Top of class for class-level stuff.public static final int MAX_WIDTH = 40;

void foo(SimpleWriter out) {

// Here’s a local constant. final int indexJump = 3; for ( int index = 0 ; index < MAX_WIDTH ; ; index += indexJump ) { ...

Expression Safety• Don’t mix types in numeric expressions unless

you have to. (This is a very common source of error.)• For example, the first line below evaluates 1/2 using

integer math (1/2 = 0), then assigns to a double (0.0)!

double derp = 1/2; // derp equals 0.0!double aha = 1.0/2.0; // This one is 0.5.

• Math operators use precedence similar to math: parentheses first, then * and /, then + and -, and left to right if otherwise equal.• However, if in doubt, extra parentheses won’t hurt.

Floating-Point or Integer?*• If your data is discrete, like money (unless you’re

doing financial software where fractions of a penny can exist), it should always be in an integer type.• The fact we use a decimal point to display it has nothing to

do with how it’s stored.

• If you’re ever testing floating-point numbers with ==, your brain has the dumb. You can’t ever expect this to return true (think about why).• Keep in mind that even in limited cases where it might work,

floating-point arithmetic uses estimations that can produce tiny amounts of error. This can ruin your test.

Boolean Expressions• Linking two numeric values with a relational operator

(<, >, <=, >=, ==, !=) produces a boolean expression:

true expressions: 3 <= 5000 1.0 >= 0.0 1 == 1false expressions: 3 == 5000 1.0 < 0.0 1 != 1

• It’s valid to use any sort of numeric expression on either side of a relational operator.• The result is always a boolean expression.

• You can use a boolean expression anywhere you would use a boolean value.• It’s most common to see them in if and while tests.

General Equality Testing• You can also use == and != to turn any two expressions of

the same type (numeric or not) into a boolean expression:

true expressions: true == true 3 != 5false expressions: false == true 3 != 3

• However, you won’t see this done often if the values aren’t integers or booleans. That’s because they are usually only going to work properly for primitive types.• Avoid using == and != with floating-point values (like doubles),

since the odds of an exact match are near zero. Floating-point arithmetic can make small errors due to estimation, so you can’t ever guarantee a match even in seemingly ideal cases.

Not What You Think• When you use the =, ==, and != operators with

reference types, they’re not always doing what you think they are! In other words:• == is not checking “is equal to” for reference types• = is not performing “copy from” for reference types

• The reason for this will be covered in depth later. Just know for now: if you want to test to see if two Strings are equal, you need to use syntax s1.equals(s2) instead of using s1 == s2.• This is a very common error that Java noobs make all the time.

Don’t let it happen to you!

Logical Operators

• The logical operators take boolean expressions and turn them into larger boolean expressions:

not: ! and: && or: ||

true boolean expressions:

!false true && true

false || true !false && 3 > 2

false boolean expressions:

!true true && false

false || false !true || 3 <= 2

String Expressions• Remember when we said String was special?

String (and arrays) are the only reference types that have access to extra operators.• Other than the “basic four” operators: . = == !=

• If + appears next to a String, it turns the other side into a String, and concatenates them to form a new String expression.

• Every primitive type has a String form, and every reference type has a toString() function.• But if you haven’t written toString() for a class, the String

you get will probably be total nonsense.

• Strings can use += in a similar manner.

Shorthand Operators*

• The operators +=, -=, *=, /=, and %= are shorthand for longer statements:

// Short for x = x + 10;x += 10;// It also works for Strings!filename += ".txt";

• You can use ++ and -- to increment/decrement.

// Short for x = x – 1;

x--;

Other Operators*

• There are other ways to use the ++ and -- operators in expressions, but often this leads to code that is difficult to read and understand so in most cases it’s not a good idea. We won’t be using them that way in this course.

• There are also a few other operators used in Java, like bit-shift (a quicker multiply or divide by powers of two) and ternary (an abbreviated if-else operator). Feel free to look these up online, but they won’t be necessary (or useful) in this course.

Long Statements*• There are rare cases when you have a one-line statement

that goes past the printable edge of the IDE window (a guideline on the right). Usually this involves a long method call or String literal.

• If a statement can’t be shortened, use two tabs:

System.out.println(“This is a really long statement” + “ so I am breaking it up at natural points”

+ “ and using two tabs for clarity.”);if (isExample) { // See how the above is distinct from this block.

i++;}

Variable Scope• Local variables are declared inside of a method.

They can be used only in the block of code where they were declared: { }.

• Parameters of a method are created when the method begins, and receive copies of the values that were passed to the method. Parameters can only be used inside the method (covered later in these slides).

• Instance variables and class variables are declared outside of methods. These are different, so we’ll discuss them much later.

Declaring Local Variables• A declaration statement creates a variable:

Type identifier;

• For example, this statement creates a new int variable named jumpCount:

int jumpCount;

• Each local variable “disappears” once it reaches the first unmatched closing brace: }

Declaration Rules• You must declare a local variable before you can use it,

and you can’t use local variable or parameter outside of the block in which it was created.

• Local primitive variables in Java have no default value. Your code will not compile if you try to use a local primitive variable before you store something in it!

• All reference values (other than parameters) have the default value of null (a special value that means “there’s no object here”).

Proper Code Formatting

• It is absolutely essential to format your code for readability: both for others, and yourself.

• Blocks should always be tabbed out.This makes it visually obvious under what conditions a statement in code will run.

• Never cram two statements on the same line. You can do this in Java, but you shouldn’t.

• Even if a block is a single line, use the { }.• A new block { should always end the line.

Narrow Your Scope*• Always restrict variables to the innermost scope where they’re needed. This prevents errors from reusing the wrong variable.

• Below, addend is not being used outside the loop, so we should declare it inside instead.• It will be created each time the loop begins, but the optimizer will

change this for us to improve efficiency.

int total;while (!in.atEOS()) { int addend = in.nextInt(); total += addend;}

Identifier Hiding*• Local variables or parameters can hide

class or instance variables if they are declared with the same name.• You should avoid this for class variables to limit

confusion, but it’s common for instance variables. We’ll cover it when we discuss instance variables.

• Classes in one package can hide classes in another package.• This is okay too! If I write my own String class, I

can still get Java’s String by using its full name: java.lang.String (i.e., the String class found in the java.lang package).

Variable Assignment• The assignment operator is used to copy primitive

values, using the syntax: variable = expression;

foo = 4 * (bar + 3);• Assignment copies the value of the expression on the

right into the variable on the left (destroying its original value). The type of the expression must match the type of the variable, or it won’t compile.

• You can also combine declaration and assignment together into a single statement:

int index = list.length – 1;

Conditional Branching• While the program is running, you can choose what code

to run by branching based on the value of a boolean expression at that point.

• An if statement begins a block that runs if its expression was true. An if-else statement runs the first block if the expression was true, and the second block if it was false.

if (boolExpression) { // This code runs if boolExpression was true.} else { // This code runs if boolExpression was false.}

Nested If Blocks• If blocks can be nested to handle

more complicated conditions:

if (bool1) { if (bool2) { // Runs iff bool1 and bool2 are both true. } else { // Runs iff bool1 is true, but bool2 is false.

}} else { // Runs iff bool1 is false.}

If-Else-If Ladders• It’s often easier to read an if-else-if statement than a set

of nested if blocks. At most one block can possibly run, which is handy. (Exactly one will run if it ends with else.)

if (bool1) { // This runs iff (if and only if) bool1 was true.

} else if (bool2) { // Runs iff bool1 was false and bool2 was true.} else if (bool3) { // Runs iff bool1 & bool2 false, but bool3 true.} else { // Runs iff bool1, bool2, bool3 were all false.}

Successive If Blocks

• However, be careful with successive if blocks, because their conditions will be tested at different times! More than one block may run in a row, even if it’s not immediately obvious.

if (count != 0) { count = 0;}if (count == 0) { // This code always runs!}

Other Branching Statements*• The switch statement allows you to select from a

number of possible sections of code based on the value of a numeric (other than floating-point) or enum type.

• Jump statements interrupt the normal flow of control (that is, the order in which statements normally run).

• We won’t go into much detail on using these because we won’t need to use them. However, I’ll issue some warnings on the dangers of jump statements after we discuss loops.

Do-While*

• The do-while loop is a variant while loop that always runs at least once.

• Do-while makes it a bit harder to see the loop condition, so I tend to avoid using it unless it’s particularly useful.

do { // this block runs at least once} while (booleanExpression);

Loops (Iteration)• If you want to do something multiple times in a row,

you need a loop. Java has four kinds:

The for loop and while loop are the most common, and used in different situations.

The do-while loop is just a variant on while. It makes code harder to read, so we’ll discuss it in best practices.

The for-each loop is special, so we’ll cover it in a later lecture.

While Loop• A while loop’s block is identical to an if block, except

the condition gets checked again at the end of the loop. It will continue to run until the expression is false when checked.

while (booleanExpression) { // loop statements go here}

• Use a while loop for any loop with a condition too complex for a for loop to easily handle.

For Loop• A for loop is shorthand for an equivalent while loop. For loop use should be restricted to loops that work well with simple counters that increment or decrement on every step.

for (initStatement ; boolExpression ; incStatement) {

// loop statements go here}

• The semicolons are just used to separate the three parts; they’re not being used as end-of-statement markers here (e.g. one follows the boolean expression, but not the increment).

Variables In Loops• If you declare a variable within the body of a loop, it

will be created fresh on each iteration. Each time you hit the closing brace, it disappears. If you need a value to persist, you must create it outside the loop.

• If you use a for loop, and your initialization statement creates a variable, this variable will only be created once and persist throughout the loop. However, when the loop finishes its last iteration, it will then disappear.

Loop Equivalence*for (initStmt ; boolExpression ; incStatement) { LOOP_STATEMENTS}

{

initStmt; while (boolExpression) { LOOP_STATEMENTS incStatement; }}

These two sections of code are semantically equivalent: they always produce the same results with the same efficiency.

This extra anonymous block is needed to limit the scope of any variables declared in initStmt. In the for loop, initStmt is only run once before the loop begins so it can be used as a counter,

but any variables declared there go away when the loop ends.

Nesting Blocks• Just as you can nest branching blocks, you can nest

loops and branches within loops.

• Variables declared in an outer scope can be detected

and used in an inner scope, but not vice versa.

// Output all values in the names array.for (int index = 0; index < names.length; index++) { out.print(names[index]); if (index != names.length – 1) { out.print(“, ”); }}

Nesting (finish)• Nesting loops within loops can be computationally

expensive!

• (example goes here)

Breaking (Is) Bad*

These statements are highly discouraged because they make it much harder to see at a glance the conditions for which code will run.

Jump statements often lead to errors in code when code is modified later.

If you think you need one, you should probably rethink your loop condition.

Be very careful using jump statements like break and continue!

Break Example* (need fix example)/* This code should remove one red widget from store. */WidgetStore widgetsSeen = new WidgetStore2();while (store.hasStuff()) { Widget widget = store.removeFirst(); if (widget.isRed()) { break; } widgetsSeen.addBack(widget);}

// Wait. What if we didn’t remove all widgets from store?store = widgetsSeen; // Uh-oh...

Break Removed* (also fix here)/* This code should remove one red widget from store. */WidgetStore widgetsSeen = new WidgetStore2();boolean foundRed = false;while (store.hasStuff()) { Widget widget = store.removeFirst(); if (widget.isRed() and !foundRed) { foundRed = true; } else { widgetsSeen.addBack(widget); }}store = widgetsSeen;

Other Options*• Another way to prevent break statements if you have a

counter and don’t need to iterate the whole way: set the counter to the end. Let the loop condition handle it.

hasDigit = false;for (int i = 0 ; i < name.length() ; i++) { if ( Character.isDigit(name.charAt(i)) ) { hasDigit = true; i = name.length(); }} Instead of this, I might decide to use a boolean flag:

while (i < name.length() and !hasDigit) {Either method is safer than using break: if you add code

to the end of the loop, it will still run on each iteration.

Early Return• A similar issue is writing a procedure with a return

statement, or a function that returns early.

• Remember, as soon as you hit the return statement, the method stops.

• While this might work for small code, as code grows in size it can lead to errors that can be missed in testing. It’s safer if methods have a single exit point.

Early Return Example (need to fix)/** True iff store has any red widgets in it. */boolean hasRedThing(WidgetStore store) { if (store.hasStuff()) { Widget widget = store.removeFirst(); if (widget.isRed()) { return true; } else { return hasRedThing(store); } store.addBack(widget); // Unreachable code! } return false;}

Early Return Removed (fix here)/** True iff store has any red widgets in it. */boolean hasRedThing(WidgetStore store) { boolean answer = false; if (store.hasStuff()) { Widget widget = store.removeFirst(); if (widget.isRed()) { answer = true; } else { answer = hasRedThing(store); } store.addBack(widget); } return answer;}

More Return Confusionvoid setParcelClass(double size, double weight) { if (size > 45.0) { setScale(Parcel.HIGH); } else if (size < 6.5) { if (weight > 50.0) { setScale(Parcel.MEDIUM); } else { setScale(Parcel.VARIES); return; } } if (size < 4.5 && weight < 20.0) { // This line of code can never run! setFlag(Parcel.SPECIAL_POST); }}

Error or Style Choice?

• Remember, practices likereturning in the middle of anoperation are not errors! They’restyle choices that may lead to errorsif they are abused or embedded in large segments of code.

• Even in cases where they might be useful or acceptable, it’s good programming practice to rewrite them for clarity.

Program State*

• The state of a program can mean many things, but the most common meaning is a snapshot of:• Which line of code is running?• What are the values of all variables in memory?

• When you write code, you’re always thinking about what will happen to the program state as each line of your code executes.• This can get complicated in a hurry, though!

Tracing Code• Tracing code is a step-by-step process where you

determine what the program state will be, just as if you were the computer.

• Tracing is typically used to identify logical bugs. You know where a problem is by when the value of your variables first differs from what you expected.

• When you trace most statements, you apply the effects from the previous state to get the next state. When you trace method calls, however, you should think in terms of the method contract. We’ll discuss this later, when we begin to discuss specifications.

Tracing Table ExampleCode Program State

index = 2

while (index < 10) {

index = 2 index = 4 index = 8

int weird;

index = 2weird = undef.

index = 4weird = undef.

index = 8weird = undef.

weird = plusPrm(index);

index = 2weird = 5

index = 4weird = 9

index = 8weird = 19

index = weird – 1;

index = 4weird = 5

index = 8weird = 9

index = 18weird = 19

}

index = 18

Tracing Table ExampleCode Program State

index = 2

while (index < 10) {

index = 2 index = 4 index = 8

int weird;

index = 2weird = undef.

index = 4weird = undef.

index = 8weird = undef.

weird = plusPrm(index);

index = 2weird = 5

index = 4weird = 9

index = 8weird = 19

index = weird – 1;

index = 4weird = 5

index = 8weird = 9

index = 18weird = 19

}

index = 18

Code and program states are interleaved, like this. Every variable needs to be included when we describe program

state, even if it hasn’t changed.

Tracing Table ExampleCode Program State

index = 2

while (index < 10) {

index = 2 index = 4 index = 8

int weird;

index = 2weird = undef.

index = 4weird = undef.

index = 8weird = undef.

weird = plusPrm(index);

index = 2weird = 5

index = 4weird = 9

index = 8weird = 19

index = weird – 1;

index = 4weird = 5

index = 8weird = 9

index = 18weird = 19

}

index = 18 We figure out what these lines will do by

calculating their effect on state, step by step.

Tracing Table ExampleCode Program State

index = 2

while (index < 10) {

index = 2 index = 4 index = 8

int weird;

index = 2weird = undef.

index = 4weird = undef.

index = 8weird = undef.

weird = plusPrm(index);

index = 2weird = 5

index = 4weird = 9

index = 8weird = 19

index = weird – 1;

index = 4weird = 5

index = 8weird = 9

index = 18weird = 19

}

index = 18

To figure out what a method call does, use its contract. This traces it in a single step.

We’ll come back to this in a later lecture so we can see

how to do it properly.

Tracing Table ExampleCode Program State

index = 2

while (index < 10) {

index = 2 index = 4 index = 8

int weird;

index = 2weird = undef.

index = 4weird = undef.

index = 8weird = undef.

weird = plusPrm(index);

index = 2weird = 5

index = 4weird = 9

index = 8weird = 19

index = weird – 1;

index = 4weird = 5

index = 8weird = 9

index = 18weird = 19

}

index = 18

To trace a loop completely, you must trace all iterations.

Tracing Table ExampleCode Program State

index = 2

while (index < 10) {

index = 2 index = 4 index = 8

int weird;

index = 2weird = undef.

index = 4weird = undef.

index = 8weird = undef.

weird = plusPrm(index);

index = 2weird = 5

index = 4weird = 9

index = 8weird = 19

index = weird – 1;

index = 4weird = 5

index = 8weird = 9

index = 18weird = 19

}

index = 18Careful! Don’t miss

any places a variable appears or

disappears.

Subroutines (i.e. Methods)• All subroutines in Java are called methods. (“Method” means “a subroutine defined inside a class”, and everything in Java is defined inside a class.)

• In most Java programs,nearly all the code youwrite will be in methods.

How Methods Work• A method is a small module of code.• The method is defined inside of a class somewhere. Its method header includes a list of parameters: data types you’ll pass it.

• When you use the name of the method in code, you’re said to be calling (or invoking) the method. This call must be followed by a list of the data you’re passing it (if any).

• The code that calls a method pauses and waits for it to return (finish); then it resumes.

Method Examplespublic static void main() (String args[]) { multiPrint(“Hello, world!”, 20); // calls multiPrint()}

/** * Prints line times number of times, on separate lines. * * @param line the String to be printed * @param times number of times to print line */public static void multiPrint() (String line, int times) { for (int i = 0; i < times; i++) { System.out.println(line); }}

Method Examples (need to format)public static void main() (String args[]) {

multiPrint(“Hello, world!”, 20); // calls multiPrint()

}

/**

* Prints line times number of times, on separate lines.

*

* @param line the String to be printed

* @param times number of times to print line

*/

public static void multiPrint() (String line, int times) {

for (int i = 0; i < times; i++) {

System.out.println(line);

}

}

An method call (invocation).A method header. It

includes return type, name, and parameter list.

A method body (its definition).

Method Signatures*• A method signature is the basic information the compiler

needs to know which method a call refers to. It’s much like the method header, except it only includes the name of the method and the types of its parameters.

• For example, the signature for main() is:

main(String[])

• The method header for main() includes all of the details, except for its code (i.e., not the method body):

public static void main(String[] args)

Method Overloading

• If two methods in the same class have different signatures, then they are different methods, even if they have the same name.

• Making different methods in the same class with the same name is called method overloading. (Don’t confuse it with method overriding, which is rewriting a method’s code—discussed later.)

• For example, SimpleWriter1L has two constructor methods: one that takes no arguments, and another that takes a String. The compiler will call the one that matches the arguments you pass it.

Overloading Example*• Overloading is permitted as long as the compiler can tell

signatures apart. (Signatures don’t include return type.)

public static void foo()… public static char foo(int bar)… public static int foo(int bar, String baz)… public static int foo(String baz, int bar)… public static int foo()…

The last one is illegal. The compiler can’t tell void foo() from int foo() when a call is made, as they both take the same parameters in the same order.

Static Methods• Most of the methods you’ve seen so far have been static methods. Static methods are always available to be called (if they’re public). You call them like this:

ClassName.staticOpInThatClass(params);

• The reason you haven’t seen this syntax is that we’ve been calling static methods from within the same class. In that case, we can leave off the Classname. part.

Static Method Example• The String class has a static function called valueOf(int value), which returns a String. You might call it like this:

String intVal = String.valueOf(25);• The code above would store the String object “25”

with the variable intVal.

• However, remember that we don’t need to create a String object to use a static method of String. Static methods are always accessible.

doSomething(String.valueOf(17));

Instance Methods• Unlike a static method, you cannot call an instance

method until you have an object of the type you want to call it from.

• The object you call an instance method from is called the distinguished parameter. It’s just like the other parameters, except it appears before the call:

distinguishedObject.instanceOp(params);

Instance Method Example• The String class has an instance function called trim().

You could call it like this:

String paddedName = “ Applejack ”;String name = paddedName.trim();

• Here, paddedName is a String object. This makes a new String object without the leading/trailing whitespace (“Applejack”) and stores it in name.

Note the Difference• The difference here is important. You can’t call an instance method of the String class unless you first have created a String object. A static method you can call at any time, though it may still require other parameter objects.

• Instance methods are usually used to provide us with a public interface: a safe way to access the data that an object represents. By letting the object handle how it can be accessed, it’s easier to use the object safely.

Parameter Passing• The values you pass to a

method are copied into that method’s parameter variables.

The formal parameters (or just parameters) are the variables created when an method begins, as declared in the method header.

The actual parameters (or arguments) are the variables, literals, or expressions you pass to an method when you call it.

Parameter Examples (fix)public static void main() (String args[]) {

multiPrint(“Hello, world!”, 20); // calls multiPrint()

}

/**

* Prints line times number of times, on separate lines.

*

* @param line the String to be printed

* @param times number of times to print line

*/

public static void multiPrint() (String line, int times) {

for (int i = 0; i < times; i++) {

System.out.println(line);

}

}

Actual parameters (arguments). These can be expressions.

Parameters passed in must match the types

in the same order.

Formal parameters (or just parameters).

These are always variables. They get

created when the method starts, and

receive copies of the actual parameters.

Passing Illustrated

TODO

Tracing Over Calls• TODO

Functions• A function is a method that returns a value to the

place where it was called from.• When you call a function, the function call itself is an

expression of the type it returns. Because of this, functions are usually embedded in larger expressions.• If you don’t do this, you’re just throwing away the value the

function worked to produce!

• Functions should generally restore their arguments. We’ll discuss this in best practice.

Function Example (fix)public static void main() (String args[]) {

if (totalLength(args) > 50) { System.out.print(“Argument list too long!”);

}}

/**

* Function to return total length of all Strings in array.

*/public static boolean totalLength(String array[]) {

int result = 0; for (int index = 0; index < array.length; index++) {

result += array[index].length();

} return result;

}

Function Example (fix)public static void main() (String args[]) {

if (totalLength(args) > 50) { System.out.print(“Argument list too long!”);

}}

/**

* Function to return total length of all Strings in array.

*/public static boolean totalLength(String array[]) {

int result = 0; for (int index = 0; index < array.length; index++) {

result += array[index].length();

} return result;

}

Function calls appear in expressions so we can use the return value.

Holy road apples! It’s another function call.

This is a function because its return type is not void.

Any return statement immediately ends the function.

Procedures• In contrast, procedures are methods that don’t return a

value. They have return type void, which just means “no return type”.

• As a result, procedure calls always appear as a single statement, rather than part of an expression.

• Since procedures are deliberately called on a line by themselves with no value expected back, most procedures will change the values of the arguments you pass to them.

Procedure Example (fix)• TODO

Arrays

• Arrays are a special data structure built into Java.• Any array is a parameterized type: you have to

declare what type of data you want the array to hold when you declare the array.

• An array is a indexed string of Type, where Type is the type you selected when you declared the array.• (Note this is a mathematical string, not a Java String.)

• Arrays are reference types, even if the type of data they hold is a primitive type. They begin with the value null. You have to call new or use array initialization to make an array object.

Why Use Arrays?• Arrays aren’t very versatile. They do come with a means

for initializing them, but this isn’t always handy.

• So why use them at all? Arrays are designed to be very, very fast for data access. They’re useful when:• You only need a simple structure for holding a string of data.• You know exactly how many entries you need the string to hold.• You’re not using generics (we’ll discuss these later).

• Unlike all other types, arrays have a special syntax for creation as well as for calling array functions.

Array Declaration

• There are two ways to declare arrays in Java. This is the preferred (more common and less confusing) method:

int[] size; // declares an int array

• This one is not preferred, but it does the same thing:

int size[]; // same thing as above

Array Creation• To create an array object, you have to call new.• Notice that you don’t use ( ) to call the array’s constructor!

Instead, use [ ] to specify how long the array should be.

final int thingNum = 8;int[] size;size = new int[thingNum];

• This makes the following array, with default values for int:

0

size[0]

0

size[1]

0

size[2]

0

size[3]

0

size[4]

0

size[5]

0

size[6]

0

size[7]

Warning…• Creating an array of reference type values does not create

any objects of that type. Rather, it sets all of the references to null. You’ll need to create the objects separately.

• Here’s an example, using a combined declaration and array creation:

// Makes an array of SimpleReaders, but does// not make any SimpleReader objects yet!SimpleReader[] file = new SimpleReader[4];

null

file[0]

null

file[1]

null

file[2]

null

file[3]

Using Arrays• Arrays only come with two abilities.• Arrays are indexed from 0 to |array|-1. The [ ] operator

gives you the entry at that index:

int[] volume = new int[100];volume[99] = 3; // use last value in array

• The second ability is to check the length of the array. For speed, it’s not a function call. You access the value directly (but it cannot be changed).

out.print(volume.length); // prints “100”

Array Creation With Initializer• You can automatically create the array and assign its

elements in a single step.

• TODO