diff --git a/source/ap-java-cheatsheet.ptx b/source/ap-java-cheatsheet.ptx index f272981..7e8f94a 100644 --- a/source/ap-java-cheatsheet.ptx +++ b/source/ap-java-cheatsheet.ptx @@ -10,7 +10,7 @@ The following is intended to be useful in better understanding Java functions coming from a Python background.

- + Function/Method Equivalents: Python to Java @@ -201,5 +201,4 @@

- \ No newline at end of file diff --git a/source/ch1_overview.ptx b/source/ch1_overview.ptx index 7c1da79..59ce40e 100644 --- a/source/ch1_overview.ptx +++ b/source/ch1_overview.ptx @@ -5,17 +5,17 @@ Overview -
- Introduction to Java for Python Programmers +
+ Prerequisites and Trajectory

This book assumes that you are already familiar with the Python programming language. - We will use Python as a starting point for our journey into Java. + We will use Python as a starting point for our journey into Java. We will begin by looking at a very simple Java program, just to see what the language looks like and how we get a program to run. Next, we will look at the main constructs that are common to most programming languages:

-
+

  • @@ -26,313 +26,311 @@
  • - Loops + User input and output

  • - Reading user input + Conditionals and Exception Handling

  • -
  • - Conditionals + Loops and Iteration

-

- Once we have the basics of Java behind us we will move on to look at the features of Java that are both unique and powerful. + Once we have the basics of Java behind us we will move on to look at more powerful features of the language.

-
+

  • - Classes + Classes and Interfaces

  • -
  • - Interfaces + Recursion

  • -
  • - Collections + File Handling

  • -
  • -

    - Graphical User Interface Programming -

    -
  • -
  • -

    - Generic Programming -

    -

-
+

+ Finally, we will look at common errors and how to find the help you need. +

-
+
Java Development Environment - -

- Thank you to Beryl Hoffman for contributing to this section from her CSAwesome: AP Java Programming book. -

-
- -

+

compilerintegrated development environmentIDE The tool that we use to compile a Java source file into a Java class file is called a compiler. Most programmers use an - Integrated Development Environment (IDE) that has the + integrated development environment (IDE) that has the compiler built in and helps you write, compile, run, and debug programs.

-

+

Active Codeload history You can learn Java by just using the interactive coding panels called Active Code in this e-book. If you are logged in, the Active Code will remember your changes and even show you a history of your - changes to the code if you click on Load History. + changes to the code if you click on Load History.

- However, it’s a good idea to also try a Java IDE to build code outside of - this e-book, especially to try coding with user input which Active Code - cannot do. There are many Java IDEs available. + However, it's a good idea to also try a Java IDE to build code outside of + this online book. There are many Java IDEs available. If you are enrolled in a course, your instructor will likely recommend one, so you should learn to use that one.

- - Java IDE Options + + Installing Java +

JDKJava development kitOracleOpenJDK + Before you can use any Java IDE or compile Java programs, you need to install the Java development kit (JDK) on your computer. The JDK includes the Java compiler, the Java runtime environment, and many essential tools for Java development. You can either download the latest version of the JDK from Oracle's website (https://www.oracle.com/java/technologies/downloads/) or use OpenJDK, which is a free and open-source implementation available at https://openjdk.org/. Most IDEs will help you configure the JDK once it's installed, but you'll need to have it on your system first. To verify your installation works, you can open a command prompt or terminal and type java -version - you should see version information displayed. +

+
+ + + Github Classroom and Codespaces +

GitHubversion controlCodespaces + GitHub is the largest source code repository host in the world, with over 300 million repositories and a global community of more than 100 million developers. Github is widely used for both open-source and private projects, making it a versatile platform for various development needs, and a great place to learn about version control and collaboration in software development. + Github provides many free opportunities for both students and teachers (https://docs.github.com/en/education/quickstart). + Github Classroom (https://classroom.github.com/) + allows teachers to set up a classroom based on Github repositories. Github + and git are both very widely used in the computer industry, so learning to use + them is great experience for students who want to showcase their skills. Github now has a cloud IDE called + Codespaces (https://github.com/features/codespaces) + which you can use for 60 hours a month for free or completely free if you + join as a school or get approved as a teacher or student. In Codespaces, + you can start from a blank template or repository, open a .java file in the + VSCode editor, follow prompts to install the Extension Pack for Java, + click on the Run and Debug (play button), follow the prompts to install + the Java debugger, and see the output of your code in the terminal. You + can also use Copilot (https://github.com/features/copilot), + which is a coding AI based on GPT, for free if you are approved for + educational use. +

+

- There are a lot of online cloud IDEs where you can code online in many - programming languages. Most are free to start, but offer different - features for a price. These are great options if you are using a - Chromebook or you cannot install software on your computer or you want an - easy no-installation option. Some of the Active Code samples in this - e-book also include a link to online IDEs. These projects can be copied to - make your own copy. -

- -

Here are some popular online IDEs:

-

-

    -
  • -

    - CodeHS (https://codehs.com/) has a free Sandbox online IDE - (https://codehs.com/app/sandbox) - where you can run Java and Java Swing programs. Students can share the links - to their code and the history of their code is saved. CodeHS has free and paid features. - Grading features are in the paid version. -

    -
  • -
  • -

    - PickCode (https://pickcode.io/) is another - online IDE that offers many free and paid features for setting up - classrooms. In the free version, tudents can share links to their code and - the history of their code is saved. Classroom features are in the paid version. -

    -
  • -
  • -

    - Replit (https://replit.com/) an online - IDE which recently switched to only allowing 3 projects at a time - for free. Be aware that Replit has turned on its AI feature for code - completion for all accounts (https://replit.com/ai). Each - user can turn the AI on and off at the bottom of the code window, - and use an AI chat window to ask questions of the AI. -

    -
  • + To use Github classroom, students need to sign up for a free Github account (https://github.com/signup) if + they don't already have one in order to use Codespaces. +

    + -
  • -

    - JuiceMind (https://juicemind.com/) is an - online IDE that offers many free and paid features for teachers to - set up classrooms like Coding Rooms. It has a built-in version of - CSAwesome. -

    -
  • -
-

-
- - - Github Classroom and Codespaces -

- Github provides many free opportunities for students and teachers (https://docs.github.com/en/education/quickstart). - Github Classroom (https://classroom.github.com/) - allows teachers to set up a classroom based on github repositories. Github - and git are both widely used in the computer industry, so learning to use - them is great experience for students. Github now has a cloud IDE called - Codespaces (https://github.com/features/codespaces) - which you can use for 60 hours a month for free or completely free if you - join as a school or get approved as a teacher or student. In Codespaces, - you can start from a blank template or a repo, open a .java file in the - VSCode editor, follow prompts to install the Extension Pack for Java, - click on the Run and Debug (play button), follow the prompts to install - the Java debugger, and see the output of your code in the terminal. You - can also use Copilot (https://github.com/features/copilot), - which is a coding AI based on GPT, for free if you are approved for - educational use. -

- -

- Students will need to sign up for a free Github account (https://github.com/signup) if - they don’t already have one in order to use Codespaces. -

-
- - - VSCode -

- VSCode (https://code.visualstudio.com) - is a widely used coding editor which you can download on your local - computers. It has many useful extensions. The code can be run in a - terminal window in the editor. See https://code.visualstudio.com/docs/languages/java - for Java support. This editor is different than Microsoft Visual Studio - which is a very large IDE. -

+ + Desktop IDE Options +

+ To install Java software on your local computer, below are several popular Java IDEs and editors that you can download and install. Please be sure to use the one that is recommended by your instructor if you are enrolled in a course, as they may have specific preferences or requirements. +

+ +

+

    +
  • +

    + VSCode (https://code.visualstudio.com) is not an IDE per se, but it + is a widely used coding editor which you can download on your local + computer with many useful extensions like debugging tools that for all practical purposes make it behave like an IDE. It is frequently used in combination with Github Classroom. See https://code.visualstudio.com/docs/languages/java + for Java support. Note that the VSCode editor is not the same as the Microsoft Visual Studio IDE which is a very large IDE that is not widely used for Java. +

    +
  • + +
  • +

    + IntelliJ IDEA (https://www.jetbrains.com/idea/) + is a free Java IDE from JetBrains which many professionals use. It is a + little easier to configure than Eclipse. Here is a guide on how to + set up IntelliJ: https://www.jetbrains.com/help/idea/install-and-set-up-product.html. +

    +
  • + +
  • +

    + Eclipse (https://www.eclipse.org/downloads/packages/installer) + is what many professional Java programmers use. It may be a little complex + for beginners. Here are some installation and configuration instructions + for Eclipse for Java beginners: http://skylit.com/javamethods/faqs/Eclipse.pdf. +

    +
  • + +
  • +

    + DrJava (http://DrJava.org) is a free, simple, + easy to install and use development environment. One nice feature is the + interactions pane at the bottom which lets you try out Java code without + having to create a class first. +

    +
  • + +
  • +

    + BlueJ (https://www.bluej.org/) is a free + Java IDE designed for beginners. It is built to explore objects and + object-oriented programming and has a teachers' community as well as a + playlist of videos online https://www.youtube.com/playlist?list=PLYPWr4ErjcnzWB95MVvlKArO6PIfv1fHd + to go with the BlueJ Object-First Java book. +

    +
  • + +
  • +

    + jGRASP (https://www.jgrasp.org/) is a free + lightweight development environment, created specifically to provide + automatic generation of software visualizations. jGRASP is implemented in + Java, and runs on all platforms with a Java Virtual Machine (Java version + 1.5 or higher). jGRASP produces Control Structure Diagrams (CSDs) for + Java, C, C++, Objective-C, Python, Ada, and VHDL; Complexity Profile + Graphs (CPGs) for Java and Ada; UML class diagrams for Java; and has + dynamic object viewers and a viewer canvas that work in conjunction with + an integrated debugger and workbench for Java. The site includes both + intro video and PDF tutorials. +

    +
  • + +
  • +

    + NetBeans (https://netbeans.org/) is one of the + original Java IDEs. Here is a tutorial on how to set it up: https://netbeans.org/kb/docs/java/quickstart. +

    +
  • +
+

- - Dr. Java -

- DrJava (from http://DrJava.org) is a free, simple, - easy to install and use development environment. One nice feature is the - interactions pane at the bottom which lets you try out Java code without - having to create a class first. -

-
- - - BlueJ -

- BlueJ (https://www.bluej.org/) is a free - Java IDE designed for beginners. It is built to explore objects and - object-oriented programming and has a teachers’ community as well as a - playlist of videos online https://www.youtube.com/playlist?list=PLYPWr4ErjcnzWB95MVvlKArO6PIfv1fHd - to go with the BlueJ Object-First Java book. -

-
- - - jGRASP -

- jGRASP (https://www.jgrasp.org/) is a free - lightweight development environment, created specifically to provide - automatic generation of software visualizations. jGRASP is implemented in - Java, and runs on all platforms with a Java Virtual Machine (Java version - 1.5 or higher). jGRASP produces Control Structure Diagrams (CSDs) for - Java, C, C++, Objective-C, Python, Ada, and VHDL; Complexity Profile - Graphs (CPGs) for Java and Ada; UML class diagrams for Java; and has - dynamic object viewers and a viewer canvas that work in conjunction with - an integrated debugger and workbench for Java. The site includes both - intro video and PDF tutorials. -

-
- - - IntelliJ -

- IntelliJ (https://www.jetbrains.com/idea/) - is a free Java IDE from JetBrains which many professionals use. It is a - little easier to configure than Eclipse below. Here is a guide on how to - set up IntelliJ: https://www.jetbrains.com/help/idea/install-and-set-up-product.html. -

-
- - - Netbeans -

- Netbeans (https://netbeans.org/) is one of the - original Java IDEs. Here is a tutorial on how to set it up: https://netbeans.org/kb/docs/java/quickstart. -

-
- - - Eclipse -

- Eclipse (https://www.eclipse.org/downloads/packages/installer) - is what many professional Java programmers use. It may be a little complex - for beginners. Here are some installation and configuration instructions - for Eclipse for Java beginners: http://skylit.com/javamethods/faqs/Eclipse.pdf. -

-
-
+ + Java Online IDE Options +

+ There are also a lot of online cloud IDEs where you can code online in many + programming languages. Most are free to start, but offer different + features for a price. These are great options if you are using a + Chromebook or you cannot install software on your computer or you want an + easy no-installation option. +

-
- Why Learn another programming Language? +

Here are some popular online IDEs:

+

+

    +
  • +

    + CodeHS (https://codehs.com/) has a free Sandbox online IDE + (https://codehs.com/app/sandbox) + where you can run Java and Java Swing programs. Students can share the links + to their code and the history of their code is saved. CodeHS has free and paid features. + Grading features are in the paid version. +

    +
  • +
  • +

    + PickCode (https://pickcode.io/) is another + online IDE that offers many free and paid features for setting up + classrooms. In the free version, students can share links to their code and + the history of their code is saved. Classroom features are in the paid version. +

    +
  • +
  • +

    + Replit (https://replit.com/) an online + IDE which recently switched to only allowing 3 projects at a time + for free. Be aware that Replit has turned on its AI feature for code + completion for all accounts (https://replit.com/ai). Each + user can turn the AI on and off at the bottom of the code window, + and use an AI chat window to ask questions of the AI. +

    +
  • +
  • +

    + JuiceMind (https://juicemind.com/) is an + online IDE that offers many free and paid features for teachers to + set up classrooms like Coding Rooms. It has a built-in version of + CSAwesome. +

    +
  • +
+

+ +

+ Thank you to Beryl Hoffman for contributing to this section from her CSAwesome: AP Java Programming book. +

+
+
+ +
+ Why Another Programming Language? + +

dynamic languagestatic languages + Python Java Python is a nice language for beginning programming for several reasons. First the syntax is sparse, and clear. Second, the underlying model of how objects and variables work is very consistent. Third, you can write powerful and interesting programs without a lot of work. - However, Python is representative of one kind of language, called a dynamic language. - You might think of Python as being fairly informal. - There are other languages, like Java and C++ that are more formal. + However, Python is representative of one kind of language, called a dynamic language. In dynamic languages like Python, the type of a variable (whether it's a number, string, list, etc.) is determined while the program is running, not when you write the code. +

+ +

In static languages, all variable types need to be declared upfront. + You might think of Python as being fairly informal about data types. + Java and C++ are more formal about types.

-

+

performance These languages have some advantages of their own. - First, is speed: Java and C++ code will generally give better performance than Python code. (See .) - Second is their maintainability. + First, is speed: Java and C++ code will generally give better performance than Python code. (See .) + Second is their maintainability over time. Maintainability is the ease with which a program can be modified to correct faults, improve performance, or adapt to a changed environment. A lot of what makes Python easy to use is that you must remember certain things. - For example if you set variable x to reference a turtle, and forget later that x is a turtle but try to invoke a string method on it, you will get an error. + For example, if you set Python variable x to reference a turtle, and forget later that x is a turtle but try to invoke a string method on it, you will get an error. Java and C++ protect you by forcing you to be upfront and formal about the kind of object each variable is going to refer to.

-

- In one sense Python is representative of a whole class of languages, sometimes referred to as “scripting languages.” Other languages in the same category as Python are Ruby and Perl. - Java is representative of what I will call industrial strength languages. - Industrial strength languages are good for projects with several people working on the project where being formal and careful about what you do may impact lots of other people. - Languages in this category include Rust, C++, C#, and Ada. +

scripting language industrial strength languages + In one sense Python is representative of a whole class of languages, sometimes referred to as scripting languages. Other languages in the same category as Python are JavaScript, Ruby, and Perl. + Java is representative of what we might call industrial strength languages. + Industrial strength languages are good for large projects with multiple programmers, where being formal and careful about code structure is important because changes made by one person can impact many others. + Other industrial strength languages include Rust, C++, C#, and Ada.

@@ -349,7 +347,7 @@

- Although Python code is generally slower than Java and C++ code, in practice Python programs can achieve equivalent performance. + Although Python code is generally slower than Java and C++ code, in practice Python programs can achieve equivalent performance. Performance can be defined as how efficiently software can accomplish its tasks. This can be done by compiling Python code to C code (see: Cython) or by calling high-performance libraries from Python (e.g., NumPy, scikit-learn, etc.). So native language performance is just one criteria to consider when deciding which language to use for a program.

@@ -357,7 +355,7 @@
-
+
Why Learn Java? Why not C or C++?

@@ -367,16 +365,17 @@

  • -

    - Java includes a larger standard library than C or C++, which means that sophisticated programs can be created in Java without including external dependencies. +

    standard library + Java includes a larger standard library than C or C++, which means that sophisticated programs can be created in Java without including external dependencies. The Java Standard Edition contains thousands of built-in classes that support tasks like file input/output, networking, data structures, and graphical interfaces. - We could not begin to scratch the surface of these classes even if we devoted all of class time! However, we will cover many useful and powerful features of the Java standard library this semester. + We could not begin to scratch the surface of these classes even if we devoted many more chapters! However, we will cover many useful and powerful features of the Java standard library.

  • -

    - Java incorporates automatic garbage collection of memory, whereas C and C++ programs typically include some degree of manual memory management. +

    garbage collection + Java incorporates automatic garbage collection of memory, which is an automatic memory management process that identifies and removes unused objects from memory, helping to free up space and improve program efficiency. + C and C++ programs typically include some degree of manual memory management. This makes programming in those languages more challenging.

  • @@ -399,9 +398,9 @@
-
+
Summary & Reading Questions -

    +

    1. Learning multiple programming languages helps programmers adapt to different styles and environments.

    2. diff --git a/source/ch2_firstjavaprogram.ptx b/source/ch2_firstjavaprogram.ptx index a485e61..7f1669d 100644 --- a/source/ch2_firstjavaprogram.ptx +++ b/source/ch2_firstjavaprogram.ptx @@ -1,27 +1,50 @@ - - Lets look at a Java Program + + Java Programs + + +
      Lets look at a Java Program

      - A time-honored tradition in Computer Science is to write a program called “hello world.” The “hello world” program is simple and easy. + A time-honored tradition in Computer Science is to write a program called “Hello World.” The “Hello World” program is simple and easy. There are no logic errors to make, so getting it to run relies only on understanding the syntax. - To be clear, lets look at a “complicated” version of hello world for Python: + To be clear, lets look at a “complicated” version of hello world for Python in .

      -
      def main(): print("Hello World!")
      + + + + def main(): + print("Hello World!") + + + +

      - Remember that we can define this program right at the Python command line and then run it: + Remember that we can define this program right at the Python command line and then run it with main() Try it in .

      -
      >>> main() "Hello World!" >>>
      +

      + The command line interface of the program is shown in . +

      + + + + +>>> main() +Hello World! + + +

      - Now lets look at the same program written in Java: + Now let's look at the same program written in Java:

      + public class Hello { @@ -31,18 +54,20 @@ public class Hello { } +

      - What we see is that at the core there are a few similarities, such as a main and the string “Hello World”. However, there is a lot more stuff around the edges that make it harder to see the core of the program. Do not worry! An important skill for a computer scientist is to learn what to ignore and what to look at carefully. You will soon find that there are some elements of Java that will fade into the background as you become used to seeing them. + Based on , what we see in the code is that at the core there are a few similarities, such as a main and the string “Hello World”. However, there is a lot more stuff around the edges that make it harder to see the core of the program. Do not worry! An important skill for a computer scientist is to learn what to ignore and what to look at carefully. You will soon find that there are some elements of Java that will fade into the background as you become used to seeing them.

      interpreter compile - The first question you probably have about this little program is “How do I run it?” Running a Java program is not as simple as running a Python program. The first thing you need to do with a Java program is compile it. The first big difference between Java and Python is that Python is an interpreted language. We could run our Python programs in the Python interpreter and we were quite happy to do that. Java makes running programs a two step process. First we must type the hello world program into a file and save that file using the name Hello.java The file name must be the same as the public class you define in the file. Once we have saved the file we compile it from the command line as follows: + The first question you probably have about this little program is “How do I run it?” Running a Java program is not as simple as running a Python program. The first thing you need to do with a Java program is compile it. The first big difference between Java and Python is that Python is an interpreted language. We could run our Python programs in the Python interpreter and we were quite happy to do that. Java makes running programs a two step process. First we must type the hello world program into a file and save that file using the name Hello.java The file name must be the same as the public class you define in the file. Once we have saved the file we compile it from the command line as .

      + $ javac Hello.java @@ -51,6 +76,7 @@ $ ls -l Hello.* -rw-r--r-- 1 bmiller bmiller 117 Jul 19 17:46 Hello.java +

      The command javac compiles our java source code into compiled byte code and saves it in a file called Hello.class. @@ -59,10 +85,11 @@ $ ls -l Hello.*

      - Now that we have compiled our java source code we can run the compiled code using the java command. + Now that we have compiled our java source code we can run the compiled code using the java command as per .

      + $ java Hello @@ -70,6 +97,8 @@ Hello World! $ + +

      Now you may be wondering what good is that extra step? What does compiling do for us? There are a couple of important benefits we get from compiling: @@ -95,8 +124,8 @@ $ JVM byte code The job of the compiler is to turn your java code into language that the Java Virtual Machine (JVM) can understand. - We call the code that the JVM understands byte code. - The JVM interprets the byte code much like the Python interpreter interprets your Python. + JVM is a bytecode interpreter that allows Java programs to run on any platform without having to modify them. + The JVM interprets the byte code much like the Python interpreter does with Python. However since byte code is much closer to the native language of the computer it can run faster.

      @@ -139,8 +168,8 @@ $ On line 1 we see that we are declaring a class called Hello:

      - - + + public class Hello { @@ -162,7 +191,7 @@ public class Hello {

      - + public static void main(String[] args) @@ -252,7 +281,7 @@ public static void main(String[] args)

      - + System.out.println("Hello World!"); @@ -276,11 +305,11 @@ System.out.println("Hello World!"); Java statements can spread across many lines, but the compiler knows it has reached the end of a statement when it encounters a ;. In Python, it is not required (or recommend) to use semicolons in this way, but whitespace is meaningful. In contrast, in Java semicolons are required to end statements, but whitespace is not considered meaningful. - This is a very important difference to remember! In Java, the following statements are all legal and equivalent. + This is a very important difference to remember! In Java, the statements in are all legal and equivalent. I would not encourage you to write your code like this, but you should know that it is legal.

      - + System.out.println("Hello World"); @@ -296,6 +325,7 @@ System. ; +

      The last two lines of the hello world program simply close the two blocks using }. @@ -304,11 +334,11 @@ System.

      - If we wanted to translate the Java back to Python we would have something like the following class definition. + If we wanted to translate the Java back to Python we would have something like class definition.

      - - + + class Hello(object): @staticmethod @@ -316,21 +346,32 @@ class Hello(object): print("Hello World!") +

      Notice that we used the decorator @staticmethod to tell the Python interpreter that main is going to be a static method. - The impact of this is that we don’t have to, indeed we should not, use self as the first parameter of the main method! Using this definition we can call the main method in a Python session like this: + The impact of this is that we don’t have to, indeed we should not, use self as the first parameter of the main method! Using this definition we can call the main method in a Python session with Hello.main(""). Try it in .

      +

      + The command line interface of the program is shown in . +

      - + + >>> Hello.main("") Hello World! ->>> + + + + +
      + +
      Summary & Reading Questions

        @@ -438,6 +479,135 @@ Hello World! + + + +

        + Construct a complete Java program that prints your name and your favorite color to the console. + Drag the blocks into the correct order on the right. +

        +
        + + + + public class NameColor { + + + class NameColor { + + + + + + public static void main(String[] args) { + + + public static main(String[] args) { + + + + + + System.out.println("Name: Alex"); + System.out.println("Favorite Color: Blue"); + + + system.out.println(Name: Alex); + System.out.println("Favorite Color: Blue") + + + + + } + } + + +
        +
      + +
      + Naming Conventions +

      + It is worth pointing out that Java has some very handy naming conventions. It is advisable to both use meaningful names and to follow these naming conventions while developing software in Java for good maintenance and readability of code. +

      + +

      +

        +
      • +

        + Class names should be nouns that are written in UpperCamelCase, namely with the first letter of each word capitalized including the first. + For example, ArrayList, Scanner, StringBuilder, System, etc. +

        +
      • + +
      • +

        + Method names use lowerCamelCase which start with a verb that describes the action they perform. This means that method names start with a lower case letter, and use upper case for each internal-word method names. For example, isInt(), nextLine(), getDenominator(), setNumerator(), etc. +

        +
      • + +
      • +

        + Instance variables of a class start with a lower case letter and use lowerCamelCase like method names. For example, count, totalAmount, etc. +

        +
      • + +
      • +

        + Constants are in all upper case letters or in upper snake case, which also known as screaming snake case, and which is a naming convention in which each word is written in uppercase letters, separated by underscores. + For example, Math.MAXINT or MAX_INT. +

        +
      • +
      +

      + + + +

      + Which of the following is a valid variable name according to the core syntax rules of Java, but causes a syntax error in Python? +

      +
      + + + _variableName + +

      + Incorrect. Leading underscores are valid in both Java and Python (commonly used in Python for private/protected attributes). +

      +
      +
      + + + variable_name + +

      + Incorrect. Snake_case names with underscores are valid in both languages (and are actually standard convention in Python). +

      +
      +
      + + + $variableName + +

      + Correct! Java allows the dollar sign ($) in variable names, but Python generates a SyntaxError because $ is not a permitted identifier character in Python. +

      +
      +
      + + + variableName2 + +

      + Incorrect. Numbers at the end of variable names are valid syntax in both Java and Python. +

      +
      +
      +
      +
      + +
      +
      \ No newline at end of file diff --git a/source/ch3_javadatatypes.ptx b/source/ch3_javadatatypes.ptx index ab3a790..6c69c36 100644 --- a/source/ch3_javadatatypes.ptx +++ b/source/ch3_javadatatypes.ptx @@ -14,10 +14,11 @@ In Java, some of the most basic data types like integers and floating point numbers are not objects. The benefit of having these primitive data types be non-objects is that operations on the primitives are fast. The problem is that it became difficult for programmers to combine objects and non-objects in the way that we do in Python. - So, eventually all the non-object primitives ended up with Objectified versions. + So, eventually all the non-object primitives ended up with Objectified versions. shows the comparison between Java's primitive and object data types.

      -
+
+ Comparison between Java's primitive and object data types. Primitive @@ -86,47 +87,54 @@ - A data type fundamentally defines a set of values and the operations you can perform on them. For instance, you can do math with int and double values, but not with boolean values. This is simlar to Python, where you can perform arithmetic on integers and floats, but not on booleans or strings. + A data type fundamentally defines a set of values and the operations you can perform on them. For instance, you can do math with int and double values, but not with boolean values. This is similar to Python, where you can perform arithmetic on integers and floats, but not on booleans or strings.

- Let’s look at a simple Python function which converts a Fahrenheit temperature to Celsius. + is a simple Python function which converts a Fahrenheit temperature to Celsius. If this program were run on the command-line, you would enter the temperature when prompted – the Javascript pop-up for input is only an artifact of the digital textbook.

- + def main(): - fahr = int(input("Enter the temperature in F: ")) - cel = (fahr - 32) * 5.0/9.0 + """ Program to convert a temperature from Fahrenheit to Celsius. """ + fahr = int(input("Enter the temperature in F: ")) # get the temperature in Fahrenheit + cel = (fahr - 32) * 5.0/9.0 # convert to Celsius print("the temperature in C is: ", cel) main() +

- Next, lets look at the Java equivalent. If this program were run on the command-line, you would enter the temperature when prompted – the “Input for Program” text box is only an artifact of the digital textbook. + Next, is the Java equivalent. If this program were run on the command-line, you would enter the temperature when prompted – the “Input for Program” text box is only an artifact of the digital textbook.

+ -import java.util.Scanner; +import java.util.Scanner; // import the Scanner class to read input from the user + /** + * Program to convert a temperature from Fahrenheit to Celsius in Java. + */ public class TempConv { public static void main(String[] args) { - Double fahr; + Double fahr; Double cel; - Scanner in; - in = new Scanner(System.in); + Scanner in; // declare a Scanner variable called in + in = new Scanner(System.in); // create a Scanner object to read input from the user System.out.println("Enter the temperature in F: "); - fahr = in.nextDouble(); - cel = (fahr - 32) * 5.0/9.0; + fahr = in.nextDouble(); // read the temperature in Fahrenheit from the user + cel = (fahr - 32) * 5.0/9.0; // convert to Celsius System.out.println("The temperature in C is: " + cel); } } +

There are several new concepts introduced in this example. We will look at them in the following order: @@ -222,6 +230,7 @@ public class TempConv {

So, what exactly does the import statement do? What it does is tell the compiler that we are going to use a shortened version of the class’s name. In this example we are going to use the class java.util.Scanner but we can refer to it as just Scanner. We could use the java.util.Scanner class without any problem and without any import statement, provided that we always referred to it by its full name. As an experiment, you may want to try this yourself. Remove the import statement and change the string Scanner to java.util.Scanner in the rest of the code. The program should still compile and run.

+ @@ -246,7 +255,9 @@ public class TempConv { For Python programmers, the following error is likely to be even more common. Suppose we forgot the declaration for cel and instead left line 6 blank. What would happen when we type javac TempConv.java on the command line?

-
+            +            
+            
             TempConv.java:13: cannot find symbol 
             symbol  : variable cel 
             location: class TempConv 
@@ -258,15 +269,88 @@ public class TempConv {
             System.out.println("The temperature in C is: " + cel); 
             ^ 
             2 errors
-            
+ + +

- When you see the first kind of error, where the symbol is on the left side of the equals sign, it usually means that you have not declared the variable. If you have ever tried to use a Python variable that you have not initialized the second error message will be familiar to you. The difference here is that we see the message before we ever try to test our program. More common error messages are discussed in the section . + When you see the first kind of error in , where the symbol is on the left side of the equals sign, it usually means that you have not declared the variable. If you have ever tried to use a Python variable that you have not initialized the second error message will be familiar to you. The difference here is that we see the message before we ever try to test our program. More common error messages are discussed in the section .

- The general rule in Java is that you must decide what kind of an object your variable is going to reference and then you must declare that variable before you use it. In our temperature converter, the calculation (fahr - 32) * 5.0/9.0 works correctly because 5.0 and 9.0 are treated as double values, preventing the integer division that would occur if we had written 5/9, which would result in 0. + The general rule in Java is that you must decide what kind of an object your variable is going to reference and then you must declare that variable before you use it. In our temperature converter, the calculation (fahr - 32) * 5.0/9.0 works correctly because 5.0 and 9.0 are treated as double values, preventing the integer division that would occur if we had written 5/9, which would result in 0.

+ + + +

+ Construct a complete Java program that reads a distance in kilometers from the user and converts it to miles. + Drag the blocks into the correct order on the right. +

+
+ + + + + import java.util.Scanner; + + + import Scanner; + + + + + public class KmToMiles { + + + + public static void main(String[] args) { + + + + Scanner input; + Double kilometers; + Double miles; + + + + + input = new Scanner(System.in); + + + input = new Scanner(System.out); + + + + + + kilometers = input.nextDouble(); + + + kilometers = input.readDouble(); + + + + + + miles = kilometers * 0.621; + + + miles = kilometers / 0.621; + + + + + System.out.println(kilometers + " kilometers is equal to " + miles + " miles."); + + + } + } + + +
+ + @@ -282,74 +366,215 @@ public class TempConv {

- Implicit typecasting happens automatically when converting a value from a smaller data type to a larger one, as there is no risk of losing information. For example, you can assign an int to a double without any special syntax. + Implicit typecasting happens automatically when converting a value from a smaller data type to a larger one, as there is no risk of losing information. For example, you can assign an int to a double without any special syntax as shown in .

-
 
-        int myInt = 10;
-        double myDouble = myInt; // Automatic casting from int to double
-        
- + + + + +void main() { + int myInt = 10; + double myDouble = myInt; // Automatic casting from int to double + + System.out.println(myDouble); +} + + + +

- Explicit typecasting is required when converting from a larger data type to a smaller one, as you might lose data. You must do this manually by placing the target type in parentheses () before the value. + Explicit typecasting is required when converting from a larger data type to a smaller one, as you might lose data. You must do this manually by placing the target type in parentheses () before the value as shown in .

-
-        double originalDouble = 9.78;
-        int castedInt = (int) originalDouble; // Explicitly casts double to int. The value of castedInt is now 9.
-        
+ + + +void main() { + double originalDouble = 9.78; + int castedInt = (int) originalDouble; // Explicitly casts double to int. The value of castedInt is now 9. + + System.out.println(castedInt); +} + + +

Besides primitive types, type casting is also a fundamental concept when working with objects, especially within an inheritance hierarchy. This involves converting an object reference from one class type to another, typically between a superclass and a subclass. This is often referred to as upcasting and downcasting.

- Let's imagine we have a simple class hierarchy: an Animal superclass and a Dog subclass. + In , we have a simple class hierarchy: an Animal superclass and a Dog subclass.

-
+
+    +    
+        
+/**
+    * Animal class is the superclass, with a method makeSound().
+    */        
 class Animal {
     public void makeSound() {
         System.out.println("The animal makes a sound.");
     }
 }
 
+/**
+    * Dog class is a subclass of Animal, with an additional method bark().
+    */
 class Dog extends Animal {
     public void bark() {
         System.out.println("The dog barks!");
     }
 }
-    
+ + +

- Upcasting (Implicit): Upcasting is casting a subclass instance to a superclass reference type. This is always safe because a subclass object is guaranteed to have all the methods and properties of its superclass. Therefore, upcasting is done implicitly by the compiler. + Upcasting (Implicit): Upcasting is casting a subclass instance to a superclass reference type. This is always safe because a subclass object is guaranteed to have all the methods and properties of its superclass. Therefore, upcasting is done implicitly by the compiler as .

-
+    +    
+        
+
+/**
+    * Animal class is the superclass, with a method makeSound().
+    */
+class Animal {
+    public void makeSound() {
+        System.out.println("The animal makes a sound.");
+    }
+}
+
+/**
+    * Dog class is a subclass of Animal, with an additional method bark().
+    */
+class Dog extends Animal {
+    public void bark() {
+        System.out.println("The dog barks!");
+    }
+}
+
+/**
+    * Upcasting example: A Dog object is created, but the reference is of type Animal.   
+    */ 
+void main() {
 // A Dog object is created, but the reference is of type Animal.
 // This is implicit upcasting.
-Animal myAnimal = new Dog(); 
+    Animal myAnimal = new Dog(); 
 
-myAnimal.makeSound(); // This is valid, as makeSound() is defined in Animal.
+    myAnimal.makeSound(); // This is valid, as makeSound() is defined in Animal.
+
+    // myAnimal.bark(); // This would cause a compile-time error!
+    // The compiler only knows about the methods in the Animal reference type.
+}
+    
+    
+    
 
-// myAnimal.bark(); // This would cause a compile-time error!
-// The compiler only knows about the methods in the Animal reference type.
-    

Downcasting (Explicit): Downcasting is casting a superclass reference back to its original subclass type. This is potentially unsafe because the superclass reference might not actually point to an object of the target subclass. You must perform an explicit cast. If you cast to the wrong type, Java will throw a ClassCastException at runtime.

- To safely downcast, you should first check the object's type using the instanceof operator. + To safely downcast, you should first check the object's type using the instanceof operator as shown in .

-
-// 'myAnimal' is an Animal reference, but it points to a Dog object.
-if (myAnimal instanceof Dog) {
-    // The check passed, so this downcast is safe.
-    Dog myDog = (Dog) myAnimal;
-
-    // Now we can access methods specific to the Dog class.
-    myDog.bark(); // This is now valid.
+    +    
+        
+/**
+    * Animal class is the superclass, with a method makeSound().
+    */       
+class Animal {
+    public void makeSound() {
+        System.out.println("The animal makes a sound.");
+    }
 }
-    
+ +/** + * Dog class is a subclass of Animal, with an additional method bark(). + */ +class Dog extends Animal { + public void bark() { + System.out.println("The dog barks!"); + } +} + +/** + * Downcasting example: An Animal reference is downcast to a Dog reference after checking its type. + */ +void main() { + Animal myAnimal = new Dog(); + + // 'myAnimal' is an Animal reference, but it points to a Dog object. + if (myAnimal instanceof Dog myDog) { + // Now we can access methods specific to the Dog class. + myDog.bark(); + } +} + + + +

- In this example, we first create a Dog object and assign it to an Animal reference (upcasting). Then, we check if the Animal reference is actually pointing to a Dog object before downcasting it back to a Dog reference. + In , we first create a Dog object and assign it to an Animal reference (upcasting). Then, we check if the Animal reference is actually pointing to a Dog object before downcasting it back to a Dog reference.

+ + + +

+ Construct a program that safely downcasts a Shape reference to a Circle object and calls a subclass method. + Drag the blocks into the correct order on the right. +

+
+ + + class Shape { + ... + } + + + + class Circle extends Shape { + public void drawCircle() { + System.out.println("Circle"); + } + } + + + + public class Downcast { + public static void main(String[] args) { + Shape myShape = new Circle(); + + + + + if (myShape instanceof Circle) { + + + if (myShape.equals(Circle)) { + + + + + + Circle myCircle = (Circle) myShape; + myCircle.drawCircle(); + + + Circle myCircle = myShape; + myCircle.drawCircle(); + + + + + } + } + } + + +
+ @@ -361,10 +586,11 @@ if (myAnimal instanceof Dog) {

- In fact, this is the first example of another big difference between Java and Python. Java does not support any operator overloading. Table 3 maps common Python string operations to their Java counterparts. For the examples shown in the table we will use a string variable called “str” + In fact, this is the first example of another big difference between Java and Python. Java does not support any operator overloading. maps common Python string operations to their Java counterparts. For the examples shown in the table we will use a string variable called “str”

-
+
+ Comparison of common string operations in Python and Java. Python @@ -427,28 +653,34 @@ if (myAnimal instanceof Dog) { List

- Next, let’s look at a program which reads numbers from a file and produces a histogram showing the frequency of the numbers. The data file we will use has one number between 0 and 9 on each line of the file. Here is a simple Python program that creates and prints a histogram. + Next, let’s look at a program which reads numbers from a file and produces a histogram showing the frequency of the numbers. The data file we will use has one number between 0 and 9 on each line of the file. is a simple Python program that creates and prints a histogram.

- - + + def main(): - count = [0]*10 - data = open('test.dat') + """ Program to read numbers from a file and produce a histogram. """ + count = [0]*10 # create a list of 10 zeros + data = open('test.dat') # open the data file + # read each line and update the count for line in data: count[int(line)] = count[int(line)] + 1 idx = 0 - for num in count: - print(idx, " occured ", num, " times.") + for num in count: # iterate over the list and print the histogram + print(idx, " occurred ", num, " times.") idx += 1 main() +

- Test running the program. It will read this data: + Test running the program. It will read .

+ + + Data file for testing the histogram program
    1
@@ -456,14 +688,16 @@ main()
    3
    9
    1
-        
+ + +

Lets review what is happening in this little program. First, we create a list and initialize the first 10 positions in the list to be 0. Next we open the data file called ‘test.dat’. Third, we have a loop that reads each line of the file. As we read each line we convert it to an integer and increment the counter at the position in the list indicated by the number on the line we just read. Finally we iterate over each element in the list, printing out both the position in the list and the total value stored in that position.

-To write the Java version of this program we will have to introduce several new Java concepts. First, you will see the Java equivalent of a list, called an ArrayList. Next, you will see three different kinds of loops used in Java. Two of the loops we will use are going to be very familiar, the third one is different from what you are used to in Python but is easy when you understand the syntax: +To write the Java version of this program we will have to introduce several new Java concepts. First, you will see the Java equivalent of a list, an ArrayList. Next, you will see three different kinds of loops used in Java. Two of the loops we will use are going to be very familiar, the third one is different from what you are used to in Python but is easy when you understand the syntax:

@@ -519,7 +753,7 @@ The code will be executed once for each element in the collection.

-Here is the Java code needed to write the exact same program: + is the Java code needed to write the exact same program.

@@ -528,126 +762,161 @@ Here is the Java code needed to write the exact same program:

+ -import java.util.Scanner; -import java.util.ArrayList; -import java.io.File; -import java.io.IOException; +import java.util.Scanner; // import the Scanner class to read input from the user +import java.util.ArrayList; // import the ArrayList class to use dynamic arrays +import java.io.File; // import the File class to read from files +import java.io.IOException; // import the IOException class to handle file input/output exceptions +/** + * Program to read numbers from a file and produce a histogram in Java. + */ public class Histo { public static void main(String[] args) { - Scanner data = null; - ArrayList<Integer> count; + Scanner data = null; + ArrayList<Integer> count; // create an ArrayList to hold counts of numbers, of type Integer Integer idx; + + // Try to open the data file and handle any potential IOExceptions try { data = new Scanner(new File("test.dat")); } catch ( IOException e) { System.out.println("Unable to open data file"); - e.printStackTrace(); + e.printStackTrace(); // print the stack trace for debugging System.exit(0); } - count = new ArrayList<Integer>(10); + count = new ArrayList<Integer>(10); // create an ArrayList with an initial capacity of 10 for (Integer i = 0; i < 10; i++) { - count.add(i,0); + count.add(i,0); // initialize the first 10 positions in the ArrayList to hold the value 0 } while(data.hasNextInt()) { - idx = data.nextInt(); + // read each integer from the file and update the count + idx = data.nextInt(); count.set(idx,count.get(idx)+1); } idx = 0; for(Integer i : count) { - System.out.println(idx + " occured " + i + " times."); + // iterate over each element in the ArrayList and print the histogram + System.out.println(idx + " occurred " + i + " times."); idx++; } } } +

- Before going any further, I suggest you try to compile the above program and run it on some test data that you create. + Before going any further, I suggest you try to compile and run it on some test data that you create.

- Now, let’s look at what is happening in the Java source. As usual, we declare the variables we are going to use at the beginning of the method. In this example we are declaring a Scanner variable called data, an integer called idx and an ArrayList called count. However, there is a new twist to the ArrayList declaration. Unlike Python where lists can contain just about anything, in Java we let the compiler know what kind of objects our array list is going to contain. In this case the ArrayList will contain Integers. The syntax we use to declare what kind of object the list will contain is the <Type> syntax. + Now, let’s look at what is happening in the Java source. As usual, we declare the variables we are going to use at the beginning of the method. In , we are declaring a Scanner variable called data, an integer called idx and an ArrayList called count. However, there is a new twist to the ArrayList declaration. Unlike Python where lists can contain just about anything, in Java we let the compiler know what kind of objects our array list is going to contain. In this case the ArrayList will contain Integers. The syntax we use to declare what kind of object the list will contain is the <Type> syntax.

- Technically, you don’t have to declare what is going to be in an array list. The compiler will allow you to leave the <``*Type*>`` off the declaration. If you don’t tell Java what kind of object is going to be on the list Java will give you a warning message like this: + Technically, you don’t have to declare what is going to be in an array list. The compiler will allow you to leave the <*Type*> off the declaration. If you don’t tell Java what kind of object is going to be on the list Java will give you a warning message like when you compile the program.

-
+        +        
+        
         Note: Histo.java uses unchecked or unsafe operations. 
         Note: Recompile with -Xlint:unchecked for details.
-        
+ +
+

Without the <Integer> part of the declaration Java simply assumes that any object can be on the list. However, without resorting to an ugly notation called casting, you cannot do anything with the objects on a list like this! So, if you forget you will surely see more errors later in your code. (Try it and see what you get)

- Lines 13—20 are required to open the file. Why so many lines to open a file in Java? The additional code mainly comes from the fact that Java forces you to reckon with the possibility that the file you want to open is not going to be there. If you attempt to open a file that is not there you will get an error. A try/catch construct allows us to try things that are risky, and gracefully recover from an error if one occurs. The following example shows the general structure of a try/catch block. + Lines 13—20 in are required to open the file. Why so many lines to open a file in Java? The additional code mainly comes from the fact that Java forces you to reckon with the possibility that the file you want to open is not going to be there. If you attempt to open a file that is not there you will get an error. A try/catch construct allows us to try things that are risky, and gracefully recover from an error if one occurs. shows the general structure of a try/catch block.

- -
+        
+        +        
+        
         try { 
             Put some risky code in here, like opening a file 
         } catch (Exception e) { 
             If an error happens in the try block an exception is thrown. We will catch that exception here! 
         }
-        
+ + +

- Notice that in line 16 we are catching an IOException. In fact, we will see later that we can have multiple catch blocks to catch different types of exceptions. If we want to be lazy and catch any old exception we can catch an Exception which is the parent of all exceptions. However, catching Exception is a terrible practice, since you may inadvertently catch exceptions you do not intend to, making it harder to identify bugs in your program. + Notice that in line 16 in , we are catching an IOException. In fact, we will see later that we can have multiple catch blocks to catch different types of exceptions. If we want to be lazy and catch any old exception we can catch an Exception which is the parent of all exceptions. However, catching Exception is a terrible practice, since you may inadvertently catch exceptions you do not intend to, making it harder to identify bugs in your program.

- On line 22 we create our ArrayList and give it an initial size of 10. Strictly speaking, it is not necessary to give the ArrayList any size. It will grow or shrink dynamically as needed, just like a list in Python. On line 23 we start the first of three loops. The for loop on lines 23–25 serves the same purpose as the Python statement count = [0]*10, that is it initializes the first 10 positions in the ArrayList to hold the value 0. + On line 22 in , we create our ArrayList and give it an initial size of 10. Strictly speaking, it is not necessary to give the ArrayList any size. It will grow or shrink dynamically as needed, just like a list in Python. On line 23 we start the first of three loops. The for loop on lines 23–25 serves the same purpose as the Python statement count = [0]*10, that is it initializes the first 10 positions in the ArrayList to hold the value 0.

- The syntax of this for loop probably looks very strange to you, but in fact it is not too different from what happens in Python using range. In fact for (Integer i = 0; i < 10; i++) is exactly equivalent to the Python for i in range(10) The first statement inside the parenthesis declares and initializes a loop variable i. The second statement is a Boolean expression that is our exit condition. In other words we will keep looping as long as this expression evaluates to true. The third clause is used to increment the value of the loop variable at the end of iteration through the loop. In fact i++ is Java shorthand for i = i + 1 Java also supports the shorthand i-- to decrement the value of i. Like Python, you can also write i += 2 as shorthand for i = i + 2 Try to rewrite the following Python for loops as Java for loops: -

- -

-

    -
  • -

    - for i in range(2,101,2) -

    -
  • + The syntax of this for loop probably looks very strange to you, but in fact it is not too different from what happens in Python using range. In fact for (Integer i = 0; i < 10; i++) is exactly equivalent to the Python for i in range(10) The first statement inside the parenthesis declares and initializes a loop variable i. The second statement is a Boolean expression that is our exit condition. In other words we will keep looping as long as this expression evaluates to true. The third clause is used to increment the value of the loop variable at the end of iteration through the loop. In fact i++ is Java shorthand for i = i + 1 Java also supports the shorthand i-- to decrement the value of i. Like Python, you can also write i += 2 as shorthand for i = i + 2.

    -
  • -

    - for i in range(1,100) -

    -
  • - -
  • -

    - for i in range(100,0,-1) -

    -
  • - -
  • -

    - for x,y in zip(range(10),range(0,20,2)) [hint, you can separate statements in the same clause with a ,] -

    -
  • -
-

+ + +

+ Match each Python for loop with its equivalent Java for loop. +

+
+ + + + + for i in range(2, 102, 2) + for (int i = 2; i < 102; i += 2) + + + + for i in range(1, 100) + for (int i = 1; i < 100; i++) + + + + for (int i = 1; i <= 100; i++) + + + + for i in range(100, 0, -1) + for (int i = 100; i > 0; i--) + + + + for (int i = 2; i <= 102; i += 2) + + + + for x, y in zip(range(10), range(0, 20, 2)) + for (int x = 0, y = 0; x < 10; x++, y += 2) + + + + for (int i = 100; i < 0; i--) + + + + for (int x = 0, int y = 0; x < 10; x++, y += 2) + + +

- The next loop (lines 27–30) shows a typical Java pattern for reading data from a file. Java while loops and Python while loops are identical in their logic. In this case, we will continue to process the body of the loop as long as data.hasNextInt() returns true. + The next loop (lines 27–30) in shows a typical Java pattern for reading data from a file. Java while loops and Python while loops are identical in their logic. In this case, we will continue to process the body of the loop as long as data.hasNextInt() returns true.

- Line 29 illustrates another important difference between Python and Java. Notice that in Java we can not write count[idx] = count[idx] + 1. This is because in Java there is no overloading of operators. Everything except the most basic math and logical operations is done using methods. So, to set the value of an ArrayList element we use the set method. The first parameter of set indicates the index or position in the ArrayList we are going to change. The next parameter is the value we want to set. Notice that, once again, we cannot use the indexing square bracket operator to retrieve a value from the list, but we must use the get method. + Line 29 in illustrates another important difference between Python and Java. Notice that in Java we can not write count[idx] = count[idx] + 1. This is because in Java there is no overloading of operators. Everything except the most basic math and logical operations is done using methods. So, to set the value of an ArrayList element we use the set method. The first parameter of set indicates the index or position in the ArrayList we are going to change. The next parameter is the value we want to set. Notice that, once again, we cannot use the indexing square bracket operator to retrieve a value from the list, but we must use the get method.

- The last loop in this example is similar to the Python for loop where the object of the loop is a Sequence. In Java we can use this kind of for loop over all kinds of sequences, which are called Collection classes in Java. The for loop on line 33 for(Integer i : count) is equivalent to the Python loop for i in count: This loop iterates over all of the elements in the ArrayList called count. Each time through the loop the Integer variable i is bound to the next element of the ArrayList. If you tried the experiment of removing the <Integer> part of the ArrayList declaration you probably noticed that you had an error on this line. Why? + The last loop in is similar to the Python for loop where the object of the loop is a Sequence. In Java we can use this kind of for loop over all kinds of sequences, which are called Collection classes in Java. The for loop on line 33 in for(Integer i : count) is equivalent to the Python loop for i in count: This loop iterates over all of the elements in the ArrayList called count. Each time through the loop the Integer variable i is bound to the next element of the ArrayList. If you tried the experiment of removing the <Integer> part of the ArrayList declaration you probably noticed that you had an error on this line. Why?

@@ -655,19 +924,22 @@ public class Histo { Arrays

- As I said at the outset of this section, we are going to use Java ArrayLists because they are easier to use and more closely match the way that Python lists behave. However, if you look at Java code on the internet or even in your Core Java books you are going to see examples of something called arrays. In fact you have already seen one example of an array declared in the ‘Hello World’ program. Lets rewrite this program to use primitive arrays rather than array lists. + As was said at the outset of this section, we are going to use Java ArrayLists because they are easier to use and more closely match the way that Python lists behave. However, if you look at Java code on the internet or even in your core Java books you are going to see examples of something called an array. In fact, you have already seen one example of an array declared in the ‘Hello World’ program. is a rewritten version of that uses primitive arrays rather than array lists.

- + -import java.util.Scanner; -import java.io.File; -import java.io.IOException; +import java.util.Scanner; // import the Scanner class to read input from the user +import java.io.File; // import the File class to read from files +import java.io.IOException; // import the IOException class to handle file input/output exceptions +/** + * Program to read numbers from a file and produce a histogram using arrays in Java. + */ public class HistoArray { public static void main(String[] args) { Scanner data = null; - Integer[] count = {0,0,0,0,0,0,0,0,0,0}; + Integer[] count = {0,0,0,0,0,0,0,0,0,0}; // create an array of 10 integers initialized to 0 Integer idx; try { data = new Scanner(new File("test.dat")); @@ -679,21 +951,64 @@ public class HistoArray { } while(data.hasNextInt()) { idx = data.nextInt(); - count[idx] = count[idx] + 1; + count[idx] = count[idx] + 1; // increment the count for the number read from the file, using array indexing } idx = 0; for(Integer i : count) { - System.out.println(idx + " occured " + i + " times."); + System.out.println(idx + " occurred " + i + " times."); idx++; } } } +

- The main difference between this example and the previous example is that we declare count to be an Array of integers. We also can initialize short arrays directly using the syntax shown on line 8. Then notice that on line 22 we can use the square bracket notation to index into an array. + The main difference between and is that we declare count to be an Array of integers. We also can initialize short arrays directly using the syntax shown here: Integer[] count = {0,0,0,0,0,0,0,0,0,0}Then notice that we can use the square bracket notation count[idx] to index into an array. +

+ + + +

+ Construct a short Java program that creates an array of three integers, + changes the first value, and prints it. Drag the blocks into the correct order on the right.

+
+ + + public class ArrayExample { + public static void main(String[] args) { + + + + + Integer[] nums = {1, 2, 3}; + + + Integer[] nums = (1, 2, 3); + + + + + + nums[0] = 5; + + + nums(0) = 5; + + + + + System.out.println(nums[0]); + + + + } + } + + +
@@ -704,62 +1019,80 @@ public class HistoArray {

- Lets stay with a simple frequency counting example, only this time we will count the frequency of words in a document. A simple Python program for this job could look like this: + Lets stay with a simple frequency counting example, only this time we will count the frequency of words in a document. shows a simple Python program for how this could look.

- + -def main(): +def main(): + """ Program to read a file and count the frequency of words in the file. """ data = open('alice30.txt') - wordList = data.read().split() + wordList = data.read().split() # split the file into a list of words count = {} - for w in wordList: + for w in wordList: # iterate over the list of words w = w.lower() count[w] = count.get(w,0) + 1 - keyList = sorted(count.keys()) - for k in keyList: + keyList = sorted(count.keys()) # sort the keys in alphabetical order + for k in keyList: # iterate over the sorted list of keys print("%-20s occurred %4d times" % (k, count[k])) main() +

- This program reads the file alice30.txt (which follows), and it then splits it into a list of words. Next it creates a dictionary called count which maps each word to the number of times that word occurs in the text. Finally, it prints out the words in alphabetical order along with their frequency. + This program reads the file alice30.txt in , and it then splits it into a list of words. Next it creates a dictionary called count which maps each word to the number of times that word occurs in the text. Finally, it prints out the words in alphabetical order along with their frequency.

-
 
-            Down, down, down.  Would the fall NEVER come to an end! 
-             'I wonder how many miles I've fallen by this time?' she said aloud. 'I must 
-             be getting somewhere near the centre of the earth.  
-             Let me see:  that would be four thousand miles down, I think--' 
-             (for, you see, Alice had learnt several things of this sort in her lessons 
-             in the schoolroom, and though this was not a VERY good opportunity for 
-             showing off her knowledge, as there was no one to listen to her, still it 
-             was good practice to say it over) '--yes, that's about the right distance
-             --but then I wonder what Latitude or Longitude I've got to?'  
-             (Alice had no idea what Latitude was, or Longitude either, 
-             but thought they were nice grand words to say.) 
+ + Data file for testing the word frequency program + +
 
+            Down, down, down. Would the fall NEVER
+            come to an end! 'I wonder how many
+            miles I've fallen by this time?' she
+            said aloud. 'I must be getting somewhere
+            near the centre of the earth. Let me see:
+            that would be four thousand miles down,
+            I think--' (for, you see, Alice had
+            learnt several things of this sort in
+            her lessons in the schoolroom, and though
+            this was not a VERY good opportunity for
+            showing off her knowledge, as there was no
+            one to listen to her, still it was good
+            practice to say it over) '--yes, that's
+            about the right distance--but then I
+            wonder what Latitude or Longitude I've got
+            to?' (Alice had no idea what Latitude was,
+            or Longitude either, but thought they were
+            nice grand words to say.)
+            
+
+

- Notice that the structure of the program is very similar to the numeric histogram program. + Notice that the structure of is very similar to the numeric histogram program.

- + -import java.util.Scanner; -import java.util.ArrayList; -import java.io.File; -import java.io.IOException; -import java.util.TreeMap; +import java.util.Scanner; +import java.util.ArrayList; // import the ArrayList class to use dynamic arrays +import java.io.File; +import java.io.IOException; +import java.util.TreeMap; // import the TreeMap class to use a map for counting word frequencies +/** + * Program to read a file and count the frequency of words in the file. + */ public class HistoMap { public static void main(String[] args) { Scanner data = null; - TreeMap<String,Integer> count; + TreeMap<String,Integer> count; // create a TreeMap to hold word counts, mapping each word (String) to its frequency (Integer) Integer idx; String word; Integer wordCount; - try { + try { // Try to open the data file and handle any potential IOExceptions data = new Scanner(new File("alice30.txt")); } catch ( IOException e) { @@ -767,28 +1100,77 @@ public class HistoMap { e.printStackTrace(); System.exit(0); } - count = new TreeMap<String,Integer>(); + count = new TreeMap<String,Integer>(); // create a TreeMap to hold word counts while(data.hasNext()) { - word = data.next().toLowerCase(); - wordCount = count.get(word); + word = data.next().toLowerCase(); // read each word from the file, convert it to lowercase + wordCount = count.get(word); // get the current count for the word from the TreeMap if (wordCount == null) { wordCount = 0; } - count.put(word,++wordCount); + count.put(word,++wordCount); // increment the count for the word and put it back into the TreeMap } - for(String i : count.keySet()) { - System.out.printf("%-20s occured %5d times\n", i, count.get(i) ); + for(String i : count.keySet()) { // iterate over the keys (words) in the TreeMap + System.out.printf("%-20s occurred %5d times\n", i, count.get(i) ); } } } + + +

+ Improve to remove the punctuation. +

+ +

- Improve the program above to remove the punctuation. + Rearrange the blocks to create a general Java method that accepts a dictionary (Map) of item prices and updates the price of a specific item. If the item does not exist, do nothing.

+
+ + + + public void updatePrice(Map<String, Double> catalog, String item, double newPrice) { + + + public void updatePrice() { + Map<String, Double> catalog, + String item, + double newPrice + + + + + + if (catalog.containsKey(item)) { + + + if (catalog.get(item) == null) { + + + + + + catalog.put(item, newPrice); + + + catalog.add(item, newPrice); + + + + + } + } + + +
+
-
+ + + +
Summary & Reading Questions

  1. @@ -813,7 +1195,7 @@ public class HistoMap {

    Maps (HashMap and TreeMap) are Java's equivalent to Python dictionaries for storing key-value pairs.

- +

What is the correct way to declare an ArrayList that will hold String objects in Java?

@@ -931,6 +1313,7 @@ public class HistoMap {
+
\ No newline at end of file diff --git a/source/ch4_conditionals.ptx b/source/ch4_conditionals.ptx index 6a38a39..623587a 100644 --- a/source/ch4_conditionals.ptx +++ b/source/ch4_conditionals.ptx @@ -4,92 +4,108 @@ Conditionals -
- Using the Simple <c>if</c> Statement +
Using Conditional Statements in Java +

conditional statements Conditional statements in Python and Java are very similar. - In Python we have three patterns: + In Python we have three patterns.

- +
+ + Using the <c>if</c> Statement

- In Python the simple if statement is written as: + shows how the simple if statement is written in Python.

+ score = 95 -if score >= 90: +if score >= 90: # Note the colon at the end of the line print("Excellent work!") + + +

In Java, this same pattern requires two changes: the condition must be in parentheses (), and the code block must be enclosed in curly braces {}. + shows how the simple if statement is written in Java.

+ public class SimpleIfExample { public static void main(String[] args) { - int score = 70; - if (score <= 70) { - System.out.println("Needs work!"); + int score = 95; + if (score >= 90) { // Note the parentheses and curly braces + System.out.println("Excellent work!"); } } } + +

Once again you can see that in Java the curly braces define a block rather than indentation. - In Java the parenthesis around the condition are required because it is technically a function that evaluates to True or False. + In Java, the parentheses around the condition are required because it is technically a function that evaluates to True or False.

-
- -
+ + + + Using the <c>if</c> - <c>else</c> Statement -

The Java equivalent follows the same syntactical rules as before.

+

shows how the if - elsestatement is written in Python.

+ age = 16 - if age >= 18: + if age >= 18: # notice the semicolon print("You can vote.") - else: + else: # notice the semicolon print("You are not yet eligible to vote.") - - + + +

is Java equivalent that follows the same syntactical rules as before.

+ + public class IfElseExample { public static void main(String[] args) { int age = 16; - if (age >= 18) { + if (age >= 18) { System.out.println("You can vote."); - } else { + } else { // else has its own block. System.out.println("You are not yet eligible to vote."); } } } -
+ + -
+ Can we use <c>elif</c>?

elif statement Java does not have an elif pattern like Python. In Java you can get the functionality of an elif statement by nesting if and else. - Here is a simple example in both Python and Java. + Here is a simple example in both Python and Java. shows how it is written in Python.

- + grade = int(input('enter a grade')) -if grade < 60: +if grade < 60: print('F') -elif grade < 70: +elif grade < 70: # notice the semicolon print('D') elif grade < 80: print('C') @@ -99,12 +115,13 @@ else: print('A') +

-In Java we have a couple of ways to write this. +In Java, we have a couple of ways to write this. shows one way.

- + public class ElseIf { @@ -112,7 +129,7 @@ public class ElseIf { int grade = 85; if (grade < 60) { System.out.println('F'); - } else { + } else { // else has its own block. if (grade < 70) { System.out.println('D'); } else { @@ -131,21 +148,22 @@ public class ElseIf { } +

-We can get even closer to the elif statement by taking advantage of the Java rule that a single statement does not need to be enclosed in curly braces. Since the if is the only statement used in each else we can get away with the following. +We can get even closer to the elif statement by taking advantage of the Java rule that a single statement does not need to be enclosed in curly braces. Since the if is the only statement used in each else block, we can get away with .

- + -public class ElseIf { +public class ElseIf { public static void main(String args[]) { - int grade = 85; + int grade = 85; if (grade < 60) { System.out.println('F'); - } else if (grade < 70) { + } else if (grade < 70) { // notice how we got rid of the curly braces. System.out.println('D'); } else if (grade < 80) { System.out.println('C'); @@ -156,24 +174,28 @@ public class ElseIf { } -
+ + -
+ Using the <c>switch</c> Statement

-Java also supports a switch statement that acts something like the elif statement of Python under certain conditions. To write the grade program using a switch statement we would use the following: -

+Java also supports a switch statement that acts something like the elif or Python match statement under certain conditions. shows how a grade program using a switch statement would look in Python. +

- Depending on your knowledge and experience with Python you may already be familiar and questioning why we are not using the match statement in our Python examples. The answer is that this book currently runs its active code examples on Python 3.7, which does not support the match statement. The match statement was introduced in Python 3.10. Below is an example of the match statement similar to our grade method. -

- + The match - case statement was introduced in Python 3.10, so doesn't run in earlier version of Python. Here is an example using Python's match - case structure. +

+ + Match Case Example - grade = 100 // 10 - def grading(grade): + grade = 85 + # Convert grade to a scale of 0-10 using integer division + tempgrade = grade // 10 + def grading(tempgrade): match grade: case 10 | 9: return 'A' @@ -185,69 +207,134 @@ Java also supports a switch statement that acts something like the eli return 'D' case _: return 'F' - print(grading(grade)) + print(grading(tempgrade)) - +

switch - The switch statement in Java provides a clean and efficient alternative to chaining multiple if-else conditions, especially when comparing a single variable against several constant values. It supports a variety of data types, including primitive types (byte, short, char, int), their wrapper classes, enumerations, and String (introduced in Java 7). Each case within a switch must be defined using a constant expression, and duplicate case values are not permitted. By default, control flow "falls through" from one case to the next unless a break, return, or throw statement is used to terminate execution. -

-

switch expressions - Java 14 introduced switch expressions, enhancing functionality by allowing the switch to return values and eliminating fall-through via the -> arrow syntax. These expressions can even use yield within code blocks for more complex evaluations. It’s important to note that traditional switch statements do not support null values and will throw a NullPointerException if evaluated with null. As the language evolves, newer versions of Java continue to extend switch capabilities with features like pattern matching and enhanced type handling, making it a more powerful and expressive tool for decision-making in Java programs. + The switch statement in Java provides an alternative to chaining multiple if-else conditions, when comparing a single variable against several constant values. It supports a variety of data types, including primitive types (byte, short, char, int), their wrapper classes, enumerations, and String (introduced in Java 7). Each case within a switch must be defined using a constant expression, and duplicate case values are not permitted. By default, control flow "falls through" from one case to the next unless a break, return, or throw statement is used to terminate execution.

- - - - +

+ switch expressions + yield + Java 14 introduced switch expressions, enhancing functionality by allowing the switch to return values and eliminating fall-through via the -> arrow syntax. These expressions can even use yield within code blocks for more complex evaluations. yield is used inside a switch expression’s block to produce the value of that expression, unlike break which simply exits a switch statement or loop. It’s important to note that traditional switch statements do not support null values and will throw a NullPointerException if evaluated with null. As the language evolves, newer versions of Java continue to extend switch capabilities with features like pattern matching and enhanced type handling, making it a more powerful and expressive tool for decision-making in Java programs. shows how the switch expression is written in Java. +

+ + -public class SwitchUp { - public static void main(String args[]) { - int grade = 85; - int tempgrade = grade / 10; - switch(tempgrade) { - case 10: - case 9: - System.out.println('A'); - break; - case 8: - System.out.println('B'); - break; - case 7: - System.out.println('C'); - break; - case 6: - System.out.println('A'); - break; - default: - System.out.println('F'); - } - } - } + public class SwitchUp { + public static void main(String args[]) { + int grade = 85; + // Convert grade to a scale of 0-10 using integer division + int tempgrade = grade / 10; + switch(tempgrade) { + case 10: + case 9: + System.out.println('A'); + break; + case 8: + System.out.println('B'); + break; + case 7: + System.out.println('C'); + break; + case 6: + System.out.println('A'); + break; + default: + System.out.println('F'); + } + } + } +

The switch statement is not used very often, and we recommend you do not use it. First, it is not as powerful as the else if model because the switch variable can only be compared for equality with an integer or enumerated constant. Second, it is very easy to forget to put in the break statement, so it is more error-prone. If the break statement is left out then then the next alternative will be automatically executed. For example, if the grade was 95 and the break was omitted from the case 9: alternative then the program would print(out both A and B.)

+

+ Finally, the switch statement does not support relational expressions such as greater than or less than. So you cannot use it to completely replace the elif. Even with the new features of Java 14+ the switch statement is still limited to constant comparisons using equality.

+
+ + + +

+ Rearrange the blocks to create a Java method that accepts a temperature reading and returns a status string ("CRITICAL", "WARNING", or "NORMAL"). +

+
+ + + + public String checkTemperature(double temp) { + + + public String checkTemperature(double temp); { + + + + + + if (temp >= 100.0) { + return "CRITICAL"; + } + + + if (temp == 100.0) { + return "CRITICAL"; + } + + + + + + else if (temp >= 75.0) { + return "WARNING"; + } + + + else (temp >= 75.0) { + return "WARNING"; + } + + + + + + else { + return "NORMAL"; + } + + + else if { + return "NORMAL"; + } + + + + + } + + +
+
-
- Boolean Operators +
+ The Ternary Operator -

Boolean operators -The conditionals used in the if statement can be Boolean variables, simple comparisons, and compound Boolean expressions. +

Boolean operators simple comparisons compound Boolean expressions +The conditionals used in the if statement can be Boolean variables, simple comparisons, and compound Boolean expressions.

ternary operator -Java also supports the boolean expression using the ternary operator -condition ? trueValue : falseValue. This operator tests a condition as part -of an assignment statement. The following table summarizes how this works: +Java also provides the ternary operator condition ? valueIfTrue : valueIfFalse, which lets you use a boolean test directly inside an assignment. If the condition is true, the first value is chosen; otherwise, the second value is used. summarizes how it works.

-
+
Ternary Operator in Java @@ -256,7 +343,7 @@ of an assignment statement. The following table summarizes how this works: condition - The Boolean expression that is evaluated (e.g., a % 2 == 0). + The boolean expression that is evaluated (e.g., a % 2 == 0). ? @@ -286,29 +373,385 @@ of an assignment statement. The following table summarizes how this works:

-Using this operator can make code shorter and more readable in cases where a simple conditional assignment is needed. +Using this operator can make code shorter and more readable in cases where a simple conditional assignment is needed. shows an example where we see the same logic implemented in two different ways.

- + + + +public class Ternary { + public static void main(String[] args) { + int a = 4; + int x = 2; + int outp; + + // ternary: + outp = (a % 2 == 0) ? (a * a) : (3 * x - 1); + System.out.println("ternary result: " + outp); + + // Equivalent using if/else + if (a % 2 == 0) { + outp = a * a; + } else { + outp = 3 * x - 1; + } + + System.out.println("if/else result: " + outp); + } +} + + + + +

+ In , we are using this ternary operator to assign a value to a based on whether a is even or odd. If a is even, it will be squared; if odd, it will be instead be calculated as 3 * x - 1. This is a concise way to write conditional assignments in Java. However, you might want to use it sparingly, as it can make code less readable if overused or used with complex expressions. +

+ + + +

+ Rearrange the blocks to create a Java method that calculates shipping costs. Orders over $100 get free shipping ($0.0), while members pay $5.0 and non-members pay $10.0. +

+
+ + + + public double calculateShipping(double orderTotal, boolean isMember) { + + + public double calculateShipping() + double orderTotal + boolean isMember + { + + + + + + if (orderTotal >= 100.0) { + return 0.0; + } + + + if (orderTotal = 100.0) { + return 0.0; + } + + + + + + else { + return isMember ? 5.0 : 10.0; + } + + + else { + return isMember : 5.0 ? 10.0; + } + + + + + } + + +
+ + +
+ Exception Handling + +

+ In Python, if you want a program to continue running when an error has occurred, you can use try-except blocks to handle exceptions. If you wanted to write a program that asks the user to enter a whole number and then squares that number, you could use the following code to do so. shows the Python code to achieve this. +

+ + + - class Main { - public static void main(String[] args) { - int a = 4; - int x = 2; + number = int(input("Please enter a whole number: ")) # ask user for a number + squared = number ** 2 # square the number + print("Your number squared is " + str(squared)) + + + - // Using the ternary operator - a = (a % 2 == 0) ? a * a : 3 * x - 1; +

+ shows the Java code that would perform the same task. It is a little more complex and utilizes the Scanner class for input. +

+ + + + import java.util.Scanner; - System.out.println("Result: " + a); - } + public class SquareNumber { + public static void main(String[] args) { + Scanner user_input = new Scanner(System.in); // create a scanner object + + System.out.print("Please enter a whole number: "); + int number = user_input.nextInt(); // ask user for a number + int squared = number * number; // square the number + + System.out.println("Your number squared is " + squared); } - + } + + + + +

+ This code works well, but will end with an exception if the user types anything other than a whole number (such as 12.5 or two). If we wanted to ensure the code will continue to run until the user enters the correct format, we could add try-except (Python) or try-catch (Java) blocks within a while loop that iterates until the user enter the correct code. While try-except blocks aren't strictly required in Python, shows how using them alongside a while loop makes the code more robust. +

+ + + + while True: + try: # try to convert the user input to an integer + number = int(input("Please enter a whole number: ")) + squared = number ** 2 + print("Your number squared is " + str(squared)) + break + except ValueError: # if the user enters a non-integer, print an error message + print("That was not a valid number. Please try again: ") +

- In this example we are using this ternary operator to assign a value to a based on whether a is even or odd. If a is even, it will be squared; if odd, it will be instead be calculated as 3 * x - 1. This is a concise way to write conditional assignments in Java. However, it should be used reasonably, as it can make code less readable if overused or used in complex expressions. + Now that we have Python code that will continuously prompt the user until they enter a whole number, shows the Java code that accomplishes the same task. Like most other equivalent Java code blocks, this code has a lot of extra bits that are necessary to get working code.

+ + + + import java.util.Scanner; + import java.util.InputMismatchException; + public class SquareNumberWithValidation { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + while (true) { // keep asking the user for a number until they enter a valid integer + try { // try to convert the user input to an integer + System.out.print("Please enter a whole number: "); + int number = scanner.nextInt(); + int squared = number * number; + System.out.println("Your number squared is " + squared); + break; + } catch (InputMismatchException e) { // if the user enters a non-integer, print an error message + System.out.println("That was not a valid number. Please try again: "); + scanner.nextLine(); // Clear the invalid input from the scanner + } + } + } + } + + + +

+ Firstly, let's talk about the extra import alongside the Scanner import. In Java, we need to import InputMismatchException because it's not automatically available like basic exceptions. This is different from Python where most exceptions are readily accessible. If you ran the previous Java codeblock without try-catch blocks and entered an erroneous input, you would have got an InputMismatchException exception despite not having imported this class. That being said, removing the explicit import of this library for the try-catch code block above will lead to compilation errors. +

+ +

+ checked exception + unchecked exception + Exceptions in Java fall under two categories: checked and unchecked. Checked exceptions must be explicitly imported and declared along with try-catch blocks for a program to compile. Unchecked exceptions do not need to be imported unless try-catch blocks are implemented for them (except for java.lang exceptions). InputMismatchException is an unchecked exception that is not part of the java.lang library, so it is only included if try-catch blocks declare it. shows the exceptions used with try-catch blocks. +

+ + + Java Exceptions Used with <c>try-catch</c> Blocks + + + Exception + Package + Description + + + IOException + java.io + Thrown when an I/O operation fails (e.g., reading or writing a file). + + + FileNotFoundException + java.io + Thrown when an attempt to open a file denoted by a pathname has failed. + + + ParseException + java.text + Thrown when parsing a string into a date, number, etc. fails (e.g., wrong format). + + + NoSuchMethodException + java.lang + Thrown when a particular method cannot be found via reflection. + + + InputMismatchException + java.util + Thrown when Scanner input doesn’t match the expected data type. + + + SQLException + java.sql + Thrown when a database access error occurs (e.g., invalid SQL query, bad connection). + + + InstantiationException + java.lang + Thrown when trying to create an instance of an abstract class or interface. + + + IllegalAccessException + java.lang + Thrown when a reflection operation tries to access a field or method it doesn't have permission for. + + +
+ +

+ Note that as with other structures in Java, try-catch blocks blocks must be encased with braces {}. The most important part of this code is, after catch, there is a set of parenthesis with an exception type and a variable name catch (InputMismatchException e). This is where we declare a InputMismatchException exception and name it with the variable name e. It is common practice, though not a requirement, to name exception variables e in this manner. +

+ +
+
+ Summary & Reading Questions +

    +
  1. +

    Java requires parentheses around the condition and curly braces for code blocks in if statements, unlike Python which uses indentation alone.

    +
  2. +
  3. +

    Java uses else if instead of Python's elif, and allows optional curly braces for single-line blocks. However, it is considered good practice to use curly braces even for single-line blocks to improve readability.

    +
  4. +
  5. +

    + Java's switch statement is similar to Python's match statement, but it only supports equality checks against constant values and does not evaluate relational expressions like greater than or less than. +

    + +
  6. +
  7. +

    + Java uses the boolean data type to represent logical values true or false, commonly used in conditionals and control flow. +

    +
  8. +

+ + + +

Which is a correct Java if statement syntax?

+
+ + + +

if (x > 0) { System.out.println("Positive"); }

+
+ +

Correct! Java requires parentheses and curly braces.

+
+
+ + +

if x > 0: print("Positive")

+
+ +

No, that's Python syntax, not Java.

+
+
+ + +

if x > 0 { System.out.println("Positive"); }

+
+ +

No, Java requires parentheses around the condition.

+
+
+ + +

if (x > 0) print("Positive");

+
+ +

No, print is not a valid method in Java. Use System.out.println.

+
+
+
+
+ + +

How do you write Python’s elif equivalent in Java?

+
+ + + +

elif (score > 90)

+
+ +

No, elif is used in Python, not Java.

+
+
+ + +

else: if (score > 90)

+
+ +

Incorrect syntax; no colon in Java and not the right structure.

+
+
+ + +

else if (score > 90)

+
+ +

Right! Java uses else if.

+
+
+ + +

ifelse (score > 90)

+
+ +

No, ifelse is not a valid construct in Java.

+
+
+
+
+ + +

What is one limitation of Java's switch statement, including in its modern versions?

+
+ + + +

It cannot evaluate relational expressions like greater than or less than.

+
+ +

No, while switch can compare values, it does not support relational expressions like > or <, even with modern enhancements of Java 14+

+
+
+ + +

It cannot handle more than five case labels.

+
+ +

No, there is no such limit. You can have many case labels in a switch statement.

+
+
+ + +

It always requires a break statement.

+
+ +

Incorrect. The break statement is actually an optional feature of switch, not a limitation.

+
+
+ + +

It can only compare a variable to constant values using equality.

+
+ +

Correct! Java's switch is limited to constant comparisons using equality.

+
+
+
+
+
\ No newline at end of file diff --git a/source/ch5_loopsanditeration.ptx b/source/ch5_loopsanditeration.ptx index fd10c12..c0e87a1 100644 --- a/source/ch5_loopsanditeration.ptx +++ b/source/ch5_loopsanditeration.ptx @@ -11,161 +11,230 @@

for loop - A definite loop is a loop that is executed a specific or definite number of times. In Python, the easiest way to write a definite loop is using the for loop in conjunction with the range function. - For example: + definite loop + A definite loop, also known as a for loop, is a loop that is executed for a specific or definite number of times. In Python, the easiest way to write a definite loop is using the for loop structure in conjunction with the range function. shows the syntax for the range function.

- + -for i in range(10): +for i in range(10): # range(10) is a list of integers from 0 to 9 print(i) +

- In Java, we would write this as: + shows how the for loop is written in Java.

+ public class DefiniteLoopExample { public static void main(String[] args) { - for (Integer i = 0; i < 10; i++ ) { + for (Integer i = 0; i < 10; i++ ) { // notice how the initialization, condition, and update are all on the same line. System.out.println(i); } } } +

- Recall that the range function provides you with a wide variety of options for controlling the value of the loop variable. + Recall that the range function provides you with a wide variety of options for controlling the value of the loop variable as shown in .

- -
+        +        
+        
         range(stop)
         range(start,stop)
         range(start,stop,step)
-        
+ +
+

- The Java for loop is really analogous to the last option giving you explicit control over the starting, stopping, and stepping in the three clauses inside the parenthesis. - You can think of it this way: + The Java for loop is really analogous to the last option giving you explicit control over the starting, stopping, and stepping in the three clauses inside the parenthesis. + shows how the Java for loop is written.

- -
+        +        
+        
         for (start clause; stop clause; step clause) {
             statement1
             statement2
         ...
         }
-        
- + + + +

- If you want to start at 100, stop at 0 and count backward by 5, the Python loop would be written as: + If you want to start at 100, stop at 0 and count backward by 5, shows how the Python for loop is written.

+ -for i in range(100, -1, -5): +for i in range(100, -1, -5): # start at 100, stop at 0, decrement by 5 print(i) +

- In Java, we would write this as: + shows how the for loop is written in Java.

- + public class DefiniteLoopBackward { public static void main(String[] args) { - for (Integer i = 100; i >= 0; i -= 5) { + for (Integer i = 100; i >= 0; i -= 5) { // start at 100, stop at 0, decrement by 5 System.out.println(i); } } } - +

In Python, the for loop can also iterate over any sequence such as a list, a string, or a tuple. Java also provides a variation of its for loop that provides the same functionality in its so-called for each loop.

- In Python, we can iterate over a list as follows: + shows how the for loop can be used to iterate over a list in Python.

- + -l = [1, 1, 2, 3, 5, 8, 13, 21] -for fib in l: +l = [1, 1, 2, 3, 5, 8, 13, 21] # create a list of integers +for fib in l: # iterate over the list print(fib) +

- In Java we can iterate over an ArrayList of integers too. Note that this requires importing the ArrayList class. + shows how the for loop can be used to iterate over an ArrayList of integers in Java.

- + import java.util.ArrayList; public class ForEachArrayListExample { public static void main(String[] args) { - ArrayList<Integer> l = new ArrayList<Integer>(); - l.add(1); - l.add(1); - l.add(2); + ArrayList<Integer> l = new ArrayList< // create an ArrayList of integers + l.add(1); // add the first integer to the list + l.add(1); // add the second integer to the list + l.add(2); // keep going l.add(3); l.add(5); l.add(8); l.add(13); - l.add(21); - for (Integer i : l) { + l.add(21); // add the last integer to the list + for (Integer i : l) { // iterate over the list System.out.println(i); } } } +

- This example stretches the imagination a bit, and in fact points out one area where Java's primitive arrays are easier to use than an array list. - In fact all primitive arrays can be used in a for each loop. + stretches the imagination a bit, and in fact points out one area where Java's primitive arrays are easier to use than an array list. + shows how the for loop can be used to iterate over all elements in a primitive array in Java.

+ public class ForEachArrayExample { public static void main(String[] args) { - int l[] = {1,1,2,3,5,8,13,21}; - for(int i : l) { + int l[] = {1,1,2,3,5,8,13,21}; // create an array of integers using primitive syntax + for(int i : l) { // iterate over the array System.out.println(i); } } } +

- To iterate over the characters in a string in Java do the following: -

- + shows how the for loop can be used to iterate over all elements in a string in Java. +

+ public class StringIterationExample { public static void main(String[] args) { - String t = "Hello World"; - for (char c : t.toCharArray()) { + String t = "Hello World"; // create a string + for (char c : t.toCharArray()) { // iterate over the characters in the string System.out.println(c); } } } + + + + +

+ Rearrange the blocks to create a Java method that accepts an upper bound integer limit and calculates the sum of all even numbers from 2 up to and including limit. +

+
+ + + public int sumEvens(int limit) { + + + + + int total = 0; + + + int total; + + + + + + for (int i = 2; i <= limit; i += 2) { + + + for (int i = 2; i < limit; i =+ 2) { + + + + + + total += i; + } + + + total = i; + } + + + + + + return total; + } + + + return i; + } + + + +
@@ -174,54 +243,113 @@ public class StringIterationExample {

while loop Both Python and Java support the while loop, which continues to execute as long as a condition is true. - Here is a simple example in Python that counts down from 5: + shows a simple example in Python that counts down from 5.

+ i = 5 -while i > 0: +while i > 0: # while i is greater than 0 print(i) - i = i - 1 + i = i - 1 +

- In Java we add parenthesis and curly braces. Here is the same countdown loop in Java: + In Java, we add parentheses and curly braces. shows the same countdown loop in Java.

+ public class WhileLoopExample { public static void main(String[] args) { - int i = 5; - while (i > 0) { + int i = 5; + while (i > 0) { // while i is greater than 0 System.out.println(i); - i = i - 1; + i = i - 1; } } } +

do-while loop Java adds an additional, if seldom used variation of the while loop called the do-while loop. The do-while loop is very similar to while except that the condition is evaluated at the end of the loop rather than the beginning. This ensures that a loop will be executed at least one time. Some programmers prefer this loop in some situations because it avoids an additional assignment prior to the loop. - For example, the following loop will execute once even though the condition is initially false. + For example, shows how loop will execute once even though the condition is initially false.

- + public class DoWhileExample { public static void main(String[] args) { - int i = 10; - do { + int i = 10; + do { // do-while loop, will run at least once no matter the condition System.out.println("This runs once, i = " + i); - } while (i < 5); + } while (i < 5); // while i is less than 5 } } + + + + +

+ Rearrange the blocks to create a Java method that accepts a starting balance and a target amount, then calculates how many years it takes for the balance to reach or exceed the target by doubling each year. +

+
+ + + + public int yearsToTarget(double balance, double target) { + int years = 0; + + + public int yearsToTarget(double balance, double target) { + int years; + + + + + + while (balance < target) { + + + while (balance >= target) { + + + + + + balance *= 2; + years++; + } + + + balance * 2; + years++; + } + + + + + + return years; + } + + + return balance; + } + + + +
+
Summary & Reading Questions @@ -321,7 +449,6 @@ public class DoWhileExample { -
- \ No newline at end of file + diff --git a/source/ch6_definingclasses.ptx b/source/ch6_definingclasses.ptx index 7a95433..5042038 100644 --- a/source/ch6_definingclasses.ptx +++ b/source/ch6_definingclasses.ptx @@ -4,6 +4,172 @@ Classes in Java + + +
+ Classes and Objects + +

+ object-oriented programming OOP + Depending on how deep your knowledge of Python and programming in general is, you may or may not be familiar with classes and objects. These two important Object-Oriented Programming (OOP) concepts will briefly be discussed. If you already have a good understanding of classes and objects in Python, this section may be skipped. +

+ +

+ object + attribute + instance variable + method + Objects in the context of programming are instances of classes. Objects contain attributes (also referred to as instance variables), which are data that describe the object or are associated with the object, and methods, which are special functions used by the object. Methods are typically actions the object can perform, or can be used to make changes to the object's attributes. +

+ +

+ class + constructor + Classes can be thought of as being similar to blueprints or a recipe; they hold details of how to create an instance of an object. Classes contain a special method called a constructor that is used to create an instance of an object. Once the object is created, it will use the class definition to define its attributes and call methods. +

+ +

+ The best way to understand classes and objects is to see them in action. Let's define a Dog class in Python: +

+ + + + + class Dog: + """ A simple Dog class definition. """ + def __init__(self, name, breed, fur_color): + # constructor method to create a Dog object + self.name = name + self.breed = breed + self.fur_color = fur_color + self.trained = False # dogs are not trained by default + print("Dog named " + self.name + " created!") + + def bark(self): + # method to make the dog bark + print(self.name + " says woof!") + + def sit(self): + # method to make the dog sit + if self.trained: # check if the dog has been trained otherwise it will not sit + print(self.name + " sits.") + else: + print(self.name + " has not been trained.") + + def train(self): + # method to train the dog, which will set the trained attribute to True + self.trained = True + + + + +

+ Let's unpack what is going on in . The first line is where we declare the class definition and name it Dog. Next, we have a special method called __init__. This __init__ method is the constructor and is required for every Python class definition. Within the __init__ method, attributes are defined. As you can see, the attributes name, breed, and fur_color must be defined when creating a Dog object using this class definition, but the trained attribute is defined within the constructor and is initialized as False. We can also have the __init__ method run any code, such as the print statement informing us that a Dog object was created. +

+ +

+ The next three blocks of code are the class's methods. These include bark(self), sit(self), and train(self). As you can see, the class defines attributes (the variables in the __init__ method) and methods for instances of the Dog class. +

+ +

+ self + Within each method, and for each attribute, you will notice the use of self. This is required in Python. self simply indicates that an attribute or method is being used for a specific instance of an object created with a class. +

+ +

+ Next, we will use this class to create a new Dog object. We will call this new Dog object my_dog: +

+ + + + class Dog: + """ A simple Dog class definition. """ + def __init__(self, name, breed, fur_color): + # constructor method to create a Dog object + self.name = name + self.breed = breed + self.fur_color = fur_color + self.trained = False # dogs are not trained by default + print("Dog named " + self.name + " created!") + + def bark(self): + # method to make the dog bark + print(self.name + " says woof!") + + def sit(self): + # method to make the dog sit + if self.trained: # check if the dog has been trained otherwise it will not sit + print(self.name + " sits.") + else: + print(self.name + " has not been trained.") + + def train(self): + # method to train the dog, which will set the trained attribute to True + self.trained = True + + # Create a Dog object called my_dog + my_dog = Dog("Rex", "pug", "brown") + + + +

+ In the final line of code in , we have created an object called my_dog. We have initialized its attributes, setting name to Rex, breed to pug, and fur_color to brown. +

+ +

+ Now that we have created a Dog object using the class we defined, we can utilize the class's methods: +

+ + + + + class Dog: + """ A simple Dog class definition. """ + def __init__(self, name, breed, fur_color): + # constructor method to create a Dog object + self.name = name + self.breed = breed + self.fur_color = fur_color + self.trained = False # dogs are not trained by default + print("Dog named " + self.name + " created!") + + def bark(self): + # method to make the dog bark + print(self.name + " says woof!") + + def sit(self): + # method to make the dog sit + if self.trained: + print(self.name + " sits.") + else: + print(self.name + " has not been trained.") + + def train(self): + # method to train the dog, which will set the trained attribute to True + self.trained = True + + + my_dog = Dog("Rex", "pug", "brown") + my_dog.bark() # call the bark method + my_dog.sit() # call the sit method + + + + + +

+ When running , the line Rex has not been trained. will appear in the output when calling the sit() method. Try adding a one or more lines of code so that Rex sits. appears in the output! +

+
+ +

+ Now, we have a full class definition and have utilized its methods. Class definitions in Java will be covered thoroughly in chapter 6. For now, it is important to know that Python programs can be written without using classes at all. Java, on the other hand, requires all code to reside in a class. This will be discussed later in chapter 6. +

+ +
+ + +
Defining Classes in Java @@ -62,10 +228,10 @@

- Here is a mostly complete implementation of a Fraction class in Python that we will refer to throughout this section: + is a mostly complete implementation of a Fraction class in Python that we will refer to throughout this section.

- + class Fraction: @@ -76,37 +242,54 @@ """ self.num = num self.den = den - def __repr__(self): - if self.num > self.den: - retWhole = int(self.num / self.den) - retNum = self.num - (retWhole * self.den) + def __repr__(self): + """ + :return: a string representation of the fraction + """ + if self.num > self.den: + retWhole = int(self.num / self.den) # find the whole number part + retNum = self.num - (retWhole * self.den) # find the numerator part return str(retWhole) + " " + str(retNum) + "/" + str(self.den) else: return str(self.num) + "/" + str(self.den) def show(self): + """ + :return: print the fraction + """ print(self.num, "/", self.den) def __add__(self, other): + """ + :param other: the fraction to add + :return: the sum of the two fractions + """ # convert to a fraction other = self.toFract(other) - newnum = self.num * other.den + self.den * other.num - newden = self.den * other.den + newnum = self.num * other.den + self.den * other.num # find the new numerator + newden = self.den * other.den # find the new denominator common = gcd(newnum, newden) return Fraction(int(newnum / common), int(newden / common)) - __radd__ = __add__ + __radd__ = __add__ # allow the fraction to be added to a number def __lt__(self, other): + """ + :param other: the fraction to compare + :return: whether the fraction is less than the other + """ num1 = self.num * other.den num2 = self.den * other.num return num1 < num2 def toFract(self, n): + """ + :param n: the number to convert to a fraction + :return: the fraction representation of the number + """ if isinstance(n, int): other = Fraction(n, 1) elif isinstance(n, float): wholePart = int(n) - fracPart = n - wholePart - # convert to 100ths??? - fracNum = int(fracPart * 100) - newNum = wholePart * 100 + fracNum - other = Fraction(newNum, 100) + fracPart = n - wholePart + fracNum = int(fracPart * 100) # convert to 100ths + newNum = wholePart * 100 + fracNum # combine the whole and fractional parts + other = Fraction(newNum, 100) elif isinstance(n, Fraction): other = n else: @@ -115,9 +298,12 @@ return other def gcd(m, n): """ - A helper function for Fraction + A helper function for Fraction. + :param m: the first number + :param n: the second number + :return: the greatest common divisor """ - while m % n != 0: + while m % n != 0: # keep going until the gcd is found oldm = m oldn = n m = oldn @@ -126,6 +312,7 @@ print(sorted([Fraction(5, 16), Fraction(3, 16), Fraction(1, 16) + 1])) +

data members @@ -133,57 +320,61 @@

- The declarations of instance variables can come at the beginning of the class definition or the end. Cay Horstman, author of the “Core Java” books puts the declarations at the end of the class. I like them at the very beginning so you see the variables that are declared before you begin looking at the code that uses them. With that in mind the first part of the Fraction class definition is as follows: + The declarations of instance variables can come at the beginning of the class definition or the end. Cay Horstman, author of the “Core Java” books puts the declarations at the end of the class. I like them at the very beginning so you see the variables that are declared before you begin looking at the code that uses them. With that in mind shows the first part of the Fraction class definition.

- - + + - public class Fraction { - private Integer numerator; + public class Fraction { + private Integer numerator; // notice the private modifier private Integer denominator; } +

+ private Notice that we have declared the numerator and denominator to be private. - This means that the compiler will generate an error if another method tries to write code like the following: + This means that the compiler will generate an error if another method tries to write code like .

- - + + - Fraction f = new Fraction(1,2); - Integer y = f.numerator * 10; + Fraction f = new Fraction(1,2); + Integer y = f.numerator * 10; // trying to access the numerator +

getter method setter method Direct access to instance variables is not allowed in Java. Therefore if we legitimately want to be able to access information such as the numerator or the denominator for a particular fraction we must have a getter method that returns the needed value. - Hence, it is a very common programming practice to both provide getter methods and setter methods when needed for instance variables in Java. + Hence, it is a very common programming practice to both provide getter methods and setter methods when needed for instance variables in Java. shows how the getter and setter methods are written.

- - + + -public Integer getNumerator() { +public Integer getNumerator() { // getter method return numerator; } -public void setNumerator(Integer numerator) { +public void setNumerator(Integer numerator) { // setter method this.numerator = numerator; } -public Integer getDenominator() { +public Integer getDenominator() { // getter method return denominator; } -public void setDenominator(Integer denominator) { +public void setDenominator(Integer denominator) { // setter method this.denominator = denominator; } +
@@ -191,23 +382,25 @@ public void setDenominator(Integer denominator) { Writing a constructor

- constructors + constructor + Once you have identified the instance variables for your class the next thing to consider is the constructor. In Java, constructors have the same name as the class and are declared public. They are declared without a return type. So any method that is named the same as the class and has no return type is a constructor. - Our constructor will take two parameters: the numerator and the denominator. + Our constructor will take two parameters: the numerator and the denominator. shows the constructor for the Fraction class.

- - + + public Fraction(Integer top, Integer bottom) { - num = top; + num = top; // notice the use of num instead of top den = bottom; } +

this @@ -217,18 +410,19 @@ public Fraction(Integer top, Integer bottom) { This allows the Java compiler to do the work of dereferencing the current Java object. Java does provide a special variable called this that works like the self variable. In Java, this is typically only used when it is needed to differentiate between a parameter or local variable and an instance variable. - For example this alternate definition of the the Fraction constructor uses this to differentiate between parameters and instance variables. + For example, shows an alternate definition of the the Fraction constructor that uses this to differentiate between parameters and instance variables.

- - + + public Fraction(Integer num, Integer den) { - this.num = num; + this.num = num; // notice how we use this.num instead of num this.den = den; } +
@@ -254,8 +448,8 @@ public Fraction(Integer num, Integer den) {
  • pass-by-value - value of the reference - Java is strictly pass-by-value. For primitive types (like int), a copy of the value is passed. For object types (like our Fraction), a copy of the value of the reference (the memory address) is passed. + + Java is strictly pass-by-value. For primitive types (like int), a copy of the value is passed. For object types (like our Fraction), a copy of the reference(Namely, the memory address) is passed.

  • @@ -273,21 +467,22 @@ public Fraction(Integer num, Integer den) { However, if you reassign the parameter to a completely new object inside the method (e.g., otherFrac = new Fraction(0,1);), it would not affect the original variable outside the method, because you are only changing the local copy of the reference.

    - Let’s begin by implementing addition in Java: + shows the first part of the Fraction class definition.

    - - + + -public Fraction add(Fraction otherFrac) { +public Fraction add(Fraction otherFrac) { Integer newNum = otherFrac.getDenominator() * this.numerator + - this.denominator * otherFrac.getNumerator(); - Integer newDen = this.denominator * otherFrac.getDenominator(); - Integer common = gcd(newNum, newDen); + this.denominator * otherFrac.getNumerator(); // notice the use of this. + Integer newDen = this.denominator * otherFrac.getDenominator(); // find the new denominator + Integer common = gcd(newNum, newDen); // find the greatest common divisor return new Fraction(newNum/common, newDen/common); } +

    First you will notice that the add method is declared as public Fraction The public part means that any other method may call the add method. @@ -297,21 +492,22 @@ public Fraction add(Fraction otherFrac) {

    Second, you will notice that the method makes use of the this variable. In this method, this is not necessary, because there is no ambiguity about the numerator and denominator variables. - So this version of the code is equivalent: + is an equivalent version of .

    - - + + public Fraction add(Fraction otherFrac) { Integer newNum = otherFrac.getDenominator() * numerator + - denominator * otherFrac.getNumerator(); + denominator * otherFrac.getNumerator(); // notice the absence of this. Integer newDen = denominator * otherFrac.getDenominator(); Integer common = gcd(newNum, newDen); return new Fraction(newNum/common, newDen/common); } +

    The addition takes place by multiplying each numerator by the opposite denominator before adding. @@ -358,21 +554,22 @@ public Fraction add(Fraction otherFrac) { To solve the problem of adding an Integer and a Fraction in Java we will overload both the constructor and the add method. We will overload the constructor so that if it only receives a single Integer it will convert the Integer into a Fraction. We will also overload the add method so that if it receives an Integer as a parameter it will first construct a Fraction from that integer and then add the two Fractions together. - The new methods that accomplish this task are as follows: + shows the new methods that accomplish this task.

    - - + + -public Fraction(Integer num) { - this.numerator = num; +public Fraction(Integer num) { + this.numerator = num; // set the numerator to the Integer this.denominator = 1; } -public Fraction add(Integer other) { - return add(new Fraction(other)); +public Fraction add(Integer other) { // overload the add method when the parameter is an Integer + return add(new Fraction(other)); } +

    Notice that the overloading approach can provide us with a certain elegance to our code. @@ -381,21 +578,21 @@ public Fraction add(Integer other) {

    - Our full Fraction class to this point would look like the following. + Our full Fraction class to this point would look . You should compile and run the program to see what happens.

    - + public class Fraction { private Integer numerator; private Integer denominator; - public Fraction(Integer num, Integer den) { + public Fraction(Integer num, Integer den) { // constructor that takes two Integers this.numerator = num; this.denominator = den; } - public Fraction(Integer num) { + public Fraction(Integer num) { // constructor that takes a single Integer, sets the denominator to 1 this.numerator = num; this.denominator = 1; } @@ -411,10 +608,10 @@ public class Fraction { Integer common = gcd(newNum,newDen); return new Fraction(newNum/common, newDen/common ); } - public Fraction add(Integer other) { + public Fraction add(Integer other) { // overload the add method when the parameter is an Integer return add(new Fraction(other)); } - private static Integer gcd(Integer m, Integer n) { + private static Integer gcd(Integer m, Integer n) { // a helper method for the add method while (m % n != 0) { Integer oldm = m; Integer oldn = n; @@ -423,85 +620,88 @@ public class Fraction { } return n; } - public static void main(String[] args) { + public static void main(String[] args) { // a main method Fraction f1 = new Fraction(1,2); System.out.println(f1.add(1)); } } - - - - Naming Conventions -

    - It is worth pointing out that Java has some very handy naming conventions. It is advisable to both use meaningful names and to follow these naming conventions while developing software in Java for good maintenance and readability of code. -

    - -

    -

      -
    • -

      - Class names should be nouns that are written in UpperCamelCase, namely with the first letter of each word capitalized including the first. - For example, ArrayList, Scanner, StringBuilder, System, etc. -

      -
    • - -
    • -

      - Method names use lowerCamelCase which start with a verb that describes the action they perform. This means that method names start with a lower case letter, and use upper case for each internal-word method names. For example, isInt(), nextLine(), getDenominator(), setNumerator(), etc. -

      -
    • - -
    • -

      - Instance variables of a class start with a lower case letter and use lowerCamelCase like method names. For example, count, totalAmount, etc. -

      -
    • - -
    • -

      - Constants are in all upper case letters or in upper snake case, which also known as screaming snake case, and which is a naming convention in which each word is written in uppercase letters, separated by underscores. - For example, Math.MAXINT or MAX_INT. -

      -
    • -
    -

    -
    -
  • - -
    - Inheritance - - -

    - If you ran the program above you probably noticed that the output is not very satisfying. Chances are your output looked something like this: + +

    + If you ran , you probably noticed that the output is not very satisfying. Chances are your output looked something like .

    - + Fraction@6ff3c5b5 +

    The reason is that we have not yet provided a friendly string representation for our Fraction objects. Just like in Python, whenever an object is printed by the println method it must be converted to string format. In Python you can control how that looks by writing an __str__ method for your class. - If you do not then you will get the default, which looks something like the above. + If you do not then you will get the default, which looks something like . We will see how to provide a friendly string representation for our Fraction class in .

    -
    + + +

    + Rearrange the blocks to create a Printer class with two overloaded printData methods—one that accepts an int and another that accepts a String. +

    +
    + + + public class Printer { + + + + + public void printData(int number) { + System.out.println("Number: " + number); + } + + + public void printData(int number) { + System.out.println("Number: " + number); + + + + + + public void printData(String text) { + System.out.println("Text: " + text); + } + + + public void printData(int text) { + System.out.println("Text: " + text); + } + + + + + } + + +
    + + +
    + +
    + Inheritance The <c>Object</c> Class

    - object class toString In Java, the equivalent of __str__ is the toString method. - Every object in Java already has a toString method defined for it because every class in Java automatically inherits from the Object class. + Every object in Java already has a toString method defined for it because every class in Java automatically inherits from the Object class. The Object class provides default implementations for the following methods.

    @@ -565,54 +765,57 @@ Fraction@6ff3c5b5

    We are not interested in most of the methods on that list, and many Java programmers live happy and productive lives without knowing much about most of the methods on that list. - However, to make our output nicer we will implement the toString method for the Fraction class. - A simple version of the method is provided below. + However, to make our output nicer we will implement the toString method for the Fraction class. shows a simple version of the method.

    - + public String toString() { - return numerator.toString() + "/" + denominator.toString(); + return numerator.toString() + "/" + denominator.toString(); // convert to a string } +

    + equals The other important class for us to implement from the list of methods inherited from Object is the equals method. In Java, when two objects are compared using the == operator they are tested to see if they are exactly the same object (that is, do the two objects occupy the same exact space in the computer’s memory?). This is also the default behavior of the equals method provided by Object. The equals method allows us to decide if two objects are equal by looking at their instance variables. - However it is important to remember that since Java does not have operator overloading if you want to use your equals method you must call it directly. + However it is important to remember that since Java does not have operator overloading if you want to use your equals method you must call it directly. Therefore once you write your own equals method:

    - - + + -object1 == object2 +object1 == object2 // this checks to see if the two objects are the same object in memory +

    - is NOT the same as + is NOT the same as .

    - - + + -object1.equals(object2) +object1.equals(object2) // this checks to see if the two objects are equal by looking at their instance variables +

    - Here is an equals method for the Fraction class: + is an equals method for the Fraction class.

    - + -public boolean equals(Fraction other) { +public boolean equals(Fraction other) { // check if this fraction is equal to another fraction Integer num1 = this.numerator * other.getDenominator(); Integer num2 = this.denominator * other.getNumerator(); if (num1 == num2) @@ -622,6 +825,7 @@ public boolean equals(Fraction other) { } +

    One important thing to remember about equals is that it only checks to see if two objects are equal – it does not have any notion of less than or greater than. @@ -640,26 +844,27 @@ public boolean equals(Fraction other) { If you look at the documentation for Integer you will see that Integer’s parent class is Number. Number is an abstract class that specifies several methods that all of its children must implement. In Java an abstract class is more than just a placeholder for common methods. - In Java an abstract class has the power to specify certain methods that all of its children must implement. + In Java an abstract class has the power to specify certain methods that all of its children must implement. You can trace this power back to the strong typing nature of Java.

    - Here is code that makes the Fraction class a child of Number: + makes the Fraction class a child of Number.

    - - + + -public class Fraction extends Number { +public class Fraction extends Number { // fraction class is a child of Number ... } +

    - extends - The keyword extends tells the compiler that the class Fraction extends, or adds new functionality to the Number class. + extending a class + The keyword extends tells the compiler that the class Fraction extends, or adds new functionality to the Number class. A child class always extends its parent.

    @@ -696,26 +901,27 @@ public class Fraction extends Number {

    - This really isn’t much work for us to implement these methods, as all we have to do is some type conversion and some division: + This really isn’t much work for us to implement these methods, as all we have to do is some type conversion and some division as shown in .

    - + -public double doubleValue() { +public double doubleValue() { // convert to a double return numerator.doubleValue() / denominator.doubleValue(); } -public float floatValue() { +public float floatValue() { // convert to a float return numerator.floatValue() / denominator.floatValue(); } -public int intValue() { +public int intValue() { // convert to an int return numerator.intValue() / denominator.intValue(); } -public long longValue() { +public long longValue() { // convert to a long return numerator.longValue() / denominator.longValue(); } +

    is-a @@ -727,34 +933,66 @@ public long longValue() {

    - However, and this is a big however, it is important to remember that if you specify Number as the type of a particular parameter then the Java compiler will only let you use the methods of a Number: longValue, intValue, floatValue, and doubleValue. + However, and this is a big however, it is important to remember that if you specify Number as the type of a particular parameter then the Java compiler will only let you use the methods of a Number: longValue, intValue, floatValue, and doubleValue.

    - Suppose you try to define a method as follows: + Suppose you try to define a method as .

    - + public void test(Number a, Number b) { - a.add(b); + a.add(b); // this is a bad idea } +

    The Java compiler would give an error because add is not a defined method of the Number class. - You will still get this error even if all your code that calls this test method passes two Fractions as parameters (remember that Fraction does implement add). + You will still get this error even if all your code that calls this test method passes two Fractions as parameters (remember that Fraction does implement add).

    + + + +

    + Construct the toString method for the Fraction class so that printing a + fraction shows it in the form numerator/denominator. Drag the blocks into the correct order on the right. +

    +
    + + + + public String toString() { + + + public void toString() { + + + + + + return numerator.toString() + "/" + denominator.toString(); + + + numerator.toString() + "/" + denominator.toString(); + + + + + } + + +
    Interfaces

    - Comparable single inheritance Lets turn our attention to making a list of fractions sortable by the standard Java sorting method Collections.sort. In Python, we would just need to implement the __cmp__ method. @@ -780,10 +1018,10 @@ public void test(Number a, Number b) {

    The Comparable interface says that any object that claims to be Comparable must implement the compareTo method. - Here is an excerpt from the official documentation for the compareTo method as specified by the Comparable interface. + Here is an excerpt from the official documentation for the compareTo method as specified by the Comparable interface. shows the excerpt.

    - + int compareTo(T o) @@ -796,79 +1034,86 @@ iff y.compareTo(x) throws an exception.) ... +

    - To make our Fraction class Comparable we must modify the class declaration line as follows: + To make our Fraction class Comparable we must modify the class declaration line as shown in .

    - + -public class Fraction extends Number implements Comparable<Fraction> { +public class Fraction extends Number implements Comparable<Fraction> { // fraction class is a child of Number and implements the Comparable interface ... } +

    The specification Comparable<Fraction> makes it clear that Fraction is only comparable with another Fraction. - The compareTo method could be implemented as follows: + The compareTo method could be implemented as shown in .

    - + -public int compareTo(Fraction other) { +public int compareTo(Fraction other) { // compare this fraction with another fraction Integer num1 = this.numerator * other.getDenominator(); Integer num2 = this.denominator * other.getNumerator(); return num1 - num2; } + +
    +
    Static member variables

    Suppose that you wanted to write a Student class so that the class could keep track of the number of students it had created. Although you could do this with a global counter variable that is an ugly solution. - The right way to do it is to use a static variable. - In Python we could do this as follows: + The right way to do it is to use a static variable. + shows how to do this in Python.

    - + class Student: numStudents = 0 - def __init__(self, id, name): + def __init__(self, id, name): self.id = id self.name = name - Student.numStudents = Student.numStudents + 1 + # this is a static variable, that can be accessed without the self prefix + Student.numStudents = Student.numStudents + 1 def main(): for i in range(10): - s = Student(i,"Student-"+str(i)) + s = Student(i,"Student-"+str(i)) # create a new Student object print('Number of students:', Student.numStudents) main() +

    - In Java we would write this same example using a static declaration. + shows how to do this in Java.

    - - + + public class Student { - public static Integer numStudents = 0; + public static Integer numStudents = 0; // static member variable, shared by all instances of the class private int id; private String name; public Student(Integer id, String name) { this.id = id; this.name = name; - numStudents = numStudents + 1; + numStudents = numStudents + 1; // a static variable, that can be accessed without the Student prefix } public static void main(String[] args) { for(Integer i = 0; i < 10; i++) { @@ -879,10 +1124,11 @@ public class Student { } +

    static member variable - In this example notice that we create a static member variable by using the static modifier on the variable declaration. Once a variable has been declared static in Java it can be accessed from inside the class without prefixing the name of the class as we had to do in Python. + In , notice that we create a static member variable by using the static modifier on the variable declaration. Once a variable has been declared static in Java it can be accessed from inside the class without prefixing the name of the class as we had to do in Python.

    @@ -893,10 +1139,14 @@ public class Student { We have already discussed the most common static method of all, main. However in our Fraction class we also implemented a method to calculate the greatest common divisor for two fractions (gdc). There is no reason for this method to be a member method since it takes two Integer values as its parameters. Therefore we declare the method to be a static method of the class. Furthermore, since we are only going to use this gcd method for our own purposes we can make it private.

    +

    + shows the implementation of the static gcd helper method in Java. +

    - + + -private static Integer gcd(Integer m, Integer n) { +private static Integer gcd(Integer m, Integer n) { // static method to compute the greatest common divisor of two integers while (m % n != 0) { Integer oldm = m; Integer oldn = n; @@ -907,17 +1157,18 @@ private static Integer gcd(Integer m, Integer n) { } +
    Full Implementation of the Fraction Class

    - Here is a final version of the Fraction class in Java, which includes all the features we discussed: + shows a final version of the Fraction class in Java, which includes all the features we discussed:

    - + import java.util.ArrayList; import java.util.Collections; @@ -1011,5 +1262,132 @@ public class Fraction extends Number implements Comparable<Fraction> { } +
    + +
    + Summary & Reading Questions +

      +
    1. +

      In Java, instance variables (fields) must be declared in the class body before they are used. Unlike Python, you cannot dynamically add new instance variables to an object at runtime.

      +
    2. +
    3. +

      Java uses access modifiers like private to enforce encapsulation, encouraging data hiding and controlled access through getter and setter methods.

      +
    4. +
    5. +

      Java requires a constructor method to initialize objects. A constructor has the same name as the class and defines its parameters explicitly, whereas Python uses the __init__ method.

      +
    6. +
    7. +

      Every Java class inherits from the Object class, which provides default methods like toString() and equals(). Overriding toString() gives more meaningful output when printing objects (similar to Python’s __str__).

      +
    8. +
    9. +

      By default, Java’s equals() method checks reference equality, just like == for objects. To compare objects based on content (like Fraction values), you must override equals() and call it explicitly.

      +
    10. +
    11. +

      Java supports inheritance through abstract classes (like Number) and interfaces. Extending an abstract class requires implementing its abstract methods, allowing objects like Fraction to be used where a Number is expected.

      +
    12. +

    + + + + + +

    How are instance variables declared in Java compared to Python?

    +
    + + +

    They can be created dynamically anywhere in the class like Python.

    +

    No, Java does not allow dynamic creation of instance variables at runtime.

    +
    + +

    Instance variables are declared inside methods only.

    +

    No, instance variables are declared in the class body, not in methods.

    +
    + +

    They must be declared in the class body before use.

    +

    Correct! Java requires instance variables (fields) to be declared in the class body.

    +
    + +

    Java does not use instance variables.

    +

    No, instance variables are fundamental in Java classes.

    +
    +
    +
    + + + +

    What Java feature encourages encapsulation and controlled access to instance variables?

    +
    + + +

    Declaring all variables as public.

    +

    No, that would expose data and reduce encapsulation.

    +
    + +

    Using access modifiers like private and providing getter/setter methods.

    +

    Right! This is how Java enforces encapsulation.

    +
    + +

    Using global variables.

    +

    No, Java does not support global variables and this reduces encapsulation.

    +
    + +

    Avoiding the use of classes altogether.

    +

    No, encapsulation is a class-based concept in Java.

    +
    +
    +
    + + + +

    How does Java initialize objects differently than Python?

    +
    + + +

    Java uses a constructor method named after the class with explicit parameters.

    +

    Correct! Unlike Python's __init__, Java constructors share the class name.

    +
    + +

    Java uses the __init__ method like Python.

    +

    No, Java does not have __init__.

    +
    + +

    Java initializes objects automatically without constructors.

    +

    No, Java requires constructors for explicit initialization.

    +
    + +

    Java uses global initialization functions instead of constructors.

    +

    No, Java uses constructors, not global functions, for object initialization.

    +
    +
    +
    + + + +

    What must you do in Java to print objects in a readable way and compare two objects based on their contents rather than their memory references?

    +
    + + +

    Use == for content comparison and no need to override toString().

    +

    No, == compares memory references, not content.

    +
    + +

    Only override toString() and use == for equality.

    +

    No, you should override equals() to compare content correctly.

    +
    + +

    Java automatically handles content comparison without overrides.

    +

    No, default equals() compares references, not content.

    +
    + +

    Override toString() for printing and override equals() to compare object contents.

    +

    Yes! This improves output and content-based comparison.

    +
    +
    +
    + +
    +
    + +
    \ No newline at end of file diff --git a/source/ch7_recursion.ptx b/source/ch7_recursion.ptx new file mode 100644 index 0000000..f04f71c --- /dev/null +++ b/source/ch7_recursion.ptx @@ -0,0 +1,480 @@ + + + Recursion in Java + + + +
    + Basic Recursion +

    + In this chapter, we will explore how to translate your recursive logic from Python to Java. While the core concepts of recursion remain the same, the syntax and a bit of the structure of your code will change somewhat. +

    +

    recursionbase caserecursive step + As you may know from Python, recursion is a powerful problem-solving technique involving one or more base cases and recursive steps in which a function or method calls itself while moving towards a base case. When moving to Java, the core logic you've learned remains identical. The challenge is adapting that logic to Java's statically-typed, class-based syntax. +

    + +

    + Let's take the familiar factorial function, which calculates n! (read as "n factorial"), so for example 5! = 5 × 4 × 3 × 2 × 1 = 120. Factorial is a classic example of recursion, where the function calls itself with a smaller value until it reaches a base case. + In general, n! = n \times (n-1) \times (n-2) \times \cdots \times 2 \times 1, + or recursively defined as n! = n \times (n-1)! with base cases 0! = 1 and 1! = 1. +

    +

    + You may recall mathematical notation using the symbol \sum (Greek letter sigma) + to represent "sum." For example, when we sum all elements in an array, we write + \sum_{i=0}^{n-1} a_i, where i=0 below the symbol indicates we start at index 0, + n-1 above it means we end at index n-1, and a_i represents the array + element at each index i. Similarly, \sum_{i=1}^{n} i means "sum all integers + i from 1 to n." +

    +

    + Factorial involves multiplication rather than addition, so we use the product symbol + \prod (Greek letter pi): n! = \prod_{i=1}^{n} i, which means "multiply + all integers i from 1 to n." Both summation and factorial can be expressed + recursively—summation as the first element plus the sum of remaining elements, and factorial + as n \times (n-1)!. +

    +

    + is the Python implementation of the factorial function. It checks for negative numbers, defines the base case for 0! and 1!, and implements the recursive step. +

    + + + +def factorial(n): + # Check for negative numbers + if n < 0: + print("Factorials are only defined on non-negative integers.") + return + # Base Case: 0! or 1! is 1 + if n <= 1: + return 1 + # Recursive Step: n * (n-1)! + return n * factorial(n - 1) + +number = 5 +print(str(number) + "! is " + str(factorial(number))) + + + + + +

    + Many Python programs organize related functions into classes. The same factorial function can be placed inside a class as a method instead of as a function. When this is done, you need to create an instance of the class in order to call the method. Below, we create the class MathTools with a method factorial, and we call it from the main function. +

    +

    + is the Python implementation of the factorial function as a method within a class. It maintains the same logic as the previous function but is now encapsulated within a class structure. +

    + + + + +class MTools: + def factorial(self, n): + # Check for negative numbers + if n < 0: + print("Factorials are only defined on non-negative integers.") + return + # Base Case: 0! or 1! is 1 + if n <= 1: + return 1 + # Recursive Step: n * (n-1)! + return n * self.factorial(n - 1) + +def main(): + # Create an instance of the class and call the method + mtools_instance = MTools() + number = 5 + print(str(number) + "! is " + str(mtools_instance.factorial(number))) + +main() + + + + +

    + See if you can spot the differences in the Java version below. +

    +

    + is the Java implementation of the factorial function. It follows the same logic as the Python version but adapts to Java's syntax and type system. +

    + + + +public class MTools { + public static int factorial(int n) { + // Check for negative numbers + if (n < 0) { + System.out.println("Factorials are only defined on non-negative integers."); + return -1; // Return -1 to indicate error + } + // Base Case: 0! or 1! is 1 + if (n <= 1) { + return 1; + } + // Recursive Step: n * (n-1)! + return n * factorial(n - 1); + } + + public static void main(String[] args) { + int number = 5; + System.out.println(number + "! is " + factorial(number)); + } +} + + + +

    + Notice the key differences from Python: instead of def factorial(n):, Java uses public static int factorial(int n) which declares the method's visibility as public, that it belongs to the class rather than an instance (hence, static), the return type as integer, and the parameter type also as integer. The recursive logic—base case and recursive step—remains identical to Python, and, of course, all code blocks use curly braces {} instead of indentation. +

    +
    + +
    + Using Helper Methods + +

    + In many recursive algorithms, the recursive calls need extra information that the original caller shouldn't have to provide. For example, to recursively process an array, you need to keep track of the index of the current position. This extra information clutters the public-facing signature by forcing users to provide implementation details they shouldn't actually need to know about. +

    +

    helper method pattern in recursion + A common pattern to solve this problem is by using a helper method. This pattern lets you create a clean, simple function or public method that users can call, while the private helper function or method handles the complex details of the recursion. The function or public method typically makes an initial call to the private helper method or function, providing the necessary starting values for the extra parameters. +

    + + +

    + First, let's see what happens if we try to write a recursive array sum function without using a helper method. In this approach, the user must provide the starting index, which is awkward and exposes implementation details. shows a Python version. +

    + + + +class ArrayProcessor: + def sum_array(self, arr, index): + """ + This version forces users to provide the index parameter. + This is inconvenient and exposes implementation details. + """ + # Base case: we've processed all elements + if index >= len(arr): + return 0 + + # Recursive step: current element + sum of remaining elements + return arr[index] + self.sum_array(arr, index + 1) + +def main(): + processor = ArrayProcessor() + numbers = [1, 2, 3, 4, 5] + # Users must remember to start at index 0 - this is confusing! + result = processor.sum_array(numbers, 0) + print("The sum of " + str(numbers) + " is " + str(result)) + +main() + + + + +

    + 's approach has a significant problem, namely that users must remember to start with index 0. Hence, the method signature is cluttered with an implementation detail, and it's easy to make a mistake by passing the wrong starting index. The same awkward pattern appears in Java as shown in . +

    + + + +public class ArrayProcessor { + public static int sumArray(int[] arr, int index) { + // Base case: we've processed all elements + if (index >= arr.length) { + return 0; + } + + // Recursive step: current element + sum of remaining elements + return arr[index] + sumArray(arr, index + 1); + } + + public static void main(String[] args) { + int[] numbers = {1, 2, 3, 4, 5}; + // Users must remember to start at index 0 - this is confusing! + int result = sumArray(numbers, 0); + System.out.println("The sum of [1, 2, 3, 4, 5] is " + result); + } +} + + + + +

    + Both versions force users to understand and provide implementation details they shouldn't need to know about. Now let's see how helper methods solve this problem by providing a clean, user-friendly interface. Notice how the public method only requires the array itself, and the hidden recursive logic tracks the current index position. +

    +

    + shows the improved Python version using a helper method. +

    + + + +class ArrayProcessor: + def sum_array(self, arr): + """ + Public method that provides a clean interface for summing array elements. + Users only need to provide the array - no implementation details required. + """ + if not arr: # Handle empty array + return 0 + # Start the recursion at index 0 + return self._sum_helper(arr, 0) + + def _sum_helper(self, arr, index): + """ + Private helper method that does the actual recursive work. + Tracks the current index position through the array. + """ + # Base case: we've processed all elements + if index >= len(arr): + return 0 + + # Recursive step: current element + sum of remaining elements + return arr[index] + self._sum_helper(arr, index + 1) + +def main(): + processor = ArrayProcessor() + numbers = [1, 2, 3, 4, 5] + result = processor.sum_array(numbers) + print("The sum of " + str(numbers) + " is " + str(result)) + +main() + + + + +

    separation of concerns + The key insight here is called the separation of concerns. The public sum_array method provides a user-friendly interface—callers just pass an array and get the sum. Users don't need to know about indexes or how the recursion works internally. The private _sum_helper method handles the recursive logic with the extra parameter needed to track progress through the array. +

    + +

    + The same helper method pattern can be applied in Java, as shown in . The public method sumArray provides a clean interface, while the private helper method sumHelper manages the recursion and index tracking. +

    + + + +import java.util.Arrays; + +public class ArrayProcessor { + public static int sumArray(int[] arr) { + // Handle empty array + if (arr.length == 0) { + return 0; + } + // Start the recursion at index 0 + return sumHelper(arr, 0); + } + + private static int sumHelper(int[] arr, int index) { + // Base case: we've processed all elements + if (index >= arr.length) { + return 0; + } + + // Recursive step: current element + sum of remaining elements + return arr[index] + sumHelper(arr, index + 1); + } + + public static void main(String[] args) { + int[] numbers = {1, 2, 3, 4, 5}; + int result = sumArray(numbers); + System.out.println("The sum of " + Arrays.toString(numbers) + " is " + result); + } +} + + + + +

    + Compare these improved versions with the earlier problematic ones. Notice how much cleaner the method calls become: processor.sum_array(numbers) in Python and sumArray(numbers) in Java. Users no longer need to worry about providing a starting index or understanding the internal mechanics of the recursion. The helper method pattern creates a clear separation between what users need to know (just pass an array) and the implementation details (tracking the index through recursion). +

    + +

    + This helper method pattern is invaluable when your recursive algorithm needs to track additional state details (like array positions, accumulated values, or depth counters) that the original caller shouldn't need to know about or care about. It's a fundamental pattern and technique you'll likely use frequently in recursive problem solving. +

    +
    + +
    + Recursion Limits: Python vs. Java +

    recursion limitscall stack + When using recursion, both Python and Java have practical limits on how deep the recursion can go before running into errors. This is due to the way both languages manage something called the call stack, which is a limited amount of memory used to keep track of function or method calls. +

    +

    + The consequence of running out of call stack space, is a concept you may have already encountered in Python. Java handles this in a very similar way to Python, both throwing an error when the call stack depth is exceeded. +RecursionErrorStackOverflowError + The only difference is the name of the error: + +

      +
    • In Python, overflowing the call stack raises a RecursionError error.
    • +
    • In Java, it throws a StackOverflowError.
    • +
    +

    + +

    + In both languages, if you write a recursive function that doesn't have a base case or that just recurses too deeply, you'll eventually hit this limit. When this happens, Python will raise a RecursionError, while Java will throw a StackOverflowError. This is because both languages use a call stack to keep track of function calls, and when the stack runs out of space, it results in an error. + Hence, when an algorithm might require thousands of recursive calls, an iterative, loop-based, approach is likely going to be the preferred solution in both Python and Java. +

    + +

    + The following Python code in demonstrates a situation where a function calls itself indefinitely without a base case, leading to a RecursionError due to overflowing the call stack. +

    + + + + def cause_recursion_error(): + """ + This function calls itself without a base case, guaranteeing an error. + """ + cause_recursion_error() + + print("Calling the recursive function... this will end in an error!") + + # The line below will start the infinite recursion. + # Python will stop it and raise a RecursionError automatically. + # Each call adds a new layer to the program's call stack. + # Eventually, the call stack runs out of space, causing the error. + cause_recursion_error() + + + + +

    + The following Java code in demonstrates a similar situation, where a method calls itself indefinitely without a base case, leading to a StackOverflowError. +

    + + + + public class Crash { + public static void causeStackOverflow() { + // The line below will start the infinite recursion. + // Java will stop it and raise a StackOverflowError automatically. + // Each call adds a new layer to the program's call stack. + // Eventually, the call stack runs out of space, causing the error. + causeStackOverflow(); + } + // A main method is required to run the Java program. + public static void main(String[] args) { + System.out.println("Calling the recursive method... this will end in an error!"); + + causeStackOverflow(); + } + } + + + +
    + +
    + Summary & Reading Questions +

      +
    1. +

      Recursion solves problems by defining a base case and a recursive step; each call reduces the problem size until the base case is reached.

      +
    2. +
    3. +

      Java methods must declare visibility, static/instance context, return type, and parameter types; e.g., public static int factorial(int n).

      +
    4. +
    5. +

      The recursive logic in Java mirrors Python conceptually, but Java uses curly braces {} and explicit types instead of indentation and dynamic typing.

      +
    6. +
    7. +

      The helper method pattern hides implementation details (like array indices) from callers, providing clean public interfaces while managing recursive state privately.

      +
    8. +
    9. +

      Deep or unbounded recursion can exhaust the call stack: Python raises RecursionError; Java throws StackOverflowError.

      +
    10. +
    11. +

      Neither Java nor Python guarantees tail call optimization, so programmers should use iterative solutions for algorithms that would require very deep recursion.

      +
    12. +
    13. +

      Recursive methods in Java must specify return types explicitly, unlike Python's dynamic typing, which affects how you handle error cases and return values.

      +
    14. +

    + + + +

    Which method signature and behavior best match a typical Java recursive factorial implementation?

    +
    + + +

    public static int factorial(int n) that returns 0 when n <= 0 and otherwise returns n * factorial(n - 1).

    +

    No. While this handles negative numbers, the base case is incorrect - factorial of 0 should be 1, not 0.

    +
    + +

    public void factorial(int n) that prints each partial product and stops when n reaches zero.

    +

    No. Printing results is fine for testing, but a proper factorial method should return the computed value.

    +
    + +

    public static int factorial(int n) that returns 1 when n <= 1 and otherwise returns n * factorial(n - 1).

    +

    Correct. This matches the standard recursive factorial definition in Java.

    +
    + +

    public static long factorial(int n) that returns 1 when n == 0 and otherwise returns n * factorial(n - 1).

    +

    No. While this logic is close, it doesn't handle the case when n = 1, and using long as return type when int parameter is used creates inconsistency.

    +
    +
    +
    + + +

    Why use a private helper method (e.g., sumHelper(int[] arr, int index)) behind a public method (e.g., sumArray(int[] arr)) in recursive array processing?

    +
    + + +

    Because it allows Java to automatically optimize the recursion for faster execution.

    +

    No. Java does not automatically optimize recursion just because you use a helper method.

    +
    + +

    To keep the public API simple while encapsulating extra recursion state (such as the current index) inside a private method.

    +

    Correct. This keeps the interface clean while hiding internal details from the caller.

    +
    + +

    Because public methods cannot take more than one parameter in recursive calls.

    +

    No. Public methods can take multiple parameters; this is about interface clarity, not parameter limits.

    +
    + +

    To eliminate the need for a base case by handling termination in the helper method automatically.

    +

    No. The helper method still needs an explicit base case to stop recursion.

    +
    +
    +
    + + +

    Which statement about recursion limits and errors is accurate?

    +
    + + + +

    When the call stack is exhausted, Python raises a RecursionError whereas Java throws a StackOverflowError, and neither language applies automatic tail call optimization.

    +
    + +

    Correct. This difference in exception types and the lack of built-in tail call optimization is a key distinction between the two languages.

    +
    +
    + + +

    Java automatically applies tail call optimization to recursive methods marked as final, preventing most stack overflows.

    +
    + +

    No. Java does not perform automatic tail call optimization, regardless of whether methods are marked as final.

    +
    +
    + + +

    Declaring a recursive method as static in Java reduces memory usage per call, allowing more recursive calls before a stack overflow occurs.

    +
    + +

    No. The static modifier changes method context (class vs. instance) but does not meaningfully affect per-call stack memory usage.

    +
    +
    + + +

    The JVM can detect simple recursive patterns and automatically convert them to iterative loops to prevent stack overflow.

    +
    + +

    No. The JVM does not automatically convert recursive methods to iterative ones. This optimization must be done manually by the programmer.

    +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/source/ch8_filehandling.ptx b/source/ch8_filehandling.ptx index c0f2e91..d9656b0 100644 --- a/source/ch8_filehandling.ptx +++ b/source/ch8_filehandling.ptx @@ -1,203 +1,147 @@ - + File Handling - -

    - File handling is an integral part of programming. Most programming languages have the ability to read from, write to, create, delete, move, and copy files. -

    -
    - - -
    +
    Class Imports -

    - Java has several libraries included for file handling, though, they must be imported. Java includes a class called File in the io library. The class can be imported with the following line. Be sure to capitalize File. + File handling is an integral part of programming. Most programming languages have the ability to create, read from, write to, and delete, files. In Python, most built-in libraries are available without needing to explicitly import additional packages, but some libraries like math do need to be imported. shows an example of importing the math library in Python.

    - + + - import java.io.File; + import math + print(math.sqrt(25)) # notice the lower case 'm' in math +

    - The Scanner class from the util library will need to be imported if there is any need for a program to read a file. It should be noted that this library is unnecessary if the program will not be reading any data from a file. + Delete the first line that says import math and see what happens. The import math is needed. The same program in Java would look like .

    + - import java.util.Scanner; - - + import java.lang.Math; -

    - The FileWriter class can be used to write to files. In the same way that the Scanner class isn't needed unless the program will read from a file, the FileWriter class isn't needed unless the program will write to a file. -

    - - - - import java.io.FileWriter; + public class SquareRoot { + public static void main(String[] args) { + System.out.println(Math.sqrt(25)); // notice the upper case 'M' in Math + } + } +

    - Finally, these last two classes provide error handling and must be used in tandem with the File class when reading from or writing to files. IOException handles file creation and writing errors, while FileNotFoundException handles errors when trying to read files. + Note the use of import java.lang.Math; in the above to import the Math class. Unlike Python, Java requires explicit import for most libraries, including the Math class and many classes related to file handling.

    - - - import java.io.IOException; - - - - - - import java.io.FileNotFoundException - - - -
    - -
    - Creating Files -

    - We will now create a File object. It is important to create a meaningful name for the File object. We will call ours myFile. + Much like the Math class, in order for your program to work with files you need use import. Java includes a class called File in the io library shown in . This class allows you to create File objects, and use its public methods.

    - - - File myFile = new File("myfile.txt"); - + + + import java.io.File; - - -

    - myFile is the name of the object within the program, while myfile.txt is the name of the file itself and will be the file name if the operation that creates the file is successful. -

    -
    +

    - Now that we have created a new File object, we can create a file using the createNewFile() method from the File class. While the previous line of code creates an object within the program for the file, this method actually does the work of creating a file and saving it in the current working directory. This method returns a boolean value. If the method returns true, the file was successfully created. If the method returns false, there is already a file using the chosen file name. We can use this method's possible return values in tandem with an if/else selection to determine if the file was created, or if a file with that file name already exists in the directory. + The Scanner class from the util library will need to be imported if there is any need for a program to read a file as shown in . It should be noted that this library is unnecessary if the program will not be reading any data from a file.

    + + + import java.util.Scanner; + +

    - First, lets look at the equivalent Python code: + The FileWriter class can be used to write to files as shown in . In the same way that the Scanner class isn't needed unless the program will read from a file, the FileWriter class isn't needed unless the program will write to a file.

    - - - import os - - filename = "myfile.txt" - - if not os.path.exists(filename): - with open(filename, 'x') as f: - pass - print(f"The file {filename} was created successfully.") - else: - print(f"The file {filename} already exists.") - + + + import java.io.FileWriter; +

    - Now, let's look at Java code that accomplishes the same task: + Finally, these last two classes provide error handling and must be used in tandem with the File class when reading from or writing to files as shown in . IOException handles file creation and writing errors, while FileNotFoundException handles errors when trying to read files.

    - - - import java.io.File; + + import java.io.IOException; - - public class CreateFile { - public static void main(String[] args) { - if (myFile.createNewFile()) { // If the file was created successfully - System.out.println("The file " + myFile.getName() + " was created sucessfully."); - } else { // If a file with the file name chosen already exists - System.out.println("The file " + myFile.getName() + " already exists."); - } - } - } - + import java.io.FileNotFoundException; + + +
    + +
    + Creating Files - -

    - You may have noticed the use of another method from the File class; getName(). This method returns a string containing the name of the file. -

    -

    - The code may seem complete at this point, but if you remember from the previous section, error handling using the IOException is required for program to compile. Let's utilize best practices and add in try/catch blocks to handle exceptions thrown by the IOException class. + We will now create a File object. It is important to create a meaningful name for the File object. We will call ours myFile, and we will call our class CreateFileObject. shows the code to create a File object in Java.

    - - + + - try { - if (myFile.createNewFile()) { // If the file was created successfully - System.out.println("The file " + myFile.getName() + " was created sucessfully."); - } else { // If a file with the file name chosen already exists - System.out.println("The file " + myFile.getName() + " already exists."); - } - } catch (IOException e) { - System.out.println("An error occurred."); - e.printStackTrace(); - } +import java.io.File; + +public class CreateFile { + public static void main(String[] args) { + // First, create a File object that represents "myfile.txt" + File myFile = new File("myfile.txt"); + // Next, print the file path (just the filename.) + System.out.println(myFile); + } +} +

    - The IOException e part in the parenthesis next to the catch. This creates a variable called e that refers to an IOException object. In other words, e refers to the error created if the try block fails. The line e.printStackTrace(); prints the stack trace to the console. This is what the console may output if the program tries to create a file, but is blocked by the operating system due to insufficient permissions: + myFile is the name of the object within the program, while myfile.txt is the name of the file itself and will be the file name if the operation that creates the file is successful.

    - - - An error occurred. - java.io.IOException: Permission denied - at java.base/java.io.File.createNewFile(File.java:1040) - at CreateFile.main(CreateFile.java:7) - - -

    - At this point, the program will function correctly. Let's add the try/catch blocks to the foundational code written before to get a complete program. + Now let's learn how to make a file in Java. In Python. files can be made using the open() function on a file path that doesn't exist yet. Similarly, in Java you create a file by using the createNewFile() method on a File object. This method actually does the work of creating a file and saving it in the current working directory, and returns a boolean value of either true or false if the file is successfully created. We can use this method's possible return values in tandem with an if/else selection to determine if the file was created. Finally, we encase this code within try/catch blocks. This step is required in the Java code to be compiled. If try/catch blocks using IOException are not included, there will be compilation errors.

    - First, the equivalent Python code: + shows the equivalent code to create a file in Python.

    - + - import os - - filename = "myfile.txt" - + filename = "newfile.txt" + print("Attempting to write to '" + filename + "' using 'w' mode...") try: - if not os.path.exists(filename): - with open(filename, 'x') as f: - pass # Create the file without writing anything - print(f"The file {filename} was created successfully.") - else: - print(f"The file {filename} already exists.") - except OSError as e: - print("An error occurred.") - import traceback - traceback.print_exc() + with open(filename, 'w') as f: + f.write("This file was created using 'w' mode.") + print("SUCCESS: The file '" + filename + "' was created or overwritten.") + except Exception as e: + # This would only catch other unexpected errors + print("An unexpected error occurred during write: " + str(e)) + +

    - Now, the completed Java code: + shows the equivalent code to create a file in Java.

    - + import java.io.File; @@ -205,191 +149,185 @@ public class CreateFile { public static void main(String[] args) { + File myFile = new File("newfile.txt"); try { - File myFile = new File("myfile.txt"); - if (myFile.createNewFile()) { // If the file was created successfully - System.out.println("The file " + myFile.getName() + " was created sucessfully."); - } else { // If a file with the file name chosen already exists + if (myFile.createNewFile()) { + System.out.println("The file " + myFile.getName() + " was created successfully."); + } else { System.out.println("The file " + myFile.getName() + " already exists."); } } catch (IOException e) { - System.out.println("An error occurred."); - e.printStackTrace(); + // This code runs if an IOException occurs + System.out.println("An error occurred while creating the file."); + e.printStackTrace(); // This prints the stack trace for more detailed error info } - - } - } - - - -

    - You may be wondering: "What if I don't want to create a file in the current working directory?" Good question! In Windows environments, you can specify the file path using two back slashes for each back slash in the file path. For each pair of back slashes, the first back slash acts as an escape character. So, if you want to save a file to this directory: -

    - -
    -            C:\Users\UserName\Documents
    -        
    - -

    - The line of code that creates a File object will look like this: -

    - - - - File myFile = new File("C:\\Users\\UserName\\Documents\\myfile.txt"); - - - -

    - If you are working in a Linux or Apple environment, you can simply use the file path with single forward slashes: -

    - - - - File myFile = new File("/home/UserName/Documents/myfile.txt"); - - -
    - -
    - Reading Files - -

    - Let's take a look at how we can use Java to read file contents. We'll start again with library imports and building a class, this time importing the Scanner and FileNotFoundException classes. We will call this class ReadFile: -

    - - - - import java.io.File; - import java.io.FileNotFoundException; - import java.util.Scanner - - public class ReadFile { - public static void main(String[] args) { - } } - -

    - We will then create a new File object exactly the same as the one from the section on creating files. Additionally, we will create a Scanner object. The Scanner object is the object that does the file reading. We will call this scanner fileReader: -

    - - - - File myFile = new File("myfile.txt"); - Scanner fileReader = new Scanner(myFile); - - - -

    - The next lines consists of a Python code examplethat reads each line of the file passed to the Scanner object.: -

    - - - - with open("filename.txt", "r") as file_reader: - for line in file_reader: - print(line.strip()) - - - -

    - The equivalent Java code: -

    - - - - while (fileReader.hasNextLine()) { - String data = fileReader.nextLine(); - System.out.println(data); - } - fileReader.close(); - - - -

    - The hasNextLine() method checks checks if the line below the current line has any data. This will evaluate to true even if the next line only contains blank spaces. Within the while loop, a string variable called data is used to store the current line that the Scanner object is pointing to. The nextLine() method does two things. Firstly, it returns the current line when called. Secondly, it moves the Scanner's position to the next line. In other words, for each iteration of the while loop, each line in the text is read, stored temporarily in the data variable, and printed to the console. Finally, the close() method accomplishes and holds the same importance as in the section on writing to files. -

    - -

    - Alternatively, the following code can be used to store the all lines of myfile.txt to one variable: -

    - - - - String data = ""; - while (fileReader.hasNextLine()) { - data = data + fileReader.nextLine() + System.lineSeparator(); - } - System.out.println(data); - fileReader.close(); - - +

    - Pay close attention to the details of this code. data must be declared using an empty string or it may not work correctly within the while loop. Additionally, care must be given to reassigning data in the while loop. data is concatinated (to ensure all lines are included) with fileReader.nextLine() and a new line operator. Each step of this process ensures what is stored in data matches exactly what is in myfile.txt. + You may have noticed the use of another method from the File class; getName(). This method returns a string containing the name of the file.

    + + +

    + Construct a short Java program that creates a File object for "myfile.txt" + and prints it. Drag the blocks into the correct order on the right. +

    +
    + + + + import java.io.File; + + + import java.io.Scanner; + + + + + public class CreateFile { + public static void main(String[] args) { + + + + + File myFile = new File("myfile.txt"); + + + File myFile = new File(); + + + + + System.out.println(myFile); + + + + } + } + + +
    +
    + +
    + Reading Files +

    - Using the second method of storing all file contents to one file, the resulting full code including try/catch blocks (this time using FileNotFoundException instead of IOException) will look something like this. First, the Python code: + Let’s take a look at how we can use Python to understand how read file contents in Java. In order to read files generally you iterate through each line in the file and read the line's content. In Java, you read files in a very similar way, however in Java we will use the Scanner class in order to iterate through the lines.

    - - +

    + Consider that reads each line of and prints it to the console. +

    + + Data file for reading example + +
    +                    1
    +                    2
    +                    3
    +                    4
    +                    5
    +                    6
    +                    7
    +                    8
    +                
    +
    +
    + + + filename = "myfile.txt" try: - with open("myfile.txt", "r") as file_reader: - data = "" + # Attempt to open the file in read mode ('r') + with open(filename, "r") as file_reader: + # Iterate over each line in the file for line in file_reader: - data += line # line already includes the newline character - print(data) - except FileNotFoundError as e: - print("An error occurred.") - import traceback - traceback.print_exc() - + print(line.strip()) + except: + #catches if the file doesn't exist or can't be written to + print("file could not be opened") +

    - And the Java equivalent: + functions very similarly to . The main difference here is that unlike Python, in Java we use the Scanner object to iterate through and read lines in the file. You will notice that the structure of the Java code is still similar to the Python; Both use a try and catch statement to read the file and catch any errors.

    - + + import java.io.File; - import java.io.FileNotFoundException; - import java.util.Scanner - + import java.io.FileNotFoundException; // This import is necessary to handle the exception if the file is not found + import java.util.Scanner; public class ReadFile { - public static void main(String[] args) { - try { - File myFile = new File("myfile.txt"); - Scanner fileReader = new Scanner(myFile); - String data = ""; - while (fileReader.hasNextLine()) { - data = data + fileReader.nextLine() + System.lineSeparator(); + public static void main (String[] args) { + String filename = "myfile.txt"; + try (Scanner fileReader = new Scanner(new File(filename))) { // try to open the file and create a Scanner object + while (fileReader.hasNextLine()) { // while there is a next line in the file + String data = fileReader.nextLine(); + System.out.println(data); } - System.out.println(data); - fileReader.close(); - } catch (FileNotFoundException e) { - System.out.println("An error occurred."); - e.printStackTrace(); + } + catch (FileNotFoundException e) { // and catch the exception if the file is not found + System.out.println("Error: The file '" + filename + "' was not found."); } } } - -

    - In this code, we simply print the contents of the file to the console, but it is easy to imagine how the data variable could be used in conjunction with the write class created in the previous section to create a copy of myfile.txt. -

    +
    +

    + You may have noticed that there are some new methods you haven't seen yet. The hasNextLine() method checks if there is a next line in the file, and returns false if there isn't. This method allows us to iterate over every line till there is no next line. The nextLine() method of the Scanner object returns the next line in the file as a string. +

    + + + +

    + Construct the part of a Java program that opens a file with a Scanner and + prints each line until there are no more lines. Drag the blocks into the correct order on the right. +

    +
    + + + + try (Scanner fileReader = new Scanner(new File(filename))) { + + + try (Scanner fileReader = new Scanner(filename)) { + + + + + + while (fileReader.hasNextLine()) { + + + while (fileReader.nextLine()) { + + + + + String data = fileReader.nextLine(); + System.out.println(data); + + + + } + } + + +
    -
    +
    Writing to Files

    @@ -397,70 +335,91 @@

    - Let us create the framework for a class that will write to a file. Let's call this class WriteFile: + shows the framework for a class that will write to a file. Let's call this class WriteFile.

    - - + + + import java.io.File; import java.io.FileWriter; import java.io.IOException; - + import java.util.Scanner; public class WriteFile { public static void main(String[] args) { - + } } - +

    - Next, we will create a FileWriter object. Let's call it myWriter: + Next, we will create a FileWriter object. Let's call it myWriter. shows the code to create a myWriter object in Python.

    + + + with open("myfile.txt", "w") as myWriter: + + - - +

    + shows the Java code to create a FileWriter object. Note that the FileWriter object is created with the name of the file to write to as an argument. If the file does not exist, it will be created. If it does exist, it will be overwritten.: +

    + +
    + FileWriter myWriter = new FileWriter("myfile.txt"); - +

    - In this next step, we will use the write() method from the FileWriter class. This Method will take any data within the parenthesis and write that data to the file selected. The write() method takes most standard data types: + In this next step, we will use the write() method from the FileWriter class. This method will take any data within the parenthesis and write that data to the file selected. The write() method takes most standard data types. The shows the code to write to a file in Python.

    + + + my_writer.write("File successfully updated!") + + - - +

    + shows the Java equivalent. This is almost completely identical except for the second line, which is very important! +

    + +
    + myWriter.write("File successfully updated!"); myWriter.close(); - +

    - You may have noticed the close() function being used after writing to the file. This is a very important step and must be included when working with files! Without using this method, the file may remain active in system resources even after the program is closed. This can lead file corruption or other terrible problems that are best avoided! + The close() method is being used after writing to the file. This is a very important step and must be included when working with files! Without using this method, the file may remain active in system resources even after the program is closed. This can lead file corruption or other terrible problems that are best avoided!

    - Next, we will again add the required try/catch blocks utilizing the IOException class. Just like with creating files, the program will not compile without these crucial additions! We will also add some print statements to inform us of the success of the file write operation. First, a Python example: + Next, we will again add the required try/catch blocks utilizing the IOException class. Just like with creating files, the program will not compile without these crucial additions! We will also add some print statements to inform us of the success of the file write operation. shows the code to write to a file in Python.

    - - - - with open("filename.txt", "r") as file_reader: - while True: - line = file_reader.readline() - if not line: # End of file - break - print(line.strip()) - + + + + try: + with open("myfile.txt", "w") as my_writer: + my_writer.write("File successfully updated!") + print("File successfully written to.") + except OSError as e: + print("An error occurred.") + import traceback + traceback.print_exc() +

    - And the equivalent Java code: + shows the Java equivalent.

    - - + + try { FileWriter myWriter = new FileWriter("myfile.txt"); myWriter.write("File successfully updated!"); @@ -470,31 +429,51 @@ System.out.println("An error occurred."); e.printStackTrace(); } - +

    - And that's it! We will add our code to the foundational code for a complete program. First, an example of equivalent Python code: + And that's it! We will add our code to the foundational code for a complete program. First, shows the completed Python code.

    - + + Data file for writing example + +
    +                    
    +                
    +
    +
    + + + try: with open("myfile.txt", "w") as my_writer: my_writer.write("File successfully updated!") print("File successfully written to.") - except OSError as e: + except OSError: print("An error occurred.") import traceback traceback.print_exc() +

    - The completed Java code: + shows the completed Java code.

    + + Data file for writing example + +
    +                    
    +                
    +
    +
    - + + import java.io.FileWriter; import java.io.IOException; @@ -512,12 +491,10 @@ } } } - + ~ - -

    - Files in a specific directory can be written to using the same technique as the last section in which file paths are specified, with two back slashes used in Windows environments. -

    +
    +

    @@ -526,20 +503,30 @@

    - Speaking of overwriting data, what if we want to append text to the end of any text already in myfile.txt? To accomplish this, we can pass a boolean argument along with the file name when creating a new data argument: + Speaking of overwriting data, what if we want to append text to the end of any text already in myfile.txt? To accomplish this, we can pass a boolean argument along with the file name when creating a new data argument as shown in .

    - - + + FileWriter myWriter = new FileWriter("myfile.txt", true); // true enables append mode - +

    - Now, when we use write() method like before, the text will be appended if there is already text in the document. If we were to update our code to include the boolean argument: + Now, when we use write() method like before, the text will be appended if there is already tSext in the document. If we were to update our code to include the boolean argument as shown in .

    - + + Data file for writing example + +
    +                    
    +                
    +
    +
    + + + import java.io.FileWriter; import java.io.IOException; @@ -559,78 +546,251 @@ } +

    - Then if we run the program twice, the contents of myfile.txt would be: + Then if we run the program twice, the contents of myfile.txt would be as shows.

    - - + + File successfully updated!File successfully updated! - +

    - This doesn't look very good! If we want each additional write to appear on a new line? The first solution may be to use the \n newline character: + This doesn't look very good! If we want each additional write to appear on a new line? A simple solution is to use the \n newline character as shows.

    - - + + myWriter.write("File successfully updated!\n"); // Added newline character - myWriter.close(); - - - -

    - The System.lineseseparator() method is a better solution. This method returns the system's default line separator, which is platform-dependent. For example, on Windows, it returns \n, while on Linux and macOS, it returns \n. Using this method ensures that your code works correctly across different operating systems: -

    - - - - myWriter.write("File successfully updated!" + System.lineseparator()); // Added newline character - myWriter.close(); - + myWriter.close(); +

    - Running it twice will result in the following contents in myfile.txt: + Running the code with the newline character twice will result in the following contents in myfile.txt as shows.

    - - + + File successfully updated! File successfully updated! - + +
    Deleting Files

    - Finally, we will take a look at using Java to delete files. This one is pretty straight-forward and follows the structure used to create files. This time, however, try/catch blocks are not needed for the program to compile. We will call this class DeleteFile. The completed code should look something like this. + Lastly, we will take a look at using Java to delete a file. This is pretty straight-forward and follows the structure used to create files. shows the CreateFile class from before that will be used to create a file that we will soon delete:

    - - + + - import java.io.File; - - public class DeleteFile { - public static void main(String[] args) { - File myFile = new File("myfile.txt"); - if (myFile.delete()) { - System.out.println("Deleted " + myFile.getName()); - } else { - System.out.println("File could not be deleted."); - } - } + import java.io.File; + import java.io.IOException; + + public class CreateFile { + public static void main(String[] args) { + File myFile = new File("myfile.txt"); + try { + if (myFile.createNewFile()) { + System.out.println("The file " + myFile.getName() + " was created successfully."); + } else { + System.out.println("The file " + myFile.getName() + " already exists."); + } + } catch (IOException e) { + // This code runs if an IOException occurs + System.out.println("An error occurred while creating the file."); + e.printStackTrace(); // This prints the stack trace for more detailed error info + } + } } + + + +

    + And finally, shows the Java code that deletes a file. We will call this class DeleteFile: +

    + + + + + +import java.io.File; +import java.io.IOException; +public class DeleteFile { + public static void main(String[] args) { + try { + File myFile = new File("myfile.txt"); + + // Create the file (does nothing if it already exists) + myFile.createNewFile(); + System.out.println("File created: " + myFile.getName()); + + // Delete the file + if (myFile.delete()) { + System.out.println("Deleted " + myFile.getName()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} + + + +

    - This is almost identical to the code within the try block of the CreateFile class we made earlier. The main difference is the use of the delete() method. This method will delete any file with the name provided when creating the myFile object. Similar to the createNewFile() method, it will return true if the file existed and could be deleted, and false if the file could not be deleted. + Note that this is almost identical to the code within the try block of the CreateFile class that we made earlier. The key difference is the use of the delete() method which will delete the file with the name that was linked to the myFile object. Similar to the createNewFile() method, it will return true if the file exists and can be deleted, and false if the file cannot be deleted.

    - \ No newline at end of file +
    + Summary & Reading Questions +

      +
    1. +

      To work with files in Java, you must import specific classes like java.io.File, java.io.FileWriter, and handle exceptions such as IOException.

      +
    2. +
    3. +

      You can create a new file using File.createNewFile(), which returns true if the file is created and false if it already exists.

      +
    4. +
    5. +

      Reading from files is done using a Scanner attached to a File, often with a loop using hasNextLine() and nextLine().

      +
    6. +
    7. +

      To write to a file, use a FileWriter object and call methods like write() and close() to save and finish the output.

      +
    8. +
    9. +

      You can delete a file using the delete() method on a File object, which returns true if successful.

      +
    10. +

    + + + +

    Which import is needed to create and manipulate files in Java?

    +
    + + + +

    import java.util.File;

    +
    + +

    No, File is part of the java.io package, not java.util.

    +
    +
    + + +

    import java.io.File;

    +
    + +

    Correct! File is found in the java.io package.

    +
    +
    + + +

    import java.file.Input;

    +
    + +

    No, this is not a valid import for file operations.

    +
    +
    + + +

    import java.system.io.*;

    +
    + +

    No, there is no such package in Java.

    +
    +
    +
    +
    + + +

    What does myFile.createNewFile() return if the file already exists?

    +
    + + + +

    It throws an exception.

    +
    + +

    No, it only throws an exception for access errors, not for existing files.

    +
    +
    + + +

    false

    +
    + +

    Correct! It returns false if the file already exists.

    +
    +
    + + +

    true

    +
    + +

    No, true is returned only when the file is successfully created.

    +
    +
    + + +

    null

    +
    + +

    No, null is not a valid return value for this method.

    +
    +
    +
    +
    + + +

    Which method checks if a file has more lines to read using a Scanner?

    +
    + + + +

    nextLine()

    +
    + +

    No, nextLine() retrieves the next line, but does not check for availability.

    +
    +
    + + +

    hasMore()

    +
    + +

    No, this is not a method of Scanner.

    +
    +
    + + +

    hasNextLine()

    +
    + +

    Correct! This checks if there is another line available to read.

    +
    +
    + + +

    canReadLine()

    +
    + +

    No, this is not a standard method in the Scanner class.

    +
    +
    +
    +
    +
    +
    + + diff --git a/source/ch9_commonmistakes.ptx b/source/ch9_commonmistakes.ptx index 9b6b6ed..4dca391 100644 --- a/source/ch9_commonmistakes.ptx +++ b/source/ch9_commonmistakes.ptx @@ -7,12 +7,91 @@ +
    + Mistakes Happen! +

    + Making mistakes is a very natural part of learning Java—or any other programming language. In fact, mistakes are an absolutely essential part of the learning process! So, try not to feel discouraged when you encounter errors in your code. Instead, view each mistake as an opportunity to deepen your understanding. Every programmer, no matter how experienced, encounters errors in their code. The key is to learn how to identify and correct these errors while also learning from them. +

    +

    + The good news is that most errors happen for just a few common reasons, and once you recognize the patterns, they become much easier to fix. This chapter focuses on those typical mistakes and how to understand and correct them. +

    +

    + One of the best ways to correct these errors is to slow down and test your code in small pieces. Write a few lines, compile, and check the output before moving on. If something goes wrong, read the first error message very carefully, and focus on fixing one problem at a time. Often, solving the first error helps fix others that follow. +

    +

    + A simple debugging technique is to use System.out.println() to print out variable values. If you're not sure whether a part of your code is running correctly or what a variable contains, you can print it out. This can help you to check your assumptions and narrow down where something is going wrong. +

    + +

    + Consider the following example where we have a method that multiplies a number by two. We can add print statements to help us debug the code and verify that the method is being called correctly and returning the expected result as shown below in . +

    + + + + // DebugExample.java + public class DebugExample { + + public static void main(String[] args) { + int number = 10; + int result = multiplyByTwo(number); + // Debugging: print the result to verify the method worked + System.out.println("Result after multiplying: " + result); + } + + public static int multiplyByTwo(int value) { + // Debugging: print the input value to check it's being passed correctly + System.out.println("multiplyByTwo received: " + value); + return value * 2; + } + }//End of class + + + +

    + In , System.out.println() is used inside both main and multiplyByTwo() to trace what values are being passed and returned. This kind of print-based debugging can quickly reveal logic errors, unexpected behavior, or whether a method is even being called. However, overuse of this technique will often take more time than using the debugging tools that are built into your IDE. +

    +

    + Useful tools in the built-in Java debugger can help you step through your code, inspect variables, and evaluate expressions at runtime. Familiarizing yourself with these tools can greatly enhance your debugging efficiency. +

    +

    + Above all, when you encounter an error, be patient with yourself. Every mistake you make is an opportunity to learn. +

    +
    + +
    + Forgetting a Semicolon +

    + A common mistake in Java is to forget that every statement must end with a semicolon (;). +

    + + + + // Histo.java + import java.util.Scanner; // Imports Scanner + + public class Histo { // Class declaration + + public static void main(String[] args) { // Main method declaration + Scanner data = null // The error will point here + System.out.println("This line will not compile."); + }// End of main method + }//End of class + + + +

    + The error "';' expected" on line 7 of Histo.java in means that a semicolon is missing at the end of the statement Scanner data = null. In Java, every statement must be terminated with a semicolon (;) to indicate its completion. The arrow points to null because that's where the compiler expected to find the semicolon. +

    + +
    +
    Forgetting to declare your variables

    In Python, you can use a variable without declaring it first, but in Java, you must declare all variables before using them. - If you try to use a variable that has not been declared, the Java compiler will give you an error message like this: + shows If you try to use a variable that has not been declared, the Java compiler will give you an error message like this:

    + import java.util.ArrayList; // Import necessary class @@ -32,17 +111,69 @@ } // End of class +

    The 'cannot find symbol' error for the variable count on line 6 indicates that count was used before it was declared within the Histo class. In Java, all variables must be explicitly declared with a data type (e.g., int, String, ArrayList<Integer>) before they can be assigned a value or referenced in any way. The arrow in the error message points to where the undeclared variable count was first encountered. To resolve this, count needs to be declared with its appropriate type (e.g., ArrayList<Integer> count;) before any attempt to initialize or use it.

    + + +

    + Based on , select all of the + statements that are true about declaring variables in Java. +

    +
    + + + +

    Every variable must be declared with a data type before it is used.

    +
    + +

    Correct! Java requires a variable to be declared with its type before it can be assigned or referenced.

    +
    +
    + + +

    The "cannot find symbol" error happens because count was used before being declared.

    +
    + +

    Correct! That error means the compiler reached a variable it has no declaration for.

    +
    +
    + + +

    Writing ArrayList<Integer> count; before using count would fix the "cannot find symbol" error.

    +
    + +

    Correct! Declaring count with its type resolves the error.

    +
    +
    + + +

    Java lets you use a variable without declaring it first, just like Python.

    +
    + +

    Incorrect. Unlike Python, Java requires all variables to be declared before use.

    +
    +
    + + +

    The error can be fixed by adding an import statement.

    +
    + +

    Incorrect. The import is already present; the problem is the missing variable declaration, not a missing import.

    +
    +
    +
    +
    Not importing a class

    - In Python, many classes are available by default. However, in Java, you must explicitly import most classes from external packages that you want to use. + In Python, many classes are available by default. However, in Java, you must explicitly import most classes from external packages that you want to use . If you forget to import a class, the compiler will give you an error message like this:

    + @@ -57,8 +188,9 @@ } // End of class +

    - You may notice that this error message looks similar to the previous one, however, it has an entirely different cause. In Java, classes like Scanner that are part of external packages (like java.util) must be explicitly imported into your source file. Java does not automatically recognize these classes. To resolve this error, you need to add an import statement for the Scanner class at the beginning of your Histo.java file, typically import java.util.Scanner;. + You may notice that this error message looks similar to the previous one , however, it has an entirely different cause. In Java, classes like Scanner that are part of external packages (like java.util) must be explicitly imported into your source file. Java does not automatically recognize these classes. To resolve this error, you need to add an import statement for the Scanner class at the beginning of your Histo.java file, typically import java.util.Scanner;.

    @@ -68,6 +200,7 @@

    Unlike Python, where you can create a new object without explicitly using a keyword, Java requires the new keyword to instantiate a new object.

    + // Histo.java // The filename for this example @@ -84,8 +217,9 @@ } // End of class +

    - This error message occurs when you forget to use the new keyword to instantiate an object. + The error message in occurs when you forget to use the new keyword to instantiate an object. Specifically, on line 8 of Histo.java, data = Scanner(new File("test.dat")); leads to a 'cannot find symbol' error. While the message states 'symbol: method Scanner(File)', this can be misleading. Java incorrectly interprets Scanner() as an attempt to call a static method named Scanner within the Histo class @@ -96,36 +230,13 @@

    -
    - Forgetting a Semicolon -

    - A common mistake in Java is to forget that every statement must end with a semicolon (;). -

    - - - // Histo.java - import java.util.Scanner; // Imports Scanner - - public class Histo { // Class declaration - - public static void main(String[] args) { // Main method declaration - Scanner data = null // The error will point here - System.out.println("This line will not compile."); - }// End of main method - }//End of class - - -

    - The error "';' expected" on line 7 of Histo.java means that a semicolon is missing at the end of the statement Scanner data = null. In Java, every statement must be terminated with a semicolon (;) to indicate its completion. The arrow points to null because that's where the compiler expected to find the semicolon. -

    - -
    -
    Forgetting to declare the kind of object in a container

    Java is a statically typed language, meaning you must specify the type of objects that can be stored in a container like an ArrayList. If you forget to declare the type, the compiler will give you an error.

    + + // UncheckedWarningDemo.java @@ -145,6 +256,7 @@ } // End of class +

    This is a compiler warning, not an error, indicating a potential type safety issue. It occurs because you are calling the add() method on rawList, which is an ArrayList used as a raw type (i.e., without specifying a generic type like <String> or <Integer>).

    @@ -154,4 +266,99 @@

    + +
    + Summary & Reading Questions +

      +
    1. +

      In Java, every variable must be declared with its type before use; undeclared variables cause compilation errors.

      +
    2. +
    3. +

      Java requires explicit import statements for classes from external packages (e.g., java.util.Scanner); otherwise, you get "cannot find symbol" errors.

      +
    4. +
    5. +

      The new keyword is mandatory when creating new objects; forgetting it leads to errors as Java treats the constructor call incorrectly.

      +
    6. +
    7. +

      Every Java statement must end with a semicolon (;); missing semicolons cause syntax errors.

      +
    8. +
    9. +

      Java uses generics for type safety in containers like ArrayList; forgetting to specify the contained type leads to compiler warnings about unchecked operations.

      +
    10. +
    11. +

      Compiler error messages may sometimes be misleading; understanding common mistakes helps quickly identify the root cause.

      +
    12. +

    + + + +

    What happens if you use a variable in Java without declaring it first?

    +
    + + +

    The compiler gives an error indicating the variable cannot be found.

    +

    Correct! Java requires all variables to be declared before use.

    +
    + +

    The variable is automatically declared as type Object.

    +

    No. Java does not implicitly declare variables.

    +
    + +

    The program compiles but throws an error at runtime.

    +

    No. This is a compile-time error.

    +
    + +

    Java ignores the variable and continues compiling.

    +

    No. Java will stop compiling with an error.

    +
    +
    +
    + + +

    Why must you include import statements for classes like Scanner?

    +
    + + +

    Because these classes belong to external packages and are not automatically available.

    +

    Correct! Java requires explicit imports for external classes.

    +
    + +

    Because Java does not support standard input without imports.

    +

    No. Standard input is supported but needs the Scanner class explicitly imported.

    +
    + +

    Because the classes are only available in Python, not Java.

    +

    No. This is a Java-specific requirement.

    +
    + +

    Because the compiler ignores unknown classes without imports.

    +

    No. It causes a compile error instead.

    +
    +
    +
    + + +

    What warning occurs when you use an ArrayList without specifying a type?

    +
    + + +

    An "unchecked" warning indicating potential type safety issues.

    +

    Correct! Using raw types disables generic type checks.

    +
    + +

    A syntax error.

    +

    No. This is a compiler warning, not an error.

    +
    + +

    A runtime exception.

    +

    No. It only warns about possible runtime errors.

    +
    + +

    A logical error in the program.

    +

    No. The warning points out type safety concerns.

    +
    +
    +
    +
    +
    diff --git a/source/chx_recursion.ptx b/source/chx_recursion.ptx deleted file mode 100644 index 4f3601e..0000000 --- a/source/chx_recursion.ptx +++ /dev/null @@ -1,276 +0,0 @@ - - - Recursion in Java - - - -
    - Basic Recursion -

    - In this chapter, we will explore how to translate your recursive logic from Python to Java. While the core concepts of recursion remain the same, the syntax and structure of your code will change somewhat. -

    -

    recursion - As you may know from Python, recursion is a powerful problem-solving technique involving base cases and recursive steps in which a function or method calls itself. When moving to Java, the core logic you've learned remains identical. The challenge is adapting that logic to Java's statically-typed, class-based syntax. -

    -

    - Let's take the familiar factorial function (which calculates the factorial of a number, namely the product of all positive integers from 1 to n). The logical steps in the code are the same, but the implementation details change. -

    -

    - Here is a simple Python function implementation: -

    - - -def factorial(n): - # Check for negative numbers - if n < 0: - print("Factorials are only defined on non-negative integers.") - return - # Base Case: 0! or 1! is 1 - if n <= 1: - return 1 - # Recursive Step: n * (n-1)! - return n * factorial(n - 1) - -def main(): - number = 5 - print(str(number) + "! is " + str(factorial(number))) - -main() - - - -

    - Many Python programs organize related functions into classes. The same factorial function can be placed inside a class as a method. Then you need to create an instance of the class to call the method. There we create the class MathTools with a method factorial, and we call it from the main function. -

    - - -class MathTools: - def factorial(self, n): - # Check for negative numbers - if n < 0: - print("Factorials are only defined on non-negative integers.") - return - # Base Case: 0! or 1! is 1 - if n <= 1: - return 1 - # Recursive Step: n * (n-1)! - return n * self.factorial(n - 1) - -def main(): - # Create an instance of the class and call the method - math_tools = MathTools() - number = 5 - print(str(number) + "! is " + str(math_tools.factorial(number))) - -main() - - - -

    - See if you can spot the differences in the Java version below. -

    -

    - Here is the equivalent Java code: -

    - - -public class MathTools { - public static int factorial(int n) { - // Check for negative numbers - if (n < 0) { - System.out.println("Factorials are only defined on non-negative integers."); - return -1; // Return -1 to indicate error - } - // Base Case: 0! or 1! is 1 - if (n <= 1) { - return 1; - } - // Recursive Step: n * (n-1)! - return n * factorial(n - 1); - } - - public static void main(String[] args) { - int number = 5; - System.out.println(number + "! is " + factorial(number)); - } -} - - -

    - Notice the key differences from Python: instead of def factorial(n):, Java uses public static int factorial(int n) which declares the method's visibility as public, that it belongs to the class rather than an instance (hence, static), the return type as integer, and the parameter type also as integer. The recursive logic—base case and recursive step—remains identical to Python, but all code blocks use curly braces {} instead of indentation. -

    -
    - -
    - Common Recursive Patterns - -

    - In many recursive algorithms, the recursive calls need extra information that the original caller shouldn't have to provide. For example, to recursively process an array, you need to keep track of the current position (index). To traverse a tree, you need to know the current node. This extra information clutters the public-facing method signature. -

    -

    - A common pattern to solve this is using a private helper method. This pattern lets you create a clean, simple public method that users will call, while the private helper method handles the complex details of the recursion. The public method typically makes the initial call to the private helper, providing the necessary starting values for the extra parameters. -

    -

    - Let's see this pattern in action with an example that calculates the sum of all elements in an integer array. The public sum method only takes the array, but the private sumHelper method also takes an index to track its progress through the array. -

    - -

    - You're likely familiar with how some recursive algorithms, like the naive Fibonacci implementation, - are elegant but inefficient, due to branching recursive calls filling the call stack. A common pattern to solve - this is using a private helper method. -

    -

    - The following example demonstrates this pattern. The public fib method provides a simple entry point, while the private fibHelper method performs the efficient recursion by carrying its state (the previous two numbers) in its parameters. -

    -

    - The following Java code demonstrates a similar pattern. -

    - - - - public class FibonacciExample { - public int fib(int n) { - if (n < 0) { - throw new IllegalArgumentException("Input cannot be negative."); - } - // Initial call to the recursive helper with depth 0. - return this._fibHelper(n, 0, 1, 0); - } - private int _fibHelper(int count, int a, int b, int depth) { - // Create an indent string based on the recursion depth. - String indent = " ".repeat(depth); - // Print when the method is entered (pushed onto the stack). - System.out.printf("%s[>>] ENTERING _fibHelper(count=%d, a=%d, b=%d)%n", indent, count, a, b); - // Base Case: When the count reaches 0, 'a' holds the result. - if (count == 0) { - System.out.printf("%s[<<] EXITING (Base Case) -> returns %d%n", indent, a); - return a; - } - // Recursive Step. - int result = this._fibHelper(count - 1, b, a + b, depth + 1); - // Print when the method exits (popped from the stack). - System.out.printf("%s[<<] EXITING (Recursive Step) -> passing %d%n", indent, result); - return result; - } - public static void main(String[] args) { - FibonacciExample calculator = new FibonacciExample(); - int n = 4; // Let's calculate the 4th Fibonacci number. - System.out.printf("--- Calculating fib(%d) ---%n", n); - int result = calculator.fib(n); - System.out.println("--------------------------"); - System.out.printf("The %dth Fibonacci number is: %d%n", n, result); - } - } - - -

    - This helper method approach is significantly more efficient in terms of time than the classic branching recursion (where fib(n) calls fib(n-1) and fib(n-2)). The branching model has an exponential time complexity of roughly O(2^n) because it re-calculates the same values many times. In contrast, our helper method has a linear time complexity of O(n), as it avoids re-computation by carrying the previous two results (a and b) forward into the next call. -

    -

    - However, regarding memory efficiency, the comparison is different. The maximum depth of the call stack for both the naive and the helper method is proportional to n, giving them both a space complexity of O(n). This means that while the helper method is much faster, it is equally vulnerable to a StackOverflowError for very large values of n. Because Java does not perform tail-call optimization, any recursive solution that goes too deep will exhaust the stack memory, regardless of its time efficiency. For true memory efficiency (O(1) space), an iterative loop-based solution is superior. -

    -

    - The following Python code demonstrates the same pattern, using a public method to initiate the calculation and a private helper method to perform the recursion. -

    - - - class FibonacciExample: - def fib(self, n: int) -> int: - """ - Public method to start the Fibonacci calculation. - """ - if n < 0: - raise ValueError("Input cannot be negative.") - # Initial call to the recursive helper with depth 0. - return self._fib_helper(n, 0, 1, 0) - - def _fib_helper(self, count: int, a: int, b: int, depth: int) -> int: - """ - Private helper that performs the tail recursion to find the number. - """ - # Create an indent string based on the recursion depth. - indent = " " * depth - # Print when the method is entered (pushed onto the stack). - print(f"{indent}[>>] ENTERING _fib_helper(count={count}, a={a}, b={b})") - - # Base Case: When the count reaches 0, 'a' holds the result. - if count == 0: - print(f"{indent}[<<] EXITING (Base Case) -> returns {a}") - return a - - # Recursive Step. - result = self._fib_helper(count - 1, b, a + b, depth + 1) - # Print when the method exits (popped from the stack). - print(f"{indent}[<<] EXITING (Recursive Step) -> passing {result}") - return result - - # The standard Python entry point, equivalent to Java's `main` method. - if __name__ == "__main__": - calculator = FibonacciExample() - n = 4 # Let's calculate the 4th Fibonacci number. - print(f"--- Calculating fib({n}) ---") - result = calculator.fib(n) - print("--------------------------") - print(f"The {n}th Fibonacci number is: {result}") - - -
    -
    - Recursion Limits: Python vs. Java -

    - The consequence of deep recursion, running out of stack space, is a concept you've already encountered in Python. Java handles this in a very similar way, throwing an error when the call stack depth is exceeded. -

    -

    - The key difference is the name of the error: -

    -
      -
    • In Python, this raises a RecursionError.
    • -
    • In Java, this throws a StackOverflowError.
    • -
    -

    - Neither language supports tail call optimization tail call optimization, so the practical limits on recursion depth are a factor in both. If an algorithm requires thousands of recursive calls, an iterative (loop-based) approach is the preferred solution in both Python and Java. -

    -

    - The following Python code demonstrates a situation where a function calls itself indefinitely without a base case, leading to aRecursionError. -

    - - - def cause_recursion_error(): - """ - This function calls itself without a base case, guaranteeing an error. - """ - cause_recursion_error() - - # Standard Python entry point - if __name__ == "__main__": - print("Calling the recursive function... this will end in an error!") - - # This line starts the infinite recursion. - # Python will stop it and raise a RecursionError automatically. - cause_recursion_error() - - - -

    - The following Java code demonstrates a similar situation, where a method calls itself indefinitely without a base case, leading to a StackOverflowError. -

    - - - public class Crash { - public static void causeStackOverflow() { - // This method calls itself endlessly without a stopping condition (a base case). - // Each call adds a new layer to the program's call stack. - // Eventually, the stack runs out of space, causing the error. - causeStackOverflow(); - } - // A main method is required to run the program. - public static void main(String[] args) { - System.out.println("Calling the recursive method... this will end in an error!"); - // This line starts the infinite recursion. - causeStackOverflow(); - } - } - - -
    -
    \ No newline at end of file diff --git a/source/main.ptx b/source/main.ptx index 6a3df61..6f4f823 100644 --- a/source/main.ptx +++ b/source/main.ptx @@ -3,9 +3,9 @@ - Java For Python Programmer + Java For Python Programmers - The PreTeXt Interactive Edition + Edition 2 @@ -13,7 +13,7 @@ git - +