Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
A deep dive into Java programming in preparation for the College Board's Advanced Placement test.
Check out the description from College Board including the description of the test. For the technical folks (it'll be more useful later in the year), this is also a handy document about the features of Java that the test uses. As of the time of this writing, there are two sections:
Multiple choice: 40 questions, 90 minutes, 50% of your score
Free response: 4 questions, 90 minutes, 50% of your score
Visual Studio Code (install latest JDK, then install the VS Code Java Extension Pack)
http://codingbat.com/java/AP-1 (learn by doing. Loads of mini problems)
Runestone Academy best break-down of skills)
We will review the basics of object-oriented programming and how Java is configured. This is primarily a build-up of vocabulary. This unit moves quickly as there are limited practical applications.
I can describe the benefits of using the JRE.
I can identify the three types of errors when programming.
I can describe the attributes of Java’s main function, including scope, instantiation, and return value.
Java's strength is also its greatest weakness. The JVM allows the same Java code to run on almost any machine. It does this by hosting a virtual machine, a simulated computer system that facilitates the interpretation of your code.
With his partner Ken Thompson, Dennis Ritchie solved a very big program for programmers. It's hard enough for programmers to design an app. It's just crazy if you have to program an app in assembly, telling the CPU and RAM how to handle each and every little operation. Programming languages like Ritchie's C allow coders to focus more on the app and less on how it has to interact with the machine. It's like the first, really powerful book of spells made for magicians.
If you'd like to learn more about the history of Computer Science, I found this video to be very charming.
When you install an app on your computer, the JIT will interpret the developer's code and set it up to run on the given machine. The install process takes longer and it might not be compatible with every machine, but then the app is ready to run very quickly. Java doesn't play like that. Instead, it interprets the code in real-time while running through a virtual machine. So while it can run pretty much everywhere, there's a bottleneck in how fast it can perform.
Who made the Java programming language? When and why? Check it out.
The JDK is a type of SDK. We'll use tools to build apps like an IDE and an interpreter. We're going to have lots of bugs or errors in our code. They will take three different forms...
Syntax or Compile-time: You can't compile this code. Something is way off and Java won't touch your mess.
Runtime or crash: Something breaks while it's running as if you asked the computer to divide a number by zero.
Logic: Everything runs okay. Nothing crashes. However, the answer you get is just wrong. If your app says 4+4
is 10
, you've got a logic error.
In Java, all code must be written inside methods, and all methods belong to a class. This means that every Java program is essentially a collection of classes, each containing methods that define the behavior of your program.
Classes must be defined inside a file that shares the exact same name as the class. For example, if your class is called MyProgram
, then the file must be named MyProgram.java
.
The entry point of every Java program is the main
method, which tells Java where to begin executing your code.
Exceptions
While every class usually matches its file name, there are a few exceptions:
You can define inner classes within another class.
Files may contain more than one class, but only one can be public
and match the file name.
Every Java app starts the same way, from a static method that returns nothing. Let's introduce these concepts now. Many of these ideas will seem strange, but they'll make more sense as you build up your background knowledge. You'll come back to this section later on and smile. But for right now, let's take a plunge into the deep end of the pool. We'll hurry right back to the basics but let's take a peek at how all Java apps start.
public static void main(String[] args){}
<=[ all Java apps start from that method! ]
Who can access this method or this variable? The main method must always be public
because it's being triggered from outside the class.
Does this method belong to an instance of the class? What's the difference between an instance and a static class? Imagine we're building a game. We've got one file or class that describes a player and another that has helpful functions like drawing a random number. Every person that plays the game gets their own instance of the player class. It tracks each player's health and abilities in the computer's memory. But the helper class can be static, just one master copy--no instance needed.
As the method closes, does it return anything? If so, what type of data is returned? The main method must always return void because it's the point of origin--there's nothing to return data to.
We start with the fundamentals of logic gates and logical expressions using De Morgan's Law. By looking at transistors, the most granular aspect of CS, we can steadily add layers of abstraction.
I can explain the connection between electricity and logic.
I can interpret logical statements with all common operators, (i.e. and, or, nor, xor, if, iff).
I can simplify a logical expression according to De Morgan's Laws.
I can convert numbers from decimal to binary and to hexadecimal.
I can describe the purpose of instantiation.
I can decide when to instantiate an object or when to use a static class.
I'm absolutely fascinated in how people build logic, systems that react to conditions, into physical devices.
We start with two tricks with circuits:
1) and &&
2) or ||
With tiny transistors and these building blocks, we can assemble our modern technological era. Let's just take a peak:
You'll need to know how to distribute the !
when simplifying logical expressions. This will make more sense as we get into more practical examples.
A "promise" or an "if" within logic is something like:
Let's simplify these statements. Reduce them down to just true
or false
true != true || (true || false)
false && true || true && false || true && false || true
!(true && false)
!(5 > 5)
!(5 <= 5)
5 == 5 && true
Can you see how false
and true
could also be considered to be 0
and 1
? All the sudden, we can make these logic gates, these electrical transistors, store binary data. Computers are pretty cool.
This is an important concept that's most easily introduced when we're not thinking about the code. If you have a recipe to make a cake, that's similar to a class definition. Each time you bake a cake, you're creating a new instance of that cake.
This is by no means a perfect example as things are more complicated... but let's consider Fortnite for a moment. There's just one map. Programmers might refer to this map by its class. If I wanted to call a tornado, at Coney Crossroads, I might type something like, Map.createTornado("Coney Crossroads");
Now let's imagine a programmer wanted to provide a player with some individual powers. I wouldn't want to be so broad as to call the whole Player
class as each player is an individual. I'd want to specify which individual player, something like lancerGuy99.upgradeWeapon();
We will look more closely at the object-oriented programming and the implications of instantiated objects.
I can describe what it means to be an object-oriented programmer.
I can describe the difference between values and references.
I can build unit tests to check every method in my class definition.
Why don't we list all of our code in one long file? How do we start to organize big projects? We start with objects. Already we've been using a class with a main method as its starting point. All of our methods have been static. What if we wanted to make a game with a lot of monsters? We can define our own Monster
class and create as many instances of that object as we need in the game. We can't use static
methods anymore as a result.
Monster
. Keep your data private, accessible only to methods that allow for more careful controls.
ArrayLists are introduced in this section because they're objects themselves. They illustrate some of the differences we see when working with objects. Instead of arrays when we can access an element just by printing someCollection[x]
, we now need to use someOtherCollection.get(x)
. Let's get into these differences.
Because ArrayLists are only accessible through methods, you can use the same type of access[index]
you can with an array. Here's what a simple traversal looks like with a good ol' array:
Notice how I used length as a property not as an accessor method() and I accessed an element from the collection using [brackets]. Now let's take a look at an ArrayList:
There's a couple important things happening above you should look closely at:
Notice how I declared a List
and then turned it into an ArrayList? It wouldn't have worked if I tried to do new List
because a List
is abstract. It's like mammal. You can tell the computer that you'd like to make a new mammal named x
and it should run the new Dog()
constructor. That's a polymorphic declaration. Use a general ancestor as a type and then be more specific during the constructor.
If you look inside the ArrayList class programmed inside our Java library, you'll notice it has an array at its core. It's a wrapper for an array. So there is a .length
property that's relevant to its internal, private programming. Every time you .add(something)
to an ArrayList it destroys its old array and copies all the content to a new, longer array. So .length
is serious business. Since that's occupied, we use the .size()
accessor method to retrieve the length of an ArrayList.
What's the point of creating our own objects? How does an ArrayList differ from an array in practical implementation? Let's go through an example project to help iIllustrate these concepts.
SecureLists are made up. They're a silly object that provides an extra layer of "security" by storing your list of 12 names in two different objects, an array and an ArrayList. Does that actually provide additional security? No, not really. But let's pretend it does so you have an opportunity to work with an array and an ArrayList simultaneously.
Let's set up your project with the following files:
We start to delve into algorithms and basic AI with our first CollegeBoard-issued lab. We will learn about String manipulation so we can have a conversation with our computer.
I can use common String methods to modify a string.
I can evaluate the contents of a String.
I can use a Scanner to take inputs.
I can isolate an object in the user's input and use it in Magpie's response.
CollegeBoard used to have three official projects, Magpie, Elevens, and PicLab. A few years ago, they dropped those four and started four new ones: Celebrity, Consumer Review, DataLab, and Steganography. But I still think Magpie is the best lab for starters.
A bid that can mimic speech.
Check out the chatbot in Activity 1:
Check out the official documentation.
Strings are a special data type in Java. They're not primitives but they behave a little differently than most instantiated objects. In many ways, they're an array of primitive char
objects. The biggest difference is that Strings also have many helpful methods to change their formatting, to search and examine the Strings, and lots of other helpful tools.
Create a new class in our project called StringExplorer and drop this code in:
Now we're going to add a few new classes to the project.
Now write a commit message to bookmark these changes and push the new version to GitHub. Then following along with the exercises in Activity 2.
Magpie's current structure and use of .indexOf("something") >= 0
is full of logic errors. It's caps sensitive, it can't tell if you've entered no response at all, and it sees the word "no" inside of "know". Let's do better.
Let's drop these two methods into your Magpie class (they're overloaded):
Now we've got to update our getResponse
method to use this instead of indexOf
.
Let's use this chart to walk through what's happening:
Let's use parts of the user's message in our response. Read the details in the student guide. Before proceeding.
Replace the else in our getResponse
method with the following code:
Now below this getResponse
method, let's add in a few methods that are being called by the code above.
Okay, now you're ready to follow along the student guide with the class and ask some questions along the way.
Your team will build a chatbot that will enter into a conversation with other chatbots built in class.
Next, we need to rename the file and the class.
Do not name your chatbot the same as anyone else's in class.
Now that you've created your robot, you can add it to the main method.
File
1 point: Your file has an original name that matches the name in your class definition
name
1 point: Returns a one-word name that roughly matches your class name
greet
2 points: Returns a 25 - 100 word opening statement.
Bonus +1 point: Randomly selects from at least three opening statements
respond
3 points: Checks for three different antagonistic words and does not complete the respond method but instead calls the antagonize
or pacify
method instead
3 points: Checks for three different pacifying words and does not complete the respond method but instead calls the antagonize
or pacify
method instead
5 points: Searches for at least five keywords and responds to the given subject matter.
antagonize
3 points: Searches for at least three keywords and responds in a negative tone to the given subject matter.
pacify
3 points: Searches for at least three keywords and responds in a positive, disarming tone to the given subject matter.
BONUS POINTS
Have your greet method randomly select from at least three opening statements
Successfully use substring on the given prompt/statement
Your bot successfully adapts to antagonistic or pacifying messages from other bots
Let's review some basics before we move onto our next, advanced concept. Now's the time to hit codingbat, SoloLearn, Codecademy, or other training websites to practice. You want the basics down pat so you can focus on new concepts as we move forward.
We will learn to solve simple problems with Java programming. We will create all sorts of variables, test their limitations and exercise basic control flow.
I can declare variables of common Java data types and assign values.
I can control the flow of my app with loops, conditionals and method calls.
I can write efficient conditionals and return comparisons in my methods.
I can describe the difference between logic, run time and compile time errors.
Primitives are objects that live entirely in stack memory (they're lowercase like int
and not like String
) . We'll go over the difference between stack and heap memory later. For now, just think of stack memory as the lightweight stuff that's really fast-access. Take a look at the types of Java primitives.
CompoundCapitalize
name of classes
camelCase
variables and methods
ALLCAPS
variables marked as final
, meaning they can't change
snake_case
is typically used only in Python and I miss it every time I work in Java or C#
What's 9 / 4
? In Java, it's just2
, but if you wrote it like 9.0 / 2
, then the answer would be 2.5. If you don't introduce a decimal to the operation, if you only give Java literal int
s , it'll match that format and ignore decimals.
We evaluate / test data and produce a true
or false
value.
This comes up all the time in problems. It's a useful trick to avoid crashing your apps, too.
A fundamental element of flow control is whether or not you want to execute a block of code. We use a conditional or if statement to test something. That test will result in a true
or false
value. If it's true, we'll execute the block of code. If it's false, we'll skip to the end of the block of code.
Loops are how we repeat commands or loop through items in a collection.
Most for loops look something like this:
The for statement has a declaration, condition and increment. But you can skip the declaration if you'd like. Let's say you want the counter to have a wider scope (so it can be accessed outside of the loop) like this:
Let's say I have an array or collection of numbers like this: int[] numberArray = [5, 10, 15, 20, 25];
Each number in that group has an address or index (that starts at 0). If I wanted to print the number 10 for example, I could write System.out.println(numberArray[1]);
So if I wanted to loop through (called iterating or traversing) all the items in this array, I could use a normal for loop like this:
But there's an easier form of the for loop that's meant to easily traverse through a collection. We'll go over some of the pros and cons of this method later.
The do-while is rarely used but it's handy if you want to make sure the steps run the first time before the loop condition is tested. Read more.
You can declare and initialize an int like int x = 5;
Similarly, you can create an array that contains three ints like this: int[] x = {5, 10, 15};
Arrays are immutable. They don't change in size. Java uses a fancier object called an ArrayList
that is more flexible. So if one of your friends is trying to convince you to increase the size of an array, just say no.
x.length; // note: this isn't a method like it is in the String class.
x[0]; // this will print "5" in my example
x[x.length-1]; // this will print "15" in my example
Loop through every element in the array
Check if an element is found in an array
Make an array of other types of objects
This is a part of control flow. The thread, the computer's train of thought, is being sent over to work through a set of commands called a method or function (either name works in this class).
We will build our own photo editing tools as we study more complex nested loops to traverse and mutate 2D arrays.
I can remove a column from a 2D array in Java.
I can write 2D array methods for the PicLab.
Convert 128 to binary
Covert 225 to binary
Convert 11010111 from base 2 to base 10
This is a byte.
Max red, green and blue (255, 255, 255) is white. No red, green and blue (0, 0, 0) is black. Sometimes we add a fourth byte to control alpha layer (transparency). rgba(255, 255, 255, 255)
is opaque black.
Two digits in base 16, hexadecimal, can describe 0 - 255. Eight digits can contain rgba. #FF0000FF
is opaque black.
What is the row index for the top left corner of the picture?
What is the column index for the top left corner of the picture?
The width of the picture is 640. What is the right most column index?
The height of the picture is 480. What is the bottom most row index?
Imagine a circumstance where you might use an interface and an abstract class. Create and implement the interface and abstract class. Instantiate objects that extend these. Create a polymorphic container or method.
Calculate the sum of an indicated column from an extremely rare occurrence of a 2D ArrayList:
public static int sumColumn(int col, List<List<Integer>> grid){
Remove a row from a 2D array:
public static String[][] removeRow(int row, String[][] names){
Calculate the sum of an entire 2D array:
public static double sum(double[][] grid){
Count the number of occurrences of a given number in a 2D array
public static int count(int[][] grid, int target){
Add a new column to a 2D array of Pixels with the average color at the end of the image
public static Pixel[][] addAverageColumn(Pixel[][] picture){
// each Pixel has .getColor() which gives a single int
// return an array that's one column wider, containing the average of every color in that row
// you can set the color of a pixel by using .setColor() and passing the method the average of that row's .getColor()
}
Convert an RGB value like 220, 175, 205 to a hex value
We have an array of Friends, Friends[] friends
, and we want to make sure that each of our friends has the items they requested from the store. Friend.getItems()
returns an array of Item objects (Item implements the Comparable
interface so you can use .equals()
to compare two items). If the Item is not on the shopping list, we'll add it to an ArrayList<Item>
called requests
. The Item class also has a publicly accessible boolean that marks if the Item has been claimed: Item.claimed
.
public ArrayList<Item> checkShoppingList(Friends[] friends, ArrayList<Item> list){
We will write our most complex algorithms as we study efficient ways to sort collections of data. Some of these algorithms will require recursion, our most abstract and challenging topic to date.
I can implement selection, insertion and merge sort algorithms.
I can compare sorting algorithms' efficiency.
We've talked about algorithms before, most especially around the shuffling patterns we've used in the Elevens lab.
The bigger the group of data, the more important it is to be efficient. Searching on the web or in a database needs to be awfully fast. We measure the efficiency of a complex search or sort algorithm in Big O notation.
Let's knock out a quick algorithm first, searching. The O(n)
way is just a straight traversal. But we could chop that down to a O(log n)
with a binary search:
The visualization of these patterns / algorithms / methods / whatever, is surprisingly helpful. You can get a feel for how we chunk the computer's task to organize a long list of numbers.
Let's start with a nested loop, a boring old O(n^2)
traversal and sort.
Now between the inner and otter loops, we do a 3-part-swap
Insertion sort has the same worst-case scenario efficiency as selection sort, but it has a much better best-case scenario efficiency.
[0]
Create a class that uses Sortable
and IntegerMonster
. Hopefully, that and the code below is enough for you to figure out what to do next. If not, let's make some extra time to practice/read about inheritance in Java.
You'll have to use extends
before implements
.
Potentially helpful analogy: I imagine "extends" as the class's last name and "implements" as job titles.
Surprise: Your client suddenly changes the SoW and insists that the sort methods' outer loops print the current state of the array neatly on one line. Each array during the sort should be labeled.
What happens if I call a function that calls itself? You can use this as a trick to chunk information in a loop-like flow.
A base case is the critical piece of a recursive function that will terminate the recursive calls, and start the domino effect in the opposite direction.
If we have a base case in place (rhymes!) we can use recursion to solve some tricky problems in an elegant fashion.
Let's start with some numbers to sort:
Check if nums
has hit its base case. Is it already split up? If not, split it up.
Then we send each side to mergeSort. Notice we send the left side first. And the next copy of mergeSort
will break that side up first too--all the way down to the base case.
But down at that last level, when they can't be broken down any further, we'll be left with a few useful ingredients, the (yellow) nums
, the left side, l
, and the right side, r
. Now we'll shove l
and r
back together, in order, and overwrite the contents of nums
. We'll do this in a separate function: merge(nums, l, r, mid, n - mid);
First notice how they include the post-operation increment, k++
(instead of ++k
). This way, every time k
is used, it increases the index tracker on the parent array. It's a clever touch. Meanwhile, i
is serving similarly as the index tracker for the left side and j
is serving the right side.
The first while loop proceeds until one of the counters hits their max. Then only one of the two remaining while loops will execute, collecting the last number.
Create a class that extends NameManager
and implements all required methods.
This is a great follow-up to the video below.
There are all sorts of variations on mergeSort and the merge function. The one from is pretty clever and fun to talk over. Check it out:
Operator
Description
Example (a=10, b=20)
+ (Addition)
Adds values on either side of the operator.
a + b will give 30
- (Subtraction)
Subtracts right-hand operand from left-hand operand.
a - b will give -10
* (Multiplication)
Multiplies values on either side of the operator.
a * b will give 200
/ (Division)
Divides left-hand operand by right-hand operand.
b / a will give 2
% (Modulus)
Divides left-hand operand by right-hand operand and returns the remainder.
b % a will give 0
++ (Increment)
Increases the value of operand by 1.
b++ gives 21
-- (Decrement)
Decreases the value of operand by 1.
b-- gives 19
Operator
Description
Example (a=10, b=15)
Result
==
Equality operator
a==b
false
!=
Not Equal to operator
a!=b
true
>
Greater than
a>b
false
<
Less than
a<b
true
>=
Greater than or equal to
a>=b
false
<=
Less than or equal to
a<=b
true
We introduce our first complex algorithms and start to pull back the scaffolding a bit. Students will get their first real experience designing aggregate objects with encapsulated properties.
I can secure my class variables with encapsulation.
I can create a constructor to initialize an object.
I can override a parent method.
I can build unit tests for all methods in an aggregate object.
Keep it DRY and OOP-y
DRY stands for Don't Repeat Yourself. So far, that's meant that if you need to repeat a bit of code, you make a loop instead of sloppily copying and pasting the same commands a few times. Now we're seeing that OOP, or Object-Oriented Programming, has was to build classes off of one another. That means we can avoid repeating (aka DRY code) by using inheritance.
Polymorphism is my favorite CS term because it sounds so much fancier than it really is (sort of a theme here). In class we'll build an abstract class called Shape with some encaspulated instance variables like length
and width
, abstract methods like .area()
. Then we'll inherit from those methods when we create types of shapes like Circle, Rectangle, Triangle and so on. Let's look closer at why this is an example of inheritance and polymorphism.
Creating a parent class called Shape
that all your shapes will inherit means that the common properties and functions can live in one place. If new features or changes needed to happen across all the elements in your app, you would have a logical place to check.
Let's take a look at a shortened Shape
class:
All the encapsulation shown between lines 3 - 14 should be familiar by now. Seek additional practice including your teacher's office hours if not. The cool new thing here is line 17. Because the parent is declaring this method, all its children (i.e class Circle extends Shape {
)will have to build their own area method. The Circle
class will return 3.14 * (length * length);
for its area()
implementation.
Because all of my app's shapes will have a common parent, I can create a collection of Shape
like:
ArrayList<Shape> myShapes = new ArrayList<>();
That allows me to to loop through the whole collection and report out their areas:
What if I wanted to build a huge space game with thousands of types of ships. I'd make rules for cargo ships and warships. There may be times when I want multiple inheritances to be applied. Well there are some limits here in Java. You can have multiple vertical levels, like Ship --> Warship --> Battleship but a single ship can't inherit from two places simultaneously. Instead, there are Interfaces.
Please download the guide to this old project from CollegeBoard.
Let's create a simple Card
object and test its encapsulated properties.
Now we'll build our aggregate object, the Deck
.
This algorithm uses a lot of structures we'll see when we have to start sorting items rather than shuffling. The problem with a perfect shuffle is that after 4 passes, all the cards are back in the original order.
In Activity 4, we'll add the shuffler method to the Deck
class. It's the same process but we'll adapt using arrays to ArrayLists. We'll just skip activities 5 and 6 outright as we'll cover that material elsewhere. In case you're curious, the one cool thing we skip over for now is assert statements in Java:
You will need to add this folder to your codebase.
Loops
Searching / counting while traversing an array and an ArrayList
Traverse to find max and mins:
public static int findLargest(int[] nums){
Interact with an ArrayList
public static void makeLowerCase(ArrayList<String> commands){
Keep count
public static int countNames(ArrayList<String> names, String target){
Shuffle methods:
public static void selectShuffle(int[] nums){
public static void perfectShuffle(Card[] cards){
Nested loops
Find common elements between two collections:
public static ArrayList<String> findCommonNames(String[] roster1, String[] roster2){
Classes
Encapsulation with accessor and mutator methods
Implementing an abstract class (with encapsulation)
OOP: When should you move properties and methods to an abstract layer?
Name three properties or methods that would be suitable for a Human
class and three that would go on an abstract Mammal
class.
How do you declare an abstract class and an abstract method?
Declare an abstract class called Athlete
, give it private properties of name
, number
, position
, and is_active
.
Make a constructor.
Make accessor methods for each property.
How do you declare a class to inherit the properties from an abstract class?
Create classes called SoccerAthlete
and BasketballAthlete
that both inherit from Athlete
.
Give each class a toString
method that returns the String, "My name is {name} and I'm a {position} in soccer. I'm #{number}." Only if they're active.
If they're inactive, the returning String should read, "I used to be play basketball as a {position}."
How can you take advantage of polymorphism?
Create a runner class with a main method that creates an array of Athlete
s. Loop through them and have each one introduce themselves.
Submit a completed NumSet class:
Your Elevens test will be a semi-randomized selection of multiple choice questions all taken from the same sources used for our Do Nows. There will be one free response question similar to the homework. Both of these parts of the test reflect the two portions of the AP test. Therefore, the best way to study would be to review AP practice problems from our relevant topics:
Redo homework assignments and previous drills
This site's Chapters 3-9: https://runestone.academy/runestone/books/published/apcsareview/index.html
Take a practice test: http://ice.cc.gatech.edu/apexam_final/index.jsp
Do some Codingbat: https://codingbat.com/java/AP-1