Skip to content

Commit

Permalink
Add nullability concept (#2584)
Browse files Browse the repository at this point in the history
* Nullability concept added

* Updating error message

* Updating config.json

* Linting issues and prerequisites updated in config.json

* Addressing review comments

* Removing trailing space

Fixes #2553
  • Loading branch information
smcg468 authored Nov 25, 2023
1 parent 18c16d0 commit e937a27
Show file tree
Hide file tree
Showing 16 changed files with 354 additions and 0 deletions.
7 changes: 7 additions & 0 deletions concepts/nullability/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"blurb": "In Java, the null literal is used to denote the absence of a value.",
"authors": [
"smcg468"
],
"contributors": []
}
53 changes: 53 additions & 0 deletions concepts/nullability/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# About

In Java, the [`null` literal][null-keyword] is used to denote the absence of a value.

[Primitive variables][primitive-data-types] in java all have a default value and therefore can never be `null`.
By convention, they start with a lowercase letter e.g `int`

[Reference variables][reference-data-types] contain the memory address of an object and can have a value of null.
These variables usually start with an uppercase e.g `String`

Attempting to assign a primitive variable a value of `null` will result in a compile time error as the variable always holds
a default value of the type assigned.

```java
//Throws compile time error stating the required type is int, but null was provided
int number = null;
```

Assigning a reference variable a `null` value will not result in a compile time error as reference variables are nullable.

```java
//No error will occur as the String variable str is nullable
String str = null;
```

Whilst accessing a reference variable which has a value of `null` will compile fine, it will result in a `NullPointerException` being thrown at runtime.

```java
int[] arr = null;

// Throws NullPointerException at runtime
arr.Length;
```

A [`NullPointerException` is thrown][null-pointer-exception] when trying to access a reference variable which is null but requires an object.

To safely work with nullable values, one should check if they are `null` before working with them which can be done using [equality operators][equality-operators] such as `==` or `!=`:

```java
int[] arr = null;

if(arr != null) {
System.out.println(arr.length);
} else {
//Perform an alternate action when arr is null
}
```

[null-keyword]: https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.7
[primitive-data-types]: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
[reference-data-types]: https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.3
[null-pointer-exception]: https://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
[equality-operators]: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op2.html
24 changes: 24 additions & 0 deletions concepts/nullability/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Introduction

In Java, the `null` literal is used to denote the absence of a value.

Primitive data types in java all have a default value and therefore can never be `null`.
By convention, they start with a lowercase letter e.g `int`

Reference types contain the memory address of an object can have a value of null.
These variables usually start with an uppercase e.g `String`

Attempting to assign a primitive variable a value of `null` will result in a compile time error as the variable always holds
a primitive value of the type assigned.

```java
//Throws compile time error stating the required type is int, but null was provided
int number = null;
```

Assigning a reference variable a `null` value will not result in a compile time error as reference variables are nullable.

```java
//No error will occur as the String variable str is nullable
String str = null;
```
22 changes: 22 additions & 0 deletions concepts/nullability/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"url": "https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.7",
"description": "null-keyword"
},
{
"url": "https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html",
"description": "primitive-data-types"
},
{
"url": "https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.3",
"description": "reference-data-types"
},
{
"url": "https://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html",
"description": "null-pointer-exception"
},
{
"url": "https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op2.html",
"description": "equality-operators"
}
]
17 changes: 17 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,18 @@
"switch-statement",
"constructors"
]
},
{
"slug": "tim-from-marketing",
"name": "Tim from Marketing",
"uuid": "28bd20c5-4fdd-4660-9225-54f24aae24e4",
"concepts": [
"nullability"
],
"prerequisites": [
"if-else-statements",
"strings"
]
}
],
"practice": [
Expand Down Expand Up @@ -2088,6 +2100,11 @@
"slug": "lists",
"name": "Lists"
},
{
"uuid": "0718bff1-25ad-42bb-860d-1b0834beb9fc",
"slug": "nullability",
"name": "Nullability"
},
{
"uuid": "58529dab-0ef2-4943-ac12-a98ca79b922b",
"slug": "numbers",
Expand Down
20 changes: 20 additions & 0 deletions exercises/concept/tim-from-marketing/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Hints

## 1. Print a badge for an employee

- [String interpolation][string-interpolation] can be used to create description strings.
- There is a [built-in method to convert a string to uppercase][to-upper-case].

## 2. Print a badge for a new employee

- You should check if the ID is `null` before using it.
- You can use the [equality operators][equality-operators] to compare the value to `null`

## 3. Print a badge for the owner

- You should check if the department is `null` before using it.
- You can use the [equality operators][equality-operators] to compare the value to `null`

[string-interpolation]: https://www.baeldung.com/java-string-interpolation
[to-upper-case]:https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#toUpperCase--
[equality-operators]: https://docs.oracle.com/cd/E21764_01/apirefs.1111/e17787/com/sigmadynamics/util/Null.html#isNull_java_lang_String_
47 changes: 47 additions & 0 deletions exercises/concept/tim-from-marketing/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Instructions

In this exercise you'll be writing code to print name badges for factory employees.

## 1. Print a badge for an employee

Employees have an ID, name and department name. Employee badge labels are formatted as follows: `"[id] - name - DEPARTMENT"`.
Implement the `Badge.print()` method to return an employee's badge label:

```java
Badge badge = new Badge();
badge.print(734, "Ernest Johnny Payne", "Strategic Communication");
// => "[734] - Ernest Johnny Payne - STRATEGIC COMMUNICATION"
```

Note that the department should be uppercased on the label.

## 2. Print a badge for a new employee

Due to a quirk in the computer system, new employees occasionally don't yet have an ID when they start working at the factory.
As badges are required, they will receive a temporary badge without the ID prefix. Modify the `Badge.print()` method to support new employees that don't yet have an ID:

```java
Badge badge = new Badge();
Badge.print(null, "Jane Johnson", "Procurement");
// => "Jane Johnson - PROCUREMENT"
```

## 3. Print a badge for the owner

Even the factory's owner has to wear a badge at all times.
However, an owner does not have a department. In this case, the label should print `"OWNER"` instead of the department name.
Modify the `Badge.print()` method to print a label for the owner:

```java
Badge badge = new Badge();
badge.print(254, "Charlotte Hale", null);
// => "[254] - Charlotte Hale - OWNER"
```

Note that it is possible for the owner to also be a new employee:

```java
Badge badge = new Badge();
badge.print(null, "Charlotte Hale", null);
// => "Charlotte Hale - OWNER"
```
26 changes: 26 additions & 0 deletions exercises/concept/tim-from-marketing/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Introduction

## Nullability

In Java, the `null` literal is used to denote the absence of a value.

Primitive data types in java all have a default value and therefore can never be `null`.
By convention, they start with a lowercase letter e.g `int`

Reference types contain the memory address of an object can
have a value of null. These variables usually start with an uppercase e.g `String`

Attempting to assign a primitive variable a value of `null` will result in a compile time error as the variable always holds
a primitive value of the type assigned.

```java
//Throws compile time error stating the required type is int, but null was provided
int number = null;
```

Assigning a reference variable a `null` value will not result in a compile time error as reference variables are nullable.

```java
//No error will occur as the String variable str is nullable
String str = null;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Introduction

## Nullability

%{concept:nullability}
23 changes: 23 additions & 0 deletions exercises/concept/tim-from-marketing/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"authors": [
"smcg468"
],
"files": {
"solution": [
"src/main/java/Badge.java"
],
"test": [
"src/test/java/BadgeTest.java"
],
"exemplar": [
".meta/src/reference/java/Badge.java"
],
"invalidator": [
"build.gradle"
]
},
"forked_from": [
"csharp/tim-from-marketing"
],
"blurb": "Learn about the null literal and nullable variables in java by printing name badges."
}
20 changes: 20 additions & 0 deletions exercises/concept/tim-from-marketing/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Design

## Learning objectives

- Know of the existence of the `null` literal.
- Know what a `NullPointerException` is and when it is thrown.
- Know how to compare a value to `null`.

## Out of scope

- `java.util.Optional`

## Concepts

- `nullability`

## Prerequisites

- `strings`: strings will be compared to null and basic methods from strings will be called.
- `if-else-statements`: using a conditional statement.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
public class Badge {

public String print(Integer id, String name, String department) {

String worksAt;

if (department == null) {
worksAt = "OWNER";
} else {
worksAt = department.toUpperCase();
}

if (id == null) {
return name + " - " + worksAt;
}

return "[" + id + "] - " + name + " - " + worksAt;
}

}
23 changes: 23 additions & 0 deletions exercises/concept/tim-from-marketing/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
id "java"
}

repositories {
mavenCentral()
}

dependencies {
testImplementation platform("org.junit:junit-bom:5.10.0")
testImplementation "org.junit.jupiter:junit-jupiter"
testImplementation "org.assertj:assertj-core:3.15.0"
}

test {
useJUnitPlatform()

testLogging {
exceptionFormat = "full"
showStandardStreams = true
events = ["passed", "failed", "skipped"]
}
}
5 changes: 5 additions & 0 deletions exercises/concept/tim-from-marketing/src/main/java/Badge.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Badge {
public String print(Integer id, String name, String department) {
throw new UnsupportedOperationException("Please implement the (static) Badge.print() method");
}
}
40 changes: 40 additions & 0 deletions exercises/concept/tim-from-marketing/src/test/java/BadgeTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

public class BadgeTest {

@Test
@Tag("task:1")
@DisplayName("Printing a badge for an employee")
public void labelForEmployee() {
Badge badge = new Badge();
assertThat(badge.print(17, "Ryder Herbert", "Marketing"))
.isEqualTo("[17] - Ryder Herbert - MARKETING");
}

@Test
@Tag("task:2")
@DisplayName("Printing a badge for a new employee")
public void labelForNewEmployee() {
Badge badge = new Badge();
assertThat(badge.print(null, "Bogdan Rosario", "Marketing")).isEqualTo("Bogdan Rosario - MARKETING");
}

@Test
@Tag("task:3")
@DisplayName("Printing a badge for the owner")
public void labelForOwner() {
Badge badge = new Badge();
assertThat(badge.print(59, "Julie Sokato", null)).isEqualTo("[59] - Julie Sokato - OWNER");
}

@Test
@Tag("task:3")
@DisplayName("Printing a badge for the owner who is a new employee")
public void labelForNewOwner() {
Badge badge = new Badge();
assertThat(badge.print(null, "Amare Osei", null)).isEqualTo("Amare Osei - OWNER");
}
}
2 changes: 2 additions & 0 deletions exercises/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ include 'concept:football-match-reports'
include 'concept:wizards-and-warriors'
include 'concept:calculator-conundrum'
include 'concept:logs-logs-logs'
include 'concept:tim-from-marketing'

// practice exercises
include 'practice:accumulate'
Expand Down Expand Up @@ -150,3 +151,4 @@ include 'practice:wordy'
include 'practice:yacht'
include 'practice:zebra-puzzle'
include 'practice:zipper'

0 comments on commit e937a27

Please sign in to comment.