Array is an object that contains a collection of elements.
What are the characteristics of an Array?
1. Array elements must be of the same data type.
2. Array size must be fixed and cannot be changed.
How to create an array?
int[] numbers = new int[3]; numbers[0] = 10; numbers[1] = 20; numbers[2] = 30; String[] names; names = new String[3]; names[0] = "Folau"; names[1] = "Kinga"; names[2] = "Laulau"; int[] ids = {1,2,3};
How to access array elements?
Use the position of the element in the array to access the element.
int[] numbers = new int[3]; numbers[0] = 10; numbers[1] = 20; numbers[2] = 30; int sum = numbers[0] + numbers[1] + numbers[2]; System.out.println("sum: "+sum);//60
Advantages of arrays
1. We can access the elements at any position.
Disadvantages of arrays
1. Size of the array does not grow at runtime.
There are two types of arrays:
1. Single dimensional array
2. Multidimensional array
Single Dimensional Array
A single dimensional array is what we have been using so far.
Multidimensional Array
int[][] numbers = new int[2][2]; numbers[0][0] = 1; numbers[0][1] = 2; numbers[1][0] = 3; numbers[1][1] = 4;
Operators are used to perform actions or operations on variables and values.
int sum = 2 + 5;
2 and 5 are values also called operands.
+ is called an operator
Operand | Operator | Operand |
---|---|---|
2 | + | 5 |
Here are the groups of operators:
a. Arithmetic Operators
b. Comparison Operators
c. Logical Operators
d. Assignment Operators
e. Ternary Operator
Arithmetic Operators
Arithmetic operators are used to perform mathematical operations just like algebra math you have in school.
Operator | Description | Example |
---|---|---|
+ (Addition) | Adds values. | 5 + 5 will give 10 |
– (Subtraction) | Subtracts values. | 10 – 5 will give -5 |
* (Multiplication) | Multiplies values. | 5 * 4 will give 20 |
/ (Division) | Divides left-hand operand by right-hand operand. | 4 / 2 will give 2 |
% (Modulus) | Returns remainder of division. | 0 % 2 will give 0 |
++ (Increment) | Increases the value by 1. | 4++ gives 5 |
— (Decrement) | Decreases the value by 1. | 4– gives 3 |
Comparison Operators
Comparison operators are used to compare two or more values.
Operator | Description | Example |
---|---|---|
== (equal to) | Compares if the two values are equal or not | (1 == 2) is not true. |
!= (not equal to) | Compares if the two values are not equal | (1 != 2) is true. |
> (greater than) | Compares if the value on the left-hand side is greater than the value on the right-hand side. | (1 > 2) is not true. |
< (less than) | Compares if the value on the left-hand side is less than the value on the right-hand side. | (1 < 2) is true. |
>= (greater than or equal to) | Compares if the value on the left-hand side is greater than or equal to the value on the right-hand side. | (1 >= 2) is not true. |
<= (less than or equal to) | Compares if the value on the left-hand side is less than or equal to the value on the right-hand side. | (1 <= 2) is true. |
Assignment Operators
Assignment operators are used to assign values to variables
Operator | Description | Example |
---|---|---|
= | Assigns values from right side operands to left side operand. | age = 2 + 4 will assign value of 2 + 3 into age |
+= | Adds right value to the left operand and assign the result to left operand. | age += 2 is equivalent to age = age + 2 |
-= | Subtracts right value from the left operand and assign the result to left operand. | age -= 2 is equivalent to age = age – 2 |
*= | Multiplies right value with the left operand and assign the result to left operand. | age *= 2 is equivalent to age = age * 2 |
/= | Divides left value with the right operand and assign the result to left operand. | age /= 4 is equivalent to age = age / 4 |
%= | Takes modulus using two operands and assign the result to left operand. | age %= 4 is equivalent to age = age % 4 |
Ternary Operator
Ternary operator is used to evaluate a boolean expression.
variable = (condition) ? (execute if condition is true) ? (execute if condition is false);
String action = (1 > 5) ? "fire" : "water"; // action will be "water" because 1 is not greater 5
Instanceof Operator
Instanceof operator is used to check the type of a variable. This is a very useful operator when working with objects and classes.
String name = "Folau"; boolean isAString = name instanceof String; // isAString here is true because name is of data type String.
In the previous tutorial we discussed variables and one of the 3 things a variable must have is a type or a data type which we will discuss here. Quick recap on variables:
public static void main(String[] args) { String firstName = "Folau"; System.out.println(firstName);// Folau }
String – data type
firstName – variable name
“Folau” = value
There are two types of data types:
1. Primitive data types – byte, short, int, long, float, double, boolean, and char
2. Non-Primitive or Object data types – String, Arrays, List, Classes(you will learn about this later)
Primitive Data Types
Primitive data types have size. Here is the 8 Java primitive data types.
Type | Size | Description |
---|---|---|
byte | 1 byte | Stores whole numbers from -128 to 127 |
short | 2 bytes | Stores whole numbers from -32,768 to 32,767 |
int | 4 bytes | Stores whole numbers from -2,147,483,648 to 2,147,483,647 |
long | 8 bytes | Stores whole numbers from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,808 |
float | 4 bytes | Stores fractional numbers from 3.4e−038 to 3.4e+038. Sufficient for storing 6 to 7 decimal digits |
double | 8 bytes | Stores fractional numbers from 1.7e−308 to 1.7e+038. Sufficient for storing 15 decimal digits |
boolean | 1 byte | Stores true or false values |
char | 2 bytes | Stores a single character/letter |
String Data Type
String is almost a primitive data type because it is used everywhere in java. But it is not a primitive data type. String variables are references and have methods which are things primitive data types don’t have.
Non Primitive Data Types
Non primitive data types are references to objects in memory and they have methods or actions to trigger.
Difference between Primitive and Non-Primitive Data Types
1. Primitive data types are defined by Java like int or double. Non Primitives are created by developers
2. Primitive data types start with lowercase like int, long, double, etc. Non Primitive data types start with uppercase like String, User, etc.
3. Primitive data types always have values. Non Primitive data types can be null.
4. Primitive data types cannot be invoked to perform actions but primitive can. i.e user.sayHello();
4. Primitive data types cannot be invoked to perform actions but primitive can. i.e user.sayHello();
Variables are very important for us to understand because computer programs are filled with them. We need to know what they are and what they do.
For beginners a variable stores a value. A more specific definition of variable is a name given to a memory location which is used to store a value in a computer program. Another definition that I like is that variables act as containers for storing numbers and words which are used in a computer program.
String firstName = "Folau"; System.out.println(firstName);// this prints out Folau firstName = "Lisa"; System.out.println(firstName);// this prints out Lisa
firstName is the variable. It holds “Folau” or “List” and you can use it any where you want to use firstName.
Here is how you create a variable:
type variable = value;
A variable must have 3 things:
type
name
value
Example: here is an example of a variable that stores a word or string.
String firstName = "Folau"; System.out.println(firstName);// this prints out John
The equal sign you see between the variable name(firstName) and the value(“Folau”) is used to assign the value to the variable.
Naming a variable has a set of rules
a. Variable names can container letters, digits, underscore, and doller signs
// you can do this int age = 25; // you cannot do this. double is a reserved word. int double = 50;
b. Variable names must not start with digits but can start with and should start with letters
// you cannnot do this. 10IsMyNumber starts with a digit. String 10IsMyNumber = 10;
c. Letters are more of the norm for java variables. In other languages such as PHP and Javascript, dollar signs and underscore are used regularly.
d. Variable names are case sensitive so firstName and firstName are different variables.
String firstName = "Folau";// N in firstName is uppercase String firstname = "Lisa";// n in firstname is lowercase
e. Variable names should start with a lowercase letter and cannot contain whitespace(pretty much no space).
// you cannot do this. There is a space in between first and name. String first name = "Folau"; // solution. Remove or replace the space with the underscore sign String first_name = ""
f. Variable names cannot be java reserved words(words that are reserved just for the language only like String you see in the above example)
// you cannot do this. String is a keyword and cannot be used as a variable name. String String = "Folau"; // you can do this. string is all in lower case. String string = "Folau";
Variable Naming conversions
1. camelCase vs snake_case.
String firstName = "Folau"; vs String first_name = "Folau"; int numberOfPersons = 100; vs int number_of_persons = 100;
Most java programs I have worked on and seen use the camelCase pattern. Most java developers I know use the camelCase pattern. I think it’s java convention to use camelCase but it’s up to you.
2. Make variable names comprehensive and easy to understand. Great programmers use comprehensive variable names just FYI. Use words, even if they are long, rather than abbreviations and initials
int numberOfPersons = 100; // great int nop = 100; // not clear int p = 100; // not good at all
3. Naming style
Sometimes developers get lazy and do this.
// NUMBER_OF_PERSONS and Number_Of_Rocks are not consistent. Name both of them the same style. public static final int NUMBER_OF_PERSONS = 100; public static final int Number_Of_Rocks = 50;
My opinion on variable naming convention is that when I name variables I make sure they are clear and easy to understand within the context. Remember code is writtern for humans and reading code is like reading a story. It should flow and make sense.
Make sure to take time to plan and think about your variable names because they are so important. Especially if you are in a team where your team members will read your code. They should not have any issue reading or understanding what your variables represent.
Development time can be saved if your variable relay the message it needs to relay. Bad variable names can cause confusion and waste a lot of development time. Plan and think first!
Your variable names kind of represent how well you understand the program you are developing. Not only that it also represents how good of a developer you are to a certain degree.
A notification system has already become a very popular feature for many applications in recent years. A notification alerts a user with important information like breaking news, product updates, events, offerings, etc. It has become an indispensable part of our daily life. In this chapter, you are asked to design a notification system.
A notification is more than just mobile push notification. Three types of notification formats are: mobile push notification, SMS message, and Email. Figure 10-1 shows an example of each of these notifications.
Solution
Service 1 to N: They represent different services that send notifications via APIs provided by notification servers.
Notification servers: They provide the following functionalities:
Cache: User info, device info, notification templates are cached.
DB: It stores data about user, notification, settings, etc.
Message queues: They remove dependencies between components. Message queues serve as buffers when high volumes of notifications are to be sent out. Each notification type is assigned with a distinct message queue so an outage in one third-party service will not affect other notification types.
Workers: Workers are a list of servers that pull notification events from message queues and send them to the corresponding third-party services.
Third-party services: Already explained in the initial design.
iOS, Android, SMS, Email: Already explained in the initial design.
Now, let us examine how every component works together to send a notification:
How to prevent data loss?
One of the most important requirements in a notification system is that it cannot lose data. Notifications can usually be delayed or re-ordered, but never lost. To satisfy this requirement, the notification system persists notification data in a database and implements a retry mechanism.
Will recipients receive a notification exactly once?
The short answer is no. Although notification is delivered exactly once most of the time, the distributed nature could result in duplicate notifications. To reduce the duplication occurrence, we introduce a dedupe mechanism and handle each failure case carefully. Here is a simple dedupe logic:
When a notification event first arrives, we check if it is seen before by checking the event ID. If it is seen before, it is discarded. Otherwise, we will send out the notification.
Notification template
A large notification system sends out millions of notifications per day, and many of these notifications follow a similar format. Notification templates are introduced to avoid building every notification from scratch. A notification template is a preformatted notification to create your unique notification by customizing parameters, styling, tracking links, etc. Here is an example template of push notifications.
BODY: You dreamed of it. We dared it. [ITEM NAME] is back — only until [DATE]. CTA: Order Now. Or, Save My [ITEM NAME] The benefits of using notification templates include maintaining a consistent format, reducing the margin error, and saving time.
Notification setting
Users generally receive way too many notifications daily and they can easily feel overwhelmed. Thus, many websites and apps give users fine-grained control over notification settings. This information is stored in the notification setting table, with the following fields:
user_id bigInt channel varchar # push notification, email or SMS opt_in boolean # opt-in to receive notification
Before any notification is sent to a user, we first check if a user is opted-in to receive this type of notification.
Rate limiting
To avoid overwhelming users with too many notifications, we can limit the number of notifications a user can receive. This is important because receivers could turn off notifications completely if we send too often.
Retry mechanism
When a third-party service fails to send a notification, the notification will be added to the message queue for retrying. If the problem persists, an alert will be sent out to developers.
Here is the final design, many new components are added in comparison with the previous design.