Detailed Table of Contents
Guidance for the item(s) below:
While you can (and will be) defining your own classes, Java comes with a whole bunch of built-in classes that you can use right-away. Let's learn about some of the most useful such built-in classes next.
Can use Java API documentation about classes
Java comes with a rich collection of classes that you can use. They form what is known as the Java API (Application Programming Interface). Each class in the API comes with documentation in a standard format.
Can use the String class
String is a built-in Java class that you can use without importing. Given below are some useful String methods:
Strings provide a method named charAt
, which extracts a character. It returns a char
, a primitive type that stores an individual character (as opposed to strings of them).
String fruit = "banana";
char letter = fruit.charAt(0);
The argument 0 means that we want the letter at position 0. Like array indexes, string indexes start at 0, so the character assigned to letter
is 'b'
.
You can convert a string to an array of characters using the toCharArray
method.
char[] fruitChars = fruit.toCharArray()
Strings provide methods, toUpperCase
and toLowerCase
, that convert from uppercase to lowercase and back.
After these statements run, upperName
refers to the string "ALAN TURING"
but name
still refers to "Alan Turing"
.
String name = "Alan Turing";
String upperName = name.toUpperCase();
System.out.println(name);
System.out.println(upperName);
Alan Turing
ALAN TURING
Note that a string method cannot change the string object on which the method is invoked, because strings are . For example, when you invoke toUpperCase
on a string "abc"
, you get a new string object "ABC"
as the return value rather than the string "abc"
being changed to "ABC"
. As a result, for such string methods that seemingly modify the string but actually return a new string instead e.g., toLowerCase
, invoking the method has no effect if you don’t assign the return value to a variable.
String s = "Ada";
s.toUpperCase(); // no effect
s = s.toUpperCase(); // the correct way
Another useful method is replace
, which finds and replaces instances of one string within another.
This example replaces "Computer Science"
with "CS"
.
String text = "Computer Science is fun!";
text = text.replace("Computer Science", "CS");
System.out.println(text);
CS is fun!
The substring
method returns a new string that copies letters from an existing string, starting at the given index.
"banana".substring(0)
"banana"
"banana".substring(2)
"nana"
"banana".substring(6)
""
If it’s invoked with two arguments, they are treated as a start and end index:
"banana".substring(0, 3)
"ban"
"banana".substring(2, 5)
"nan"
"banana".substring(6, 6)
""
The indexOf
method searches for a single character (or a substring) in a string and returns the index of the first occurrence. The method returns -1
if there are no occurrences.
"banana".indexOf('a')
1
"banana".indexOf('a', 2)
3
searches for 'a'
, starting from position 2"banana".indexOf('x')
-1
"banana".indexOf("nan")
2
searches for the substring "nan"
To compare two strings, it is tempting to use the ==
and !=
operators.
String name1 = "Alan Turing";
String name2 = "Alan Turing";
System.out.println(name1 == name2);
This code compiles and runs, and most of the time it shows true
. But it is not correct. The problem is, , the ==
operator checks whether the two variables refer to the same object (by comparing the references). If you give it two different string objects that contain the same letters, it is supposed to yield false
because they are two distinct objects even if they contain the same text. However, because Java strings are immutable, in some cases (but not always) Java reuses existing string objects instead of creating multiple objects, which can cause the above code to yield true
. Therefore, it is not safe to use ==
to compare strings if your intention is to check if they contain the same text.
The right way to compare strings is with the equals
method.
This example invokes equals
on name1
and passes name2
as an argument. The equals
method returns true
if the strings contain the same characters; otherwise it returns false
.
if (name1.equals(name2)) {
System.out.println("The names are the same.");
}
If the strings differ, you can use compareTo
to see which comes first in alphabetical order. The return value from compareTo
is the difference between the first characters in the strings that differ. If the strings are equal, their difference is zero. If the first string (the one on which the method is invoked) comes first in the alphabet, the difference is negative. Otherwise, the difference is positive.
In this example, compareTo
returns positive 8, because the second letter of "Alan" comes 8 letters after the second letter of "Ada".
String name1 = "Alan";
String name2 = "Ada";
int diff = name1.compareTo(name2);
if (diff == 0) {
System.out.println("The names are the same.");
} else if (diff < 0) {
System.out.println("name1 comes before name2.");
} else if (diff > 0) {
System.out.println("name2 comes before name1.");
}
Both equals
and compareTo
are case-sensitive. The uppercase letters come before the lowercase letters, so "Ada"
comes before "ada"
. To check if two strings are similar irrespective of the differences in case, you can use the equalsIgnoreCase
method.
String s1 = "Apple";
String s2 = "apple";
System.out.println(s1.equals(s2)); //false
System.out.println(s1.equalsIgnoreCase(s2)); //true
Some more comparison-related String
methods:
contains
: checks if one string is a sub-string of the other e.g., Snapple
and app
startsWith
: checks if one string has the other as a substring at the beginning e.g., Apple
and App
endsWith
: checks if one string has the other as a substring at the end e.g., Crab
and ab
You can embed a special character e.g., line break, tab, backspace, etc. in a string using an escape sequence.
Escape sequence | meaning |
---|---|
\n | newline character |
\t | tab character |
\b | backspace character |
\f | form feed character |
\r | carriage return character |
\" | " (double quote) character |
\' | ' (single quote) character |
\\ | \ (back slash) character |
\uDDDD | character from the Unicode character set, by specifying the Unicode as four hex digits in the place of DDDD |
An example of using escape sequences to print some special characters.
System.out.println("First line\nSecond \"line\"");
First line
Second "line"
As the behavior of the \n
, the recommended way to print a line break is using the System.lineSeparator()
as it works the same in all platforms.
Using System.lineSeparator()
to print a line break.
System.out.println("First" + System.lineSeparator() + "Second");
First
Second
Sometimes programs need to create strings that are formatted in a certain way. String.format
takes a format specifier followed by a sequence of values and returns a new string formatted as specified.
The following method returns a time string in 12-hour format. The format specifier \%02d
means “two digit integer padded with zeros”, so timeString(19, 5)
returns the string "07:05 PM"
.
public static String timeString(int hour, int minute) {
String ampm;
if (hour < 12) {
ampm = "AM";
if (hour == 0) {
hour = 12; // midnight
}
} else {
ampm = "PM";
hour = hour - 12;
}
// returns "07:05 PM"
return String.format("%02d:%02d %s", hour, minute, ampm);
}
Implement the printPrice
method in the code below to produce the given output. Its behavior:
item
is a string in the format name--$price
i.e., a name and a price of an item separated using a --
e.g., banana--$3/50
NAME: price
where the name is in upper case. The price does not have a $
sign and has .
in place of the /
banana--$3/50
BANANA: 3.50
name
part of the input can have trailing/leading spaces which should be omitted from the output.
banana --$3/50
BANANA: 3.50
Do a Web search to find how to remove leading/trailing spaces. Suggested search terms java string remove leading trailing spaces
public class Main {
public static void printPrice(String item) {
// TODO: add your code here
}
public static void main(String[] args) {
printPrice("sandwich --$4/50");
printPrice(" soda --$10/00");
printPrice(" fries --$0/50");
}
}
SANDWICH: 4.50
SODA: 10.00
FRIES: 0.50
Hint
Can use wrapper classes for primitive
Primitive values (like int
, double
, and char
) do not provide methods.
For example, you can’t call equals
on an int
:
int i = 5;
System.out.println(i.equals(5)); // compiler error
But for each primitive type, there is a corresponding class in the Java library, called a wrapper class, as given in the table below. They are in the java.lang
package i.e., no need to import.
Primitive type | Wrapper class |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
Double d = new Double(2.5);
int i = d.intValue();
System.out.println(d);
System.out.println(i);
2.5
2
Each wrapper class defines constants MIN_VALUE
and MAX_VALUE
.
Accessing max and min values for integers:
System.out.println(Integer.MIN_VALUE + " : " + Integer.MAX_VALUE);
-2147483648 : 2147483647
Wrapper classes provide methods for strings to other types e.g., Integer.parseInt
converts a string to (you guessed it) an integer. The other wrapper classes provide similar methods, like Double.parseDouble
and Boolean.parseBoolean
.
Integer.parseInt("1234")
1234
Wrapper classes also provide toString
, which returns a string representation of a value.
Integer.toString(1234)
"1234"
Implement the printTotalScore
method in the code below to produce the given output. Its behavior:
values
is an array of strings, each string representing an integer e.g., ["5", "-1"]
["5", "-1"]
4
public class Main {
public static void printTotalScore(String[] values){
// TODO: add your code here
}
public static void main(String[] args) {
printTotalScore(new String[]{});
printTotalScore(new String[]{"0", "124", "-15"});
}
}
0
109
Can use the Arrays class
java.util.Arrays
provides methods for working with arrays. One of them, toString
, returns a string representation of an array. It also provides a copyOf
that copies an array.
Using Arrays.copyOf
and Arrays.toString
:
int[] a = new int[]{1,2,3,4};
int[] b = Arrays.copyOf(a, 3); // copy first three elements
System.out.println(Arrays.toString(b));
int[] c = Arrays.copyOf(a, a.length); // copy all elements
System.out.println(Arrays.toString(c));
[1, 2, 3]
[1, 2, 3, 4]
Implement the following two methods in the code below to produce the given output.
filterEmails(String[] items): String[]
items
is an array of strings each of which may be an email address or some other random stringString[]
containing email addresses that were in items
. Any string containing @
is considered as an email.["aaa@bbb", "xyz"]
["aaa@bbb"]
printItems(String[] items)
items
in the standard array format. e.g., ["aaa", "bbb"]
[aaa, bbb]
import java.util.Arrays;
public class Main {
public static String[] filterEmails(String[] items){
// TODO: add your code here
}
public static void printItems(String[] items){
// TODO: add your code here
}
public static void main(String[] args) {
printItems(filterEmails(new String[]{}));
printItems(filterEmails(new String[]{"abc"}));
printItems(filterEmails(new String[]{"adam@example.com", "aab", "john@example.com", "some@"}));
printItems(filterEmails(new String[]{"xyz", "@bee.com", "aab"}));
}
}
[]
[]
[adam@example.com, john@example.com, some@]
[@bee.com]
Hint
Can use the Scanner class
Scanner
is a class that provides methods for inputting words, numbers, and other data. Scanner
provides a method called nextLine
that reads a line of input from the keyboard and returns a String. The following example reads two lines and repeats them back to the user:
import java.util.Scanner;
public class Echo {
public static void main(String[] args) {
String line;
Scanner in = new Scanner(System.in);
System.out.print("Type something: ");
line = in.nextLine();
System.out.println("You said: " + line);
System.out.print("Type something else: ");
line = in.nextLine();
System.out.println("You also said: " + line);
}
}
Scanner
class normally reads inputs as strings but it can read in a specific type of input too.
The code below uses the nextInt
method of the Scanner
class to read an input as an integer.
Scanner in = new Scanner(System.in);
System.out.print("What is your age? ");
int age = in.nextInt();
in.nextLine(); // read the new-line character that follows the integer
System.out.print("What is your name? ");
String name = in.nextLine();
System.out.printf("Hello %s, age %d\n", name, age);
Write a program to ask the user for a description of overseas expenses (presumably, the user has just returned from an overseas trip) and calculate the total in local currency.
$1.0
= local $1.70
$amount
e.g., $1.50
Here is one example output:
Your expenses while overseas?beer $4.50 books $3.00 $5.00 for food, that's all
Expenses in overseas currency:[$4.50, $3.00, $5.00]
Total in local currency: $21.25
Here is another:
Your expenses while overseas?nothing. I lived off my friends all the time.
Expenses in overseas currency:[]
Total in local currency: $0.00
One more:
Your expenses while overseas? Just $10
Expenses in overseas currency:[$10]
Total in local currency: $17.00
Here's the skeleton code to use as the starting point:
public class Main {
// You can add more methods here
public static void main(String[] args) {
String line;
Scanner in = new Scanner(System.in);
System.out.print("Your expenses while overseas?");
// TODO: add your code here
}
}
You can use the split
method of the String
class to convert a sentence into an array of words. e.g.,
String sentence = "hello my dear";
// split using the space as the delimiter
String[] words = sentence.split(" ");
System.out.println(Arrays.toString(words));
[hello, my, dear]
Hint
Guidance for the item(s) below:
Having learned how to use Git in your own computer, let's also learn a bit about working with remote code repositories too.
Can explain remote repositories
Remote repositories are repos that are hosted on remote computers and allow remote access. They are especially useful for sharing the revision history of a codebase among team members of a multi-person project. They can also serve as a remote backup of your codebase.
It is possible to set up your own remote repo on a server, but the easier option is to use a remote repo hosting service such as GitHub or BitBucket.
You can clone a repo to create a copy of that repo in another location on your computer. The copy will even have the revision history of the original repo i.e., identical to the original repo. For example, you can clone a remote repo onto your computer to create a local copy of the remote repo.
When you clone from a repo, the original repo is commonly referred to as the upstream repo. A repo can have multiple upstream repos. For example, let's say a repo repo1
was cloned as repo2
which was then cloned as repo3
. In this case, repo1
and repo2
are upstream repos of repo3
.
You can pull from one repo to another, to receive new commits in the second repo, if the repos have a shared history. Let's say some new commits were added to the after you cloned it and you would like to copy over those new commits to your own clone i.e., sync your clone with the upstream repo. In that case, you pull from the upstream repo to your clone.
You can push new commits in one repo to another repo which will copy the new commits onto the destination repo. Note that pushing to a repo requires you to have write-access to it. Furthermore, you can push between repos only if those repos have a shared history among them (i.e., one was created by copying the other at some point in the past).
Cloning, pushing, and pulling can be done between two local repos too, although it is more common for them to involve a remote repo.
A repo can work with any number of other repositories as long as they have a shared history e.g., repo1
can pull from (or push to) repo2
and repo3
if they have a shared history between them.
A fork is a remote copy of a remote repo. As you know, cloning creates a local copy of a repo. In contrast, forking creates a remote copy of a Git repo hosted on GitHub. This is particularly useful if you want to play around with a GitHub repo but you don't have write permissions to it; you can simply fork the repo and do whatever you want with the fork as you are the owner of the fork.
A pull request (PR for short) is a mechanism for contributing code to a remote repo, i.e., "I'm requesting you to pull my proposed changes to your repo". For this to work, the two repos must have a shared history. The most common case is sending PRs from a fork to its repo.
Here is a scenario that includes all the concepts introduced above (click inside the slide to advance the animation):
Project Management → Revision Control → Remote Respositories
Can clone a remote repo
Given below is an example scenario you can try yourself to learn Git cloning.
Suppose you want to clone the sample repo samplerepo-things to your computer.
Note that the URL of the GitHub project is different from the URL you need to clone a repo in that GitHub project. e.g.
GitHub project URL: https://github.com/se-edu/samplerepo-things
Git repo URL: https://github.com/se-edu/samplerepo-things.git
(note the .git
at the end)
File
→ Clone / New…
and provide the URL of the repo and the destination directory.
Tools → Git & GitHub → Clone
Can pull changes from a repo
Here's a scenario you can try in order to learn how to pull commits from another repo to yours.
1. Clone a repo (e.g., the repo used in [Git & GitHub → Clone]) to be used for this activity.
2. Delete the last few commits to simulate cloning the repo a few commits ago.
Right-click the target commit (i.e. the commit that is 2 commits behind the tip) and choose Reset current branch to this commit
.
Choose the Hard - …
option and click OK
.
This is what you will see.
Note the following (cross refer the screenshot above):
Arrow marked as a
: The local repo is now at this commit, marked by the master
label.
Arrow marked as b
: The origin/master
label shows what is the latest commit in the master
branch in the remote repo.
Use the reset
command to delete commits at the tip of the revision history.
git reset --hard HEAD~2
Now, your local repo state is exactly how it would be if you had cloned the repo 2 commits ago, as if somebody has added two more commits to the remote repo since you cloned it.
3. Pull from the other repo: To get those missing commits to your local repo (i.e. to sync your local repo with upstream repo) you can do a pull.
Click the Pull
button in the main menu, choose origin
and master
in the next dialog, and click OK
.
Now you should see something like this where master
and origin/master
are both pointing the same commit.
git pull origin
You can also do a fetch
instead of a pull
in which case the new commits will be downloaded to your repo but the working directory will remain at the current commit. To move the current state to the latest commit that was downloaded, you need to do a merge
. A pull
is a shortcut that does both those steps in one go.
When you clone a repo, Git automatically adds a remote repo named origin
to your repo configuration. As you know, you can pull commits from that repo. As you know, a Git repo can work with remote repos other than the one it was cloned from.
To communicate with another remote repo, you can first add it as a remote of your repo. Here is an example scenario you can follow to learn how to pull from another repo:
Open the local repo in SourceTree. Suggested: Use your local clone of the samplerepo-things
repo.
Choose Repository
→ Repository Settings
menu option.
Add a new remote to the repo with the following values.
Remote name
: the name you want to assign to the remote repo e.g., upstream1
URL/path
: the URL of your repo (ending in .git
) that. Suggested: https://github.com/se-edu/samplerepo-things-2.git
(samplerepo-things-2
is another repo that has a shared history with samplerepo-things
)Username
: your GitHub usernameNow, you can fetch or pull (pulling will fetch the branch and merge the new code to the current branch) from the added repo as you did before but choose the remote name of the repo you want to pull from (instead of origin
):
Click the Fetch
button or the Pull
button first.
If the Remote branch to pull
dropdown is empty, click the Refresh
button on its right.
If the pull from the samplerepo-things-2
was successful, you should have received one more commit into your local repo.
Navigate to the folder containing the local repo.
Set the new remote repo as a remote of the local repo.
command: git remote add {remote_name} {remote_repo_url}
e.g., git remote add upstream1 https://github.com/johndoe/foobar.git
Now you can fetch or pull (pulling will fetch the branch and merge the new code to the current branch) from the new remote.
e.g., git fetch upstream1 master
or git pull upstream1 master
Tools → Git & GitHub → Pull
Can fork a repo
Given below is a scenario you can try in order to learn how to fork a repo:.
0. Create a GitHub account if you don't have one yet.
1. Go to the GitHub repo you want to fork e.g., samplerepo-things
2. Click on the button on the top-right corner. In the next step,
[ ] Copy the master branch only
option.GitHub does not allow you to fork the same repo more than once to the same destination. If you want to re-fork, you need to delete the previous fork.
Tools → Git & GitHub → Pull
Can push to a remote repo
Given below is a scenario you can try in order to learn how to push commits to a remote repo hosted on GitHub:
1. Fork an existing GitHub repo (e.g., samplerepo-things) to your GitHub account.
2. Clone the fork (not the original) to your computer.
3. Commit some changes in your local repo.
4. Push the new commits to your fork on GitHub
Click the Push
button on the main menu, ensure the settings are as follows in the next dialog, and click the Push
button on the dialog.
Tags are not included in a normal push. Remember to tick Push all tags
when pushing to the remote repo if you want them to be pushed to the repo.
Use the command git push origin master
. Enter your Github username and password when prompted.
Tags are not included in a normal push. To push a tag, use this command: git push origin <tag_name>
e.g. git push origin v1.0
You can push to repos other than the one you cloned from, as long as the target repo and your repo have a shared history.
Push your repo to the new remote the usual way, but select the name of target remote instead of origin
and remember to select the Track
checkbox.
Push to the new remote the usual way e.g., git push upstream1 master
(assuming you gave the name upstream1
to the remote).
You can even push an entire local repository to GitHub, to form an entirely new remote repository. For example, you created a local repo and worked with it for a while but now you want to upload it onto GitHub (as a backup or to share it with others). The steps are given below.
1. Create an empty remote repo on GitHub.
Login to your GitHub account and choose to create a new Repo.
In the next screen, provide a name for your repo but keep the Initialize this repo ...
tick box unchecked.
Note the URL of the repo. It will be of the form https://github.com/{your_user_name}/{repo_name}.git
.
e.g., https://github.com/johndoe/foobar.git
(note the .git
at the end)
2. Add the GitHub repo URL as a remote of the local repo. You can give it the name origin
(or any other name).
3. Push the repo to the remote.
Push each branch to the new remote the usual way but use the -u
flag to inform Git that you wish to the branch.
e.g., git push -u origin master
Guidance for the item(s) below:
As you are likely to be using an IDE for the project, let's learn at least enough about IDEs to get you started using one.
Can explain IDEs
Professional software engineers often write code using Integrated Development Environments (IDEs). IDEs support most development-related work within the same tool (hence, the term integrated).
An IDE generally consists of:
Examples of popular IDEs:
Some web-based IDEs have appeared in recent times too e.g., Amazon's Cloud9 IDE.
Some experienced developers, in particular those with a UNIX background, prefer lightweight yet powerful text editors with scripting capabilities (e.g. Emacs) over heavier IDEs.
Exercises
Can navigate code effectively using IDE features
Some useful navigation shortcuts:
IntelliJ IDEA Code Navigation