Skip Top Navigation Bar

Educator Briefings

Included in this document are some of the updates and features that have been made in Java from Java 8 through the most current version of Java. This document has been designed to help educators and organizations that educate students at the high school and college level to become aware of new features that should be considered as part of an introduction to Java experience. The benefits of helping educators and organizations get current and stay current come in the form of keeping pace with the evolution of Java, ensuring students are being taught the expected industry standard for how code should be written, and to increase engagement of programming students using Java.

Updates to the core Java language are being released every 6 months, in September and March.

The features included in this brief are organized by release and separated into three categories: Features of Data Oriented Programming, Features to Increase Engagement, and Features to Support Instruction. For each feature, we have included a link to the corresponding JEP page, description of the feature, and some examples for how to use the feature.

The following is a summary chart of what can be found below:

Features for Data Oriented Programming

Release Status Feature
Java 24 Preview JEP 492: Flexible Constructor Bodies
Java 22 Finalized JEP 456: Unnamed Variables & Patterns
Java 21 Finalized JEP 441: Pattern Matching for switch
Java 21 Finalized JEP 440: Record Patterns
Java 17 Finalized JEP 409: Sealed Classes
Java 16 Finalized JEP 395: Records
Java 14 Finalized JEP 361: Switch Expressions
Java 10 Finalized JEP 286: Local-Variable Type Inference

Features to Increase Engagement

Release Status Feature
Java 24 Preview JEP 488: Primitive Types in Patterns, instanceof, and switch
Java 21 Finalized JEP 431: Sequenced Collections
Java 16 Finalized JEP 394: Pattern Matching for instanceof
Java 15 Finalized JEP 378: Text Blocks
Java 11 Finalized JEP 323: Local-Variable Syntax for Lambda Parameters
Java 9 Finalized JEP 269: Convenience Factory Methods for Collections
Java 8 Finalized JEP 126: Lambda Expressions & Virtual Extension Methods

Features to Support Instruction

Release Status Feature
Java 24 Preview JEP 495: Simple Source Files and Instance Main Methods
Java 23 Finalized JEP 467: Markdown Documentation Comments
Java 22 Finalized JEP 458: Launch Multi-File Source-Code Programs
Java 14 Finalized JEP 358: Helpful NullPointerExceptions
Java 11 Finalized JEP 330: Launch Single-File Source-Code Programs
Java 9 Finalized JEP 222: jshell: The Java Shell (Read-Eval-Print Loop)

Which new features should be incorporated into Introductory Computer Science courses?

This article provides an overview of features that are recommended for intro to CS courses to include.

Recommended Features for Intro CS

Categories:

The features listed in this section are recommended for inclusion in introductory computer science courses and data structures courses (i.e., CS 1 or CS 2 courses) that include a focus on data-oriented programming. These features reflect current, more modern ways of introducing programming using Java, beyond just object-oriented programming.

Features:

Originally previewed in JEP 447 with a second preview in JEP 482.

Constructors will be allowed to include statements that do not reference the instance being created prior to an explicit constructor call such as super(…) and this(…).

An example of a good use of this feature would be as a check on parameters being passed in prior to using them.

Uses in Intro to CS

Recommended to be included once finalized.

Learn more: JEP 492: Flexible Constructor Bodies (Third Preview)

When variable declarations or nested patterns are required but not used, an underscore (' _ ') can be used instead.

Some examples:

try {
  //something
} catch (Exception ex) {
   //error message
} 

The variable ex isn’t being used, so we could re-write as:

try {
  //something
} catch (Exception _ ) {
   //error message
}

Another example for when you want to grab a specific value in a record, but do not need the other data:

public class DogTester {
    public static void main(String [] args) {
     Dog d = new Dog(new LicName("Brady the Blue Brindle", "Brady"), "Whippet", 46.7);
     Cat c = new Cat("Sweetie", "Siamese", 7.5);
     ArrayList <Animal> animals = new ArrayList<Animal>();
     animals.add(d);
     animals.add(c);

     for (Animal a: animals) {
        if (a instanceof Dog(LicName(_,String nickname), _, _)) {
            System.out.println(nickName);
        }

        if (a instanceof Cat(String n, _, _)) {
            System.out.println(n);
        }
     }
   }
}

sealed interface Animal permits Dog, Cat {
} 

record Dog(LicName name, String Breed, double weight) implements Animal {
}

record Cat(String name, String Breed, double weight) implements Animal {
}

record LicName(String fullName, String nickname) {
}

Uses in Intro to CS

This would be recommended for any courses that include data in their course. Data science courses would benefit from the use of records and record patterns. Incorporating real-world data has the potential to increase engagement for students.

Learn more: JEP 456: Unnamed Variables & Patterns

Resources

This feature has considerable interaction with Record Patterns JEP 440: Record Patterns, which is covered above.

Similar to what we saw in Record Patterns, the Pattern Matching for Switch includes:

  1. a type check in the form of case checks;
  2. creation and assignment of variable; and
  3. typecasting of the variable.
sealed interface Animal permits Dog, Cat {
}

ArrayList<Animal> animList = new ArrayList<>();   

for (Animal a : animList) {
    switch (a) {

      //uses pattern matching to declare dog and assign it to (Dog)a
      case Dog dog: {
        System.out.println(dog.name().showName());
        break;  
      }
      case Cat cat: {
         System.out.println(cat.name());
         break;
      }
   }
}

Or combine with Unnamed Patterns and Variables (JEP 456: Unnamed Variables & Patterns) and rule switching with Lambda notation.

for (Animal a : animList) {
   switch (a) {
      //uses rule switch with lambda
      case Dog(LicenseName(_, String nickname), _, _) -> 
           System.out.println(nickName);
      case Cat(String name, _, _) -> System.out.println(name);
   }
}

Since we are using a sealed interfaces that only allows implementation with Dog and Cat, a default statement is not necessary.

Sealed Classes were finalized in the JDK 17 (JEP 409: Sealed Classes).

Uses in Intro to CS

This would be recommended for any courses that include data in their course. Data science courses would benefit from the use of records and record patterns. Incorporating real-world data has the potential to increase engagement for students.

Learn more: JEP 441: Pattern Matching for switch

Resources

This is an extension of JEP 394: Pattern Matching for instanceof, which allowed the instanceof operator to take a type pattern and perform pattern matching.

A pattern consists of a test and a set of local variables, known as pattern variables.

A type pattern consists of a test for the type of variable and a pattern variable.

sealed interface Animal permits Dog, Cat {
}

ArrayList<Animal> animList = new ArrayList<>();   

for (Animal a: animList) {
   //Old way 
   if (a instanceof Dog){
      Dog dog = (Dog) a;
      System.out.println("Dog: " + dog);
   }

   //New way
   if (a instanceof Dog dog) {
      System.out.println("Dog: " + dog);
   }

In the new way, a instanceof Dog dog completes the following:

  1. the type check;
  2. the creation and assignment of variable dog; and
  3. casts a to type Dog.

Rather than creating a new Dog dog, we can create variables for the instances variables of Dog we are actually going to use, as seen below.

if (a instanceof Dog(LicenseName (String showName, String nickName), String breed, double wt)) {      
   System.out.println(showName + " is a " + breed); 
}

NOTE: The Animal interface is a sealed interface. Sealed Classes were finalized in the JDK 17 (JEP 409: Sealed Classes).

Uses in Intro to CS

This would be recommended for any courses that include data in their course. Data science courses would benefit from the use of records and record patterns. Incorporating real-world data has the potential to increase engagement for students.

Learn more: JEP 440: Record Patterns

Resources

Sealed classes and interfaces restrict which other classes or interfaces can extend or implement them. This allows the originator to control which code has the responsibility for implementing it.

Using sealed classes and interfaces, support pattern matching for switch (JEP 441: Pattern Matching for switch) made final in the JDK 21 by allowing switch cases to be exhaustive without the need for a default clause.

For example, the Animal interface below allows for only Dog and Cat to implement it:

sealed interface Animal permits Dog, Cat {
}

Uses in Intro to CS

This would be recommended for any courses that include data in their course. Data science courses would benefit from the use of records and record patterns. Incorporating real-world data has the potential to increase engagement for students.

Learn more: JEP 409: Sealed Classes

In data-oriented programming, records allow us to treat data as non-modifiable, which is generally not the case for objects. Records are simply the right tool for dealing with non-modifiable data.

Records are simple to create and are meant to be used with non-modifiable data. The way in which they are designed protects the data from being altered making it the safer and right solution.

Consider a common CS 1 Project to write a Point class:

public class Point {
    private int x; 
    private int y;

    public Point() {
        x = 0; 
        y = 0;
    }

    public Point(int myX, int myY) {
        x = myX;
        y = myY;
    }

    public int getX() { 
        return x; 
    }

    public int getY() { 
        return y; 
    }
}

This class can be rewritten using a record as follows:

record PointRecord(int x, int y) {
}

The record supplies -

  • A constructor:

    PointRecord(int x, int y)
    
  • Accessor methods:

    -x()
    -y()
    

Below is an example of how to use the Point class and PointRecord record:

public static void main(String[] args) { 
    Point p = new Point();
    System.out.println("(" + p.getX() + ", " + p.getY() + ")");
    
    Point p2 = new Point(5, 7);
    System.out.println("(" + p2.getX() + ", " + p2.getY() + ")");
    
    PointRecord p3 = new PointRecord(-3, 4);
    System.out.println("(" + p3.x() + ", " + p3.y() + ")");
}

Records also include the following automatically:

  - toString()</li>
  - hashCode()</li>
  - equals()</li>

toString() Example:

public static void main(String [] args) { 
    Point p = new Point();
    System.out.println("(" + p.getX() + ", " + p.getY() + ")");
    
    Point p2 = new Point(5, 7);
    System.out.println("(" + p2.getX() + ", " + p2.getY() + ")");

    PointRecord p3 = new PointRecord(-3, 4);
    System.out.println("(" + p3.x() + ", " + p3.y() + ")");

    System.out.println(p);
    System.out.println(p2);
    System.out.println(p3);
}

Output:

(0, 0)
(5, 7)
(-3, 4)
Point@7bb11784
Point@33a10788
PointRecord[x=-3, y=4]

The first two are Point objects and we are getting a number generated by the Java Virtual Machine:

Point@7bb11784
Point@33a10788

The third one is a PointRecord object that contains a toString() method and prints:

PointRecord[x=-3, y=4]

equals() Example:

public static void main(String[] args) { 
    Point p = new Point();
    Point p2 = new Point(5, 7);
    PointRecord p3 = new PointRecord(-3, 4);
    PointRecord p4 = new PointRecord(0, 0);
    PointRecord p5 = new PointRecord(-3, 4);

    System.out.println(p3.equals(p4));
    System.out.println(p3.equals(p5));
    System.out.println(p3 == p5);
}

Output:

false
true
false
  • p3.equals(p4)

The equals() method will examine the instance variables of each object to see if they are equal. Since the x value of p3 is –3 and the x value of p4 is 0 AND the y value of p3 is 4 and the y value of p4 is 0, these two objects are not equal in value and the method returns false.

  • p3.equals(p5)

Since the x value of p3 and p5 are both –3 AND the y value of p3 and p5 are 4, these two objects are equal in value and the method returns true.

  • p3 == p5

While p3 and p5 are equal in value they are not the same object. Each object is distinct and stored separately in memory. Therefore, the method returns false.

Additional methods can be included in Records as well.

Uses in Intro to CS

This would be recommended for any courses that include data in their course. Data science courses would benefit from the use of records and record patterns. Incorporating real-world data has the potential to increase engagement for students.

Learn more: JEP 395: Records

Resources

Extends the switch semantics. Now a switch can be an expression.

For example:

int grade = 9;
String gradeText = switch(grade) {
   case 9, 10: {
      yield "Under-classman";  
   }
   case 11, 12: {
      yield "Upper-classman";
   }
   default: {
      yield "Other";
   }
}; 

For switch expressions, yield is used to return the value of the expression. There is no fall through in switch expressions.

int month = 5; 
String myMonth = switch(month) {
  case 1 -> "January";
  case 2 -> "February";
  case 3 -> "March";
  case 4 -> "April";
  case 5 -> "May";
  case 6 -> "June";
  case 7 -> "July";
  case 8 -> "August";
  case 9 -> "September";
  case 10 -> "October";
  case 11 -> "November";
  case 12 -> "December";
  default -> "That is not a month"; 
};
System.out.println (myMonth);

In this case, the lambda-style arrow notation ( -> ) specifies the return the value of the expression. As it is an expression, there is no fall through.

Uses in Intro to CS

This would be recommended for any courses that include data in their course. Data science courses would benefit from the use of records and record patterns. Incorporating real-world data has the potential to increase engagement for students.

Learn more: JEP 361: Switch Expressions

Resources

In cases where the type of the variable can be inferred, the keyword var can be used instead of the type. These cases include local variables being declared with initializers, enhanced for-loops indexes, and index variables declared in traditional for loops. You can also use var for arguments in lambda expressions and for pattern variables in record patterns.

Some examples of variable declarations are as follows:

var brady = new Dog();
var wordlist = new ArrayList<String> ();

An example of an enhanced for-loop is as follows:

for (var word : wordlist) { ...

Uses in Intro to CS

The use of var could be incorporated in the earliest introductory computer science course.

Some examples of improper uses of var are as follows:

  • var wordlist;

Without an initialization, the compiler is unable to infer the type of wordlist.

  • var brady = null;

Since null can be assigned to objects of any type, the compiler is unable to infer the type of brady.

Learn more: JEP 286: Local-Variable Type Inference

Resources

The following features might be useful in creating more engaging lab experiences for students and foster an increased engagement.

Originally previewed in JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview).

This preview features is an enhancement to pattern matching to extend the instanceof (JEP 394: Pattern Matching for instanceof) and switch (JEP 441: Pattern Matching for switch) to work with primitive variables.

Previously, you could only use instanceof on reference types, to answer the question of whether an object was of a specific type. With primitive patterns you can use instanceof with primitive types, to answer the question of whether the variable can be represented by a specific type without any loss of precision or data.

For example, we can say:

int x = 100; 
if (x instanceof byte b) {
   System.out.println (b + " is in the byte range");
else{
   System.out.println (b + " is not in the byte range");
}

We can now switch over all primitive types. If we are using a switch expression, then we will need to be sure that all cases are being covered. We do this by including cases with additional guards. For example, we can say:

int x = //…
String result = switch (x){
  case 0 -> "zero";
  case int y when y < 0 -> "negative";
  case int _ -> "positive";
}

Some important things to note here. The reserved word when is being used as a condition for the second case statement. We cannot use when again in the third case as it would cause the compiler to detect that the switch statement is not exhaustive. We use the last case statement as an option for all cases that aren’t the first two cases. This makes the switch exhaustive as required.

Also, note that since we are not using the variable in the third case, we can simply use an unnamed variable (_) as a placeholder. Please see JEP 456: Unnamed Variables & Patterns for more information on unnamed variables.

We can also use switch expression instead of the ternary conditional operator (?:). We can also use a switch to allow for statements as well as expressions.

For example, we could use the ternary conditional operator:

String result = (x % 2 == 0) ? "Even" : "Odd";

Which is equivalent to this if..else statement:

if (x % 2 == 0) {
   result = "Even";
} else {
   result = "Odd";
}

And finally using a switch expression:

String result = switch(x % 2 == 0) {
   case true -> "Even";
   case false -> "Odd";
};

If we would rather report out on this information, we could write the following:

switch(x % 2 == 0) {
   case true -> System.out.println ("Even");
   case false -> System.out.println ("Odd");
}

In this case the ternary conditional operator would not allow for a statement, since it uses expressions only. We could use an if..else statement here as well.

Uses in Intro to CS

Switch statements and switch expressions in general may help increase students understanding of conditionals and in some cases are better than using a long series of if..else statements. Students who learn ternary conditional operators, may choose to write their solutions using switch expressions instead. This feature has the potential to increase engagement for students.

Learn more: JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)

Resources

In addition to the Collection class, the ArrayList class now also implements the SequencedCollection. The SequencedCollection, contains the following new methods which would be considered legal Java during the AP Computer Science A exam:

  • addFirst(E e) – adds an element as the first element of this collection
  • addLast(E e) – adds an element as the last element of this collection
  • getFirst() – Gets the first element of this collection
  • getLast() – Gets the last element of this list
  • removeFirst() – Removes and returns the first element of this collection
  • removeLast() – Removes and returns the last element of this collection
  • reversed() – Returns a reverse-order view of this collection

Uses in Intro to CS

This new content could impact course work where students are asked to access or move specific elements or to add element to an ArrayList by adding each element to the front of the list. This feature could have an impact on specific sorting algorithms.

Learn more: JEP 431: Sequenced Collections

Resources

A pattern consists of a test and a set of local variables, known as pattern variables.

A type pattern consists of a test for the type of variable and a pattern variable.

sealed interface Animal permits Dog, Cat {
}

ArrayList<Animal> animList = new ArrayList<>();   

for (Animal a: animList) {
   //Old way 
   if (a instanceof Dog) {
      Dog dog = (Dog)a;
      //do something with dog
   }
   //New way
   if (a instanceof Dog dog) {
         //do something with dog
   }
}

Uses in Intro to CS

This would be recommended for any courses that include data in their course. Data science courses would benefit from the use of records and record patterns. Incorporating real-world data has the potential to increase engagement for students.

Learn more: JEP 394: Pattern Matching for instanceof

Resources

A text block is a multi-line string literal that avoids the needs for most escape sequences, automatically formats the string in a predictable way, and gives the developer control over the format when desired.

The opening delimiter is a sequence of three double quote characters (""") followed by zero or more white spaces followed by a line terminator.

The content begins at the first character after the line terminator of the opening delimiter and ends at the last character before the first double quote for the closing delimiter.

The closing delimiter is a sequence of three double quote characters (""").

Some examples:

System.out.println("first\nsecond\nthird\n");

Prints the same result as:

System.out.println("""
first
second
third
""");

While a line terminator is required after the opening delimiter, it is not required before a closing delimiter.

The following will cause an error since there is no line terminator before the word first.

System.out.println("""first
second
third
""");

However, the line terminator after third is not required and the following will produce the same result as the original example.

System.out.println("""
first
second
third""");

Uses in Intro to CS

Could impact how students respond to coursework and questions that require them to create strings using a particular spacing.

Learn more: JEP 378: Text Blocks

Relates to JEP 286: Local-Variable Type Inference.

This feature allows the use of var when establishing the parameters in lambda expressions.

For example, consider the following Computations interface:

public interface Computations {
   public double operation(double first, double second);
}

We can define the functionality of operation as follows:

Computations subt = (f, s) -> f - s;
System.out.println(subt.operation(3, 2));

We can also define the functionality of operation using var as follows:

Computations subt = (var f, var s) -> f - s;
System.out.println(subt.operation(3, 2));

This aligns the syntax of the formal parameters in lambda expressions with the syntax of a local variable declaration.

Uses in Intro to CS

For courses that are currently incorporating lambda, this feature should be included in the course of study.

Learn more: JEP 323: Local-Variable Syntax for Lambda Parameters

This feature allows for small non-modifiable sets of data to be set to Lists, Maps, and Sets, using the of method.

For example, instead of adding the following names to a student roster by calling the add method repeated, such as:

List<String> roster = new ArrayList<>();
roster.add("Mark");
roster.add("Liam");
roster.add("Aidan");
roster.add("Emelia");

If the roster is non-modifiable, meaning we won’t need to add, remove, or change any of the elements, we can create the list using the of method. This is similar to using an initializer list with arrays. For example:

List<String> names = List.of("Mark", "Liam", "Aidan", "Emelia");

Note that you cannot add any null values to list created with the List.of() factory method.

Uses in Intro to CS

This would be recommended for any courses that include data in their course. Data science courses would benefit from the use of records and record patterns. Incorporating real-world data has the potential to increase engagement for students.

Learn more: JEP 269: Convenience Factory Methods for Collections

Full details on Project Lambda can be found here: OpenJDK: Project Lambda

Lambda’s allow programmers to implement an interface that contains one method, without having to write the full class. They consist of a parameter list, the arrow token, and a return value based on the body of the code statements.

For example, consider the following Computations interface:

public interface Computations {
    public double operation(double first, double second);
}

We could create classes AdditionComputation and MultiplyComputation as well as several others, such as:

public class AdditionComputation implements Computations {
   @Override
   public double operation(double first, double second) {
      return first + second;
   }
}

public class MultiplyComputation implements Computations {
   @Override
   public double operation(double first, double second) {
      return first * second;
   }
}

To use these classes, we might write the following:

public class LambdaTester {
   public static void main(String[] args) {
      AdditionComputation add = new AdditionComputation();
      MultiplyComputation mult = new MultiplyComputation();
      System.out.println(add.operation(5.3, 2.3));
      System.out.println(mult.operation(5, 3));
   }
}

This would mean that every time we wanted to provide unique functionality for the operation method in Computations and use it, we would need to first create a class that implements Computations, then create an instance of this class, and finally call operation.

If we use lambda, we can create an instance of Computations that can be used to call the operation method and provide the functionality as part of declaring and creating that instance.

For example:

Computations subt = (f, s) -> f - s;
System.out.println(subt.operation(3,2));

Uses in Intro to CS

The use of lambda would be appropriate in a course where interfaces are being used. Additionally, it could easily be incorporated into any course that uses data and ArrayList. Some examples of the ArrayList forEach method are as follows.

The forEach method of the Collection interface takes a Consumer object as a parameter. Consumer is an interface that has an accept method that needs to be implemented. The accept method performs an operation on the given argument.

The following examples pass the implementation of the method accept as an argument to the forEach method. The accept method is void, so we have included the output statement as part of the implementation.

The following prints out all of the values of the list:

names.forEach((n) -> System.out.println(n));`

The following prints out all of the values that have a length greater than 4:

names.forEach((n) -> {
  if (n.length() > 4) {
      System.out.println(n);
  }
});

The following prints out the values that start with the letter "A":

names.forEach((n) -> {
   String first = n.substring(0,1);
   if (first.equals ("A")) {
      System.out.println(n);
   }
});

The implementation of a lambda expression can use variable defined outside of itself, as long as they are final, or at least not modified. In that case, the compiler can make this variable final for you. These non-final variable that can be made final by the compiler are called effectively final variables. The following code wouldn’t work because it requires the use of a local variable, and tries to modify it. So this local variable is not final, and cannot be made final.

int sum = 0; 
names.forEach((n) -> {
   sum += n.length();
});
System.out.println(sum/names.size());

Learn more: JEP 126: Lambda Expressions & Virtual Extension Methods

Resources

The following features could impact the way the course is taught. Many of these features make introducing new topics easier for students. This section will also include deprecated APIs that will no longer be supported in the future, yet we know that some teachers might still be using these materials.

Features:

Originally previewed in JEP 445: Unnamed Classes and Instance Main Methods (Preview), second preview in JEP 463: Implicitly Declared Classes and Instance Main Methods (Second Preview) and third preview in JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview).

Great for beginners just learning Java, Simple Source Files and Instance Main Methods allows new and experienced programmers to write smaller programs succinctly, without the need for constructs intended for programming in the large. This is great for beginners and those who want to rapidly prototype or try code snippets.

This preview feature automatically imports three static methods for simple text input and output with the console. These methods are declared in the new top-level class java.io.IO.

Instead of:

public class MyClass {
   public static void main(String [] args) {
       System.out.println ("Java Rocks!");
   }
}

We can write the following:

void main() {
   println ("Java Rocks!");
}

It also automatically imports the top-level classes in the java.base module. This includes java.util which will allow for the use of ArrayList without import statements. Other useful classes that are included and could be incorporated in an introductory CS course to raise engagement are: java.time, java.text, java.io, and java.math.

Uses in Intro to CS

This content is shared as an instructional tool to help get students into the core Java content more quickly. It is similar to products that include an interactions pane with the added benefit of the code being in a .java file so it can be saved, tweaked, and run multiple times without having to re-type.

Another resource that allows teachers to learn about and demonstrate code snippets is the Java Playground. NOTE: this is not an online IDE and doesn’t allow for saving program code.

Learn more: JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)

In addition to being able to write documentation comments in JavaDoc and HTML, you can now use Markdown. Markdown is typically much easier to write and read within the code and translates to HTML.

Uses in Intro to CS

Comments written in markdown are easier to read and write within the code than HTML. If you would like to include more formatting in comments for starter code, using markdown would be the right tool to use.

Learn more: JEP 467: Markdown Documentation Comments

Expands prior JEP 330: Launch Single-File Source-Code Programs by allowing multiple files to be compiled and run at the same time, rather than needing to compile the files first and then run them.

Uses in Intro to CS

Multi-file and single-file source-code launcher provides instructors and students with more options in terms of tools that can be used and how they approach introducing concepts to students.

Single-file and multi-file source-code works well in jShell or IDEs that leverage jShell.

Learn more: JEP 458: Launch Multi-File Source-Code Programs

A helpful upgrade to NullPointerException errors. At the point in a program where code tries to access a null reference, an exception message will be displayed that names which variable was null.

Uses in Intro to CS

A helpful instructional tool that gives a little more information and can help identify the source of the exception better.

Learn more: JEP 358: Helpful NullPointerExceptions

This new feature allows multiple classes to be saved in the same .java file.

For example, saved in the DogTester.java file:

class Dog {
   private String name; 
   private String breed;
   private double weight; 

   public Dog(String n, String b, double w) {
      // body  
   }
}
public class DogTester {
   public static void main(String[] args) {
      Dog d = new Dog("Brady", "Whippet", 42); 
      ...
   }
}

The name of the file should be the same as the class that contains the main method.

You can add multiple classes or records. For example:

public class DogTester {
   public static void main(String [] args) {
       Dog d = new Dog(new LicName("Brady the Blue Brindle", 
              "Brady"), "Whippet", 46.7);
       System.out.println(d);
   }
}

record Dog(LicName name, String Breed, double weight) {
}

record LicName(String fullName, String nickname) {
}

Uses in Intro to CS

Single-file source-code launcher provides instructors with more options in terms of tools that can be used and how they approach introducing concepts to students.

Single-file source-code works well in jShell, IDEs that leverage jShell, and the Java Playground.

Learn more: JEP 330: Launch Single-File Source-Code Programs

JShell allows for rapid prototyping of lines of code, or snippets.

Requires the use of the command prompt to run the program code.

Uses in Intro to CS

This feature could be used in the earliest introductory computer science course as a way to introduce new topics and quickly demonstrate the functionality associated with particular snippets of code.

Learn more: JEP 222: jshell: The Java Shell (Read-Eval-Print Loop)