Java Fundamentals  «Prev  Next»
Lesson 1

Elements of the Java Programming Language

This module examines the fundamentals of the Java programming language. Topics covered in this module include tokens and comments, as well as data types, arrays, and strings. You will learn how Java evaluates expressions, and You will also learn about some of the different Java operators.

Java SE 17 uses Lexical Tokens

Even in Java SE 17, the basic building blocks of the language are still lexical tokens. These remain the fundamental units that the compiler recognizes and processes to understand your code. While some details of specific keywords or features might have evolved across different versions, the overall concept of lexing your code into tokens remains fundamental to Java's compilation process.
Here's a quick breakdown of the main types of lexical tokens in Java:
  1. Identifiers: Names you define, like variables, classes, or methods.
  2. Keywords: Reserved words with specific meanings in the language, like `if`, `for`, or `public`.
  3. Literals: Fixed values like numbers, strings, or characters.
  4. Separators: Symbols like punctuation marks separating different parts of your code, like `(`, `)`, or `;`.
  5. Operators: Symbols that perform operations on data, like arithmetic operators (`+`, `-`, `*`), comparison operators (`==`, `<`), or logical operators (`&&`, `||`).
  6. Comments: Text ignored by the compiler, used for documentation or explaining code.

While new features and syntax additions might occur in later versions, the foundation of breaking down code into these basic units remains unchanged.


Module Learning Objectives

After completing the module, You will have the skills and knowledge necessary to:
  1. Describe how Java code is broken down into tokens
  2. Explain the different types of comments supported in Java
  3. Use Java's different data types
  4. Evaluate expressions in Java
  5. Use numeric, Boolean, string and assignment operators


Appropriate use of Generics

In the Java programming language, the utilization of generics introduces a mechanism for type safety and reusability across different kinds of data types and algorithms. When determining the appropriate usage of generics, developers should identify specific use cases and programming scenarios where their application can yield significant benefits. The key areas to consider include:
  1. Type Safety and Error Prevention: Generics enable developers to enforce a more stringent type check at compile time, thereby preventing runtime errors related to type casting. Use cases where the application manipulates collections of objects, and there's a need to ensure that only objects of a specific type are added or retrieved, are prime candidates for generics. This preemptive error checking mechanism significantly reduces the risk of `ClassCastException`.
  2. Code Reusability and Abstraction: Generics allow for the creation of classes, interfaces, and methods that operate on a parameterized type, making them applicable to a wide range of data types. This is particularly useful in scenarios where the same logic or algorithm needs to be applied to different types of data, such as sorting algorithms, data structures (like lists, maps, sets), and utility methods. The ability to abstract over types leads to more modular, readable, and reusable code.
  3. API Design and Framework Development: When developing libraries or frameworks that will be used by other developers, employing generics can make the API more flexible and easier to use. It allows API consumers to specify their own types while still benefiting from the strong type checking that generics provide. This is especially relevant for collections frameworks, I/O libraries, and any utility libraries that offer generalized operations on objects.
  4. Avoidance of Explicit Type Casting: In the absence of generics, developers often resort to using the base `Object` type to achieve generality, which necessitates explicit type casting when retrieving elements from a collection or data structure. Generics eliminate the need for such casts, thus making the code cleaner, more readable, and less prone to runtime errors.
  5. Enhanced Performance: While not the primary motivation for using generics, avoiding explicit type casting can lead to slight performance improvements, as the overhead associated with casting is reduced. Scenarios involving high-performance computing or processing large data sets might benefit marginally from this aspect of generics.

In summary, the adoption of generics in Java should be guided by the objectives of enhancing type safety, promoting code reusability and abstraction, improving API design, reducing the need for explicit type casting, and potentially enhancing performance. Identifying use cases and programming scenarios where these objectives align with the project's goals is crucial in determining the appropriate application of generics.
Question: Which of the following code fragments is/are appropriate usage(s) of generics? [Select 1 option: ]
  1. Map < String, List <String> > myMap = new HashMap();
  2. List <String> list = new ArrayList< >(); 
    list.add("A");
    list.addAll(new ArrayList< >()); 
    
  3. List <String> list = new ArrayList< >();
    list.add("A");
    List<? extends String> list2 = new ArrayList< >();
    list.addAll(list2); 
    
  4. List< >(); list = new ArrayList <String >();


Answer: c
Explanation:
  1. Although this is valid code, it is not a good use of generics because when you execute new HashMap(), you create a raw HashMap and it will produce a warning at compile time.
    Note that to take advantage of automatic type inference during generic class instantiation, you must specify the diamond operator. that is, you must use new HashMap<>() in this case.
  2. Java SE 7 supports limited type inference for generic instance creation; you can only use type inference if the parameterized type of the constructor is obvious from the context. In this option, the last line will not compile because the list.addAll() method expects
    Collection<? extends String> 
    

    and so the compiler cannot infer the generic type for ArrayList.
  3. c. is the correct answer.
  4. The diamond operator is used at the place of creation of the object and not at the place of variable type declaration.
    So it should be: List<String> list = new ArrayList< >();

SEMrush Software