Skip to content

Instantly share code, notes, and snippets.

@Theartbug
Last active February 20, 2019 17:10
Show Gist options
  • Save Theartbug/d7f339e0ba91154cbed937206c7d1b6d to your computer and use it in GitHub Desktop.
Save Theartbug/d7f339e0ba91154cbed937206c7d1b6d to your computer and use it in GitHub Desktop.
Java Fundamentals: The Java Language

Combined Summaries

Simple App

  • programs are executed via the java command on the command line
    • full class names including package name
  • programs are made up of statements
    • end with semicolon
    • separated by whitespace
  • comments add notes and hide statements
  • packages provide organization
    • assure uniqueness
    • most IDE's tie source code file structure to package names

variables, data types, and math operators

  • variables are strongly typed
  • primitive types
    • integer, floating point, char, boolean
  • math operators
    • basic operators, postfix / prefix operators, compound assignment operators
  • math operators follow a well-defined order of precedence
    • can affect the order of precedence using parenthesis
  • type conversions
    • compiler automatically applies widening type conversions
    • type casting explicitly performs type conversions
      • required for narrowing conversions, can be unpredictable

conditional logic, looping, arrays

  • use if-else statements to provide conditional logic
    • can be chained together
  • block statements use brackets to group statements
    • variables are block scoped
  • both while and do-while loops execute code as long as a condition is true
    • do-while will execute at least once
  • for loop provides simple notation for loop initialization control
  • for-each statement handles details of executing once for each array member
  • switch statment simplifies notation of testing against multiple matches
    • limited to the integer and char types

representing complex types with classes

  • class is timplate for creating an object
    • declared with class keyword
    • class instances (objects) are allocated with new keyword
  • classes are just reference types
    • point to a reference of where the object exists
    • with assignment between to variables, copy the reference not the object! (both will point to the same instance, unlike primitive types)
  • use access modifiers to control encapsulation
    • public, private, protected
  • methods on classes manipulate state and perform operations
    • use return keyword to exit and/or return a value
  • fields store object state
    • considered a low level detail of objects, do not want to directly expose
    • interaction normally controlled through accessors(getters) and mutators(setters)

class initializers and constructors

  • objects should be created in some useful state
  • field initializers provide an initial value as part of declaration
    • the most strict way of initializing state
  • every class has at least one constructor
    • java will automagically create one for you if you don't with no arguments
    • if you create one yourself, you must create the no arugment constructor as well
  • one constructor can chain another
    • call to the other must be the first line
  • initialization blocks share code across constructors
    • are created with brackets {} only
  • must keep order in mind
    • field > initialization blocks > constructors

closer look at parameters

  • parameters are immutable
    • changes made to a passed value are not visible outside of method
    • changes made to members of passed class instances are visible outside of methods
      • such as fields
  • a class may have multiple versions of its constructor / methods known as overloading
    • each one needs a unique signature
      • name, number of parameters, type of parameters
  • a method can be declared to accept a varying number of parameter values
    • values are received as an array (Java takes care of creating the array instance for you)
    • must be last parameter

Class Inheritance

  • Inheritance allows a new class to be defined with the characteristics of another class
    • uses the extend keyword
  • child class can override parent class methods
    • methods are automatically overrideable
    • can optinoally use @Override annotation to tell compiler that there is a parent class method you are trying to override
  • all classes derive from Object parent class
    • this means all classes have characteristics of Object
    • provides a universal reference type
  • object references are only equal when referencing the same instance, by default
    • overriding Object.equals provides the ability to create a new comparison behavior
  • use super to access parent class behaviors / characteristics / members
  • final and abstract provide control over class inheritance and method overriding
    • final indicates you cannot inherit from the class / override the method
    • abstract requires the method to be overriden / requires the class to inherit from some parent
  • constructors are not inherited
    • must provide own constructors for each class
    • can tap into parent constructors using super keyword and the signature paramater list

More About Data Types

  • String class stores immutable sequence of Unicode characters
    • can implement toString method to provide conversion of class to a string
  • StringBuilder class provides and efficient way to manipulate string values
  • Primitive wrapper class brings class capabilities to primitive values
    • called boxing
    • much less efficient, only use when capabilities are needed
  • final fields prevent a value from being changed once assigned
    • simple final fields must be set during object instance creation
    • static final fields act as named constants within the class
  • Enumeration types are useful for defining a type with finite list of values

Exceptions and Error Handling

  • Exceptions provide a non-intrusive way to handle errors
  • use try / catch / finally for structure
  • Exceptions are typed and can be caught by type
    • can have a separate catch statement for differing exception types
    • catch most specific to least specific type
      • system moves from top down, and will assign it to the first exception it can use
  • exceptions are raised to parents using throw
  • methods must declare unhandled checked exceptions using thows
  • can create custom exception types
    • normally inherit from the Exception class, which makes them a checked exception (must be handled somewhere in class chain)

Working with Packages

  • a package is a group of related types
    • package delcaration must appear in source file before any type declarations
  • packages are namespaces, and types are qualified by their package name
    • use import statements to map simple names to qualified names
  • packages serve as an access boundary
  • packages simplify distribution
    • types organized hierarchically according to package name
    • archive files store package hierarchy in a single file (jar files)
      • can have a manifest file that provide descriptive information about that file

Creating Abstract Relationshis with Interfaces

  • an interface defines a contract
    • provieds no implementation
    • can include methods and constants
  • classes implement interfaces
    • must conform to the contract defined by the interface
    • classes are able to implement multiple interfaces
  • interfaces can extend other interfaces
    • implementing an extended interface implicitly implements the base interface

Static members, nested types, anonymous classes

  • static members are shared class-wide
    • not associated with an individual instance
  • static initialization blocks provide one-time type initialization
    • at the first time that type is ever defined, never again
    • good for keeping track of something across all instances of that type
  • a nested type is a type declared within another type
    • can be used to provide structure and scoping (class is marked static or using interfaces with nesting)
    • inner classes create an association between nested and enclosing instances
      • one class inside another, not marked as static
      • whenever an instance of the inner class is created, it automatically has reference to the enclosing classes members
  • anonymous classes are declared as part of their creation
    • useful for simple interface implementations and class extensions

Static members, Nested Types, and Anonymous classes

Static Members

  • not associated with an individual instance, but instead shared class-wide
  • declared using static keyword
    • accessible using the class name
  • a static field
    • a value not associated with a specific instance
    • all instances have the same value
  • a static method
    • Performs an action not tied to a specific instance
    • Can access static fields only!
  • Example:
class Flight {
  int passengers;
  void add1Passenger() {
    if(hasSeating()) {
      allPassengers++; // stored separately in memory than instance information
      passengers++;
    } else handletooMany();
  }
  static int allPassengers;
  static int getAllPassengers() {
    return allPassengers;
  }
  static int resetAllPassengers() {
    allPassengers = 0;
  }
}
  • Example in use:
Flight.resetAllPassengers(); // accessed with uninstanciated class name, sets to 0
Flight lax045 = new Flight();
lax045.add1Passenger(); // stored separately in memory than allPassengers, sets passengers to 1 and allPassengers to 1

Flight slc015 = new Flight();
lsc015.add1Passenger(); // sets passengers to 1, but allPassengers increments to 2
  • static methods can be short-hand accessed by static import
import static com.pluralsight.travel.Flight.resetAllPassengers;
import static com.pluralsight.travel.Flight.getAllPassengers;

Static Initialization Blocks

  • perform one-time type initalization, executed before the type's first use
  • statements start with static keyword and are enclosed in brackets outside of any method or constructor
  • cannot access instance members
  • must handle all checked exceptions, cannot use throws
CrewMember p = CrewManager.FindAvailable(FlightCrewJob.Pilot);

public class CrewManager {
  private final static String FILENAME = "...";
  private static CrewMember[] pool;
  public static CrewMember FindAvailable(FlightCrewJob job) {
    for(int i=0; i < pool.length; i++) {
      if(pool[i] != null && pool[i].job == job) {
        cm = pool[i];
        pool[i] = null; // take the crew member out of the pool since they were used for a job
        break;
      }
    }
    return cm;
  }
}
  • If we want to initialize the CrewMember pool prior to any class accessing it, we can use a static initialization block
public class CrewManager {
  ...
  static {
    BufferedReader reader = null;
    try {
      reader = new BufferedReader(...);
      String line = null; // variable to read the file
      int i = 0; // index to track place in array
      pool = new CrewMember[10]; // will have 10 members
      while((line = reader.readLine()) != null) {
        String[] parts = line.split(","); // split into a string, first part is job, second part is name
        FlightCrewJob job = FlightCrewJob.valueOf(parts[0]); // since the incoming string has capital letters that will match the case and capitalization of the enumeration values, 
        // we can use the .valueOf() method on the enum (ex: Pilot is P in enum)
        pool[i] = new CrewMember(job); // add the crew member job to pool
        pool[i].setName(parts[1]); // set the name of the CrewMember
        i++;
      }
    } catch(IOException e) {
      // must handle error in static initialization blocks
    }
  }
}

Nested Types

  • a type declared within another type
  • classes can be declared within classes and interfaces
  • interfaces can be declared within classes and interfaces
  • nested types are members of the enclosing type
    • private members of the enclosing type are visible to the nested type
    • nested types support all member access modifiers
      • public, package private, protected, private
  • can serve differing purposes
    • help with structuring and scoping
      • no relationship between instances of nested and enclosing type
      • static classes nested within classes
      • all classes nested within interfaces
      • all nested interfaces
  • example:
public class Passenger implements Comparable {

 // since two values are used to represent a concept, 
 // will often wrap those values within a nested class so they are packaged together
 public static class RewardProgram {
   private int memberLevel;
   private int memberDays;
   
   public int getLevel() { return level; }
   public int getMemberDays() { return memberDays; }
   
   public void setMemberDays(int days) { this.memberDays = days; }
 }
 
 // need to instanciate the nested class
 private RewardProgram rewardProgram = new RewardProgram();
 public RewardProgram getRewardProgram() { return rewardProgram; }
}
  • useage example:
Passenger steve = new Passenger();
steve.setName("Steve");
steve.getrewardProgram().setLevel(3);
steve.getRewardProgram().setMemberDays(180); // can set nested class private fields

// since the nested class is public, can instantiate it as a reference itself!
Passenger.RewardProgram platinum = new Passenger.RewardProgram();
platinum.setLevel(3);

if(steve.getRewardProgram().getLevel() == platinum.getLevel()) // Steve is platinum

Inner Class

  • nested classes associated with an instance of the enclosing class
  • lack the static keyword
  • Example: Taking FlightIterator class and place it inside of Flight
    public class Flight implements Comparable<Flight>, Iterable<Person> {
      private CrewMember[] crew;
      private Passenger [] roster;
      public Iterator<Person> iterator() {
        return new FlightIterator(); // no longer needs to pass crew / roster
      }
      private class FlightIterator implements Iterator<Person> {
        private int index = 0;
        public boolean hasNext() {
          return index < (crew.length + roster.length); // can utilize the crew and roster variables instead of re-declaring them
        }
        public Person next() {
          Person p = (index < crew.length) ? crew[index] : roster[index - crew.length];
          index++;
          return p;
        }
      }
    }
    
  • inner classes have two this references
    • the this inside of the inner class, as well as the this of the exterior class

Anonymous Classes

  • Declared as part of their creation
  • useful for simple interface implementations or class extensions
  • are inner classes
    • associated with the containing class instance
  • create as if constructing an instance of the interface or base class
    • place opening and closing brackets after the interface / base class
    • place implementation code within brackets
  • Example: make FlightIterator class into an anonymous class
    public class Flight implements Comparable<Flight>, Iterable<Person> {
      private CrewMember[] crew;
      private Passenger [] roster;
      public Iterator<Person> iterator() {
        // declare anonymous class using interface name
        return new Iterator<Person>() { // FlightItorator is now anonymous, placed inside of the Itorator of person
          private int index = 0;
          public boolean hasNext() {
            return index < (crew.length + roster.length);
          }
          public Person next() {
            Person p = (index < crew.length) ? crew[index] : roster[index - crew.length];
            index++;
            return p;
          }
        }
      }
    }
    
  • avoid the need to declare classes that will not be reused

Creating Abstract Relationships with Interfaces

Interfaces & Implementation

  • interface defines a contract, yet provides no implementation
    • classes provide implementation, but conform to contract of interface
    • the interface does not limit other aspects of class implementation
  • Example: java.lang.Comparable - used to determine relative order
    • Method: compareTo receives item to compare
      • return indicates current instance relative sequence
      • Negative value: before
      • Positive value: after
      • Zero value: equal
  • Example: Passenger order based on member level and days
public class Passanger implements Comparable {
  private int memberLevel; // 3(highest priority), 2, 1
  private int memberDays;
  public int compareTo(Object o) { // implements a comparison, in this case for sorting
    Passenger p = (Passenger) o; // typecast to Passenger
    if(memberLevel > p.memberLevel) return -1;
    else if(memberLevel < p.memberLevel) return 1;
    else { // their level must be equal
      if(memberDays > p.memberDays) return -1;
      else if(memberDays > p.memberDays) return 1;
      else return 0; // they must be tied for level and number of days as a member
    }
  }
}

...

Passenger bob = new Passenger();
bob.setLevelAndDays(1, 180);
Passenger jane = new Passenger();
jane.setLevelAndDays(1, 90);
Passenger steve = new Passenger();
steve.setLevelAndDays(2, 180);
Passenger lisa = new Passenger();
lisa.setLevelAndDays(3, 730);
Passenger[] passengers = {bob, jane, steve, lisa};
Arrays.sort(passenger); // since Passenger implements Comparable with a compareTo method, the array can be sorted based on that method!
  • Example: order flights by time of take off
public class Flight implements Comparable {
  private int flightTime; // minutes past midnight
  
  public int compareTo(Object o) {
    Flight f = (Flight) o;
    return flightTime - f.flightTime; // if after, returns negative. If before, returns positive. If equal, returns 0
  }
}

Implementing a genertic interface

  • Some interfaces require additional type information known as generics
  • Comparable interface can accept a type, along with the compareTo method
public interface Comparable<T> {
  int compareTo(T o);
}
  • this would allow the compareTo method to accept a particular type, and then type casting within the body of the method will no longer be needed
public class Flight implements Comparable<Flight> {
  private int flightTime;
  
  public int compareTo(Flight f) { // no longer have to receive something as an Object and convert
    // Flight f = (Flight) o;  NO LONGER NEEDED
    return flightTime - f.flightTime;
  }
}
  • type passed in does not have the be the same type of the class that is implementing
    • public class Passenger implements Comparable<Flight> {}

Implementing Multiple Interfaces

  • A class can implement as many classes as it needs
public class Flight implements Comparable<Flight> {
  private int flightTime; // minutes past midnight
  private CrewMember[] crew;
  private Passenger[] roster;
  
  public int compareTo(Flightt f) {
    return flightTime - f.flightTime;
  }
}
  • create an class called Person that CrewMember and Passenger can extend
public class Person {
  private String name;
}

public class CrewMember extends Person {...}

public class Passenger extends Person implements Comparable<Passenger> {...}
  • in order to have the Flight class interact with Person and Passenger and place these into the crew and roster arrays, must implement an Iterable on Flight
public interface Iterable<T> {
  Iterator<T> iterator();
}

public interface Iterator<T> {
 boolean hasNext();
 T next;
}
  • in order to iterate over an Iterable, must create an Iterator interface
    • typically this is done with a separate class to manage iteration
public class FlightIterator implements Iterator<Person> {
  private CrewMember[] crew;
  private Passenger{} roster;
  private int index = 0;
  
  public FlightIterator(CrewMember[] crew, Passenger[] roster) {
    this.crew = crew;
    this.roster = roster;
  }
  
  boolean hasNext() {
    // if the index is less than the total number of Persons, there is more to iterate over
    return index < (crew.length + roster.length);
  }
  
  public Person next() {
    // is the index less than the total number of crew members? if so it must be a crew member and assign that person to p, otherwise it is a passenger and assign that person to p 
    Person p = (index < crew.length ? crew[index] : roster[index - crew.length];
    index++;
    return p;
  }
}

public class Flight implements Comparable<Flight>, Iterable<Person> {
  ...
  
  public Iterator<Person> iterator() {
    return new FlightIterator(crew, roster);
  }
}
  • now we can use foreach to iterate over each person on the Flight
Flight lax045 = new Flight(45);
// Add crew members:
// Pilot Patty, CoPilot Karl, Marshal Mary
// Add Passengers:
// Bob, Jane, Steve, Lisa
for(Person p:lax045) System.out.println(p.getName());

Declaring an Interface

  • declared using the interface keyword
  • do not have implementations, just defining contracts
  • has some features available to classes
    • methods
      • only a Name, parameter, and return type
      • implicitly public
    • Constants
      • typed named values
      • implicitly public, final, static (is the same value for all implementations of the interface, no per instance)
    • Extending interfaces
      • interfaces can extend each other
      • implementing an extended interface implies implementation of the base interface

Working with packages

What are packages

  • a group of related types
    • provide a namespace to avoid type name collisions
    • provide access boundary
    • act as a unit of distribution
  • source file identifies associated package, must appear before any type declarations
    • applies to all types in the file

NameSpace

  • package name is part of the type name
    • reverse domain name structure creates unique package name
    • type name is qualified by package name
    package com.pluralsight.travel;
    
    public class Flight {}
    
    //elsewhere in code
    
    com.pluralsight.travel.Flight alx175 = new Flight(); // very specific in name space
    

Determining Type's Package

  • complier needs to know each type's package
    • explicit qualifying is impractical
  • Java offers alternatives to explicitly qualify types
    • allows use of simple name in code
  • Types in current package do not need to be qualified
  • Types in java.lang package do not need to be qualified
    • Object, primitive wrapper classes, String, StringBuilder, etc.
  • Use Type imports
    • tells complier to map simple names to qualified names
  • Single type import:
    • preferred method
    • IDE will automatically add import to you
    import com.pluralsight.travel.Flight; //allows simple type use within file
    import com.xyzcompany.bar.Beer;
    ...
    
    Flight lax175 = new Flight();
    Beer lightBeer = new Beer();
    
  • Import on demand
    • provides mapping for all types in a package
    import com.pluralsight.travel.* // grabs everything within the package
    import com.xyzcompany.bar.*
    
    • may not want to use all types in case there are name collisions in different packages
    • will return an error if there is a name collision, unsafe to use

Limiting Access to Package Content

  • can serve as an access boundary, referred to as package private
  • useful for creating types and features to support functionality provided by package
    • not meant to be used stand-alone
  • can apply to a type
    • entire type is inaccessible outside of the package
  • can apply to members
    • specific methods of an accessible type are inaccessible outside of package
  • Access modifiers
    • none: only within own package (default private), usable on types and methods
    • public: everywhere, useable on types and methods
    • private: only within own class, not usable on top-level types, usable on methods
    • protected: only within own class and subclasses, not usable on top-level types, usable on methods

packages are unit of distribution

  • packages provide predictable software structure
  • class files organized in hierarchical folders reflect the package name
    • each part of package name is a separate folder
  • easy to distribute
  • use archive files, known as a jar file
    • supports package structure into a single file
    • supports compressing content
    • optionally includes a manifest that provides information regarding archive content
      • list of name value pairs
      • commonly used to define startup class
  • JDK provides a utility for creating archive files known as the jar command-line utility
  • creating archive files is a included with many other tools
  • IDEs
  • build automation systems: Gradle, Maven

Exceptions and Error handling

Exceptions

  • Try, Catch, and Finally help with exception flow
    • Finally cleans up code after Try or Catch run
try {
  // code tried
} catch(Exception e) {
  // handle
  e.getMessage() // can obtain the error message from the Exception thrown
  e.printStackTrace(); // can manually print stack trace for debugging
}

Another Example:

// C:\Numbers.txt
5
12
6
4
BufferedReader reader = null; // written outside of the blocks so all blocks have access to it
int total = 0;

try {
  reader = new BufferedReader(new FileReader("C:\\Numbers.txt")); // use double \\ to denote the desired use of \ (escape for special characters) This will open the file, must close it when done
  String line = null;
  while ((line = reader.readLine()) != null) {
    total += Integer.valueOf(line);
    System.out.println("Total: " + total);
  }
} catch(Exception e) { // do something }
finally {
  try { // must also wrap the closing of the file in case something happens when attempting to close the file
      if(reader != null) reader.close()
  } catch(Exception e) { // do something }

}

Handle Exceptions by Type

  • each exception is a class, with a base class of Object
  • Object <- Throwable <- Error / Exception (inheritance map)
    • Error class is usually a parent class from virtual machine related errors like LinkageError, etc.
    • Exception class is much more common, and is a parent of RuntimeException, IOException, etc.
      • NullPointerException inherits from RuntimeException
  • Java compiler requires the handling of checked exceptions at compile time, will throw an error if not handled
    • IOException and others that inherit directly from Exception class
  • RuntimeException and its children, and virtual machiene errors do not throw errors at compile time, and are called Unchecked exceptions
  • exceptions can be handled by type
    • Java will test each catch starting at the top
    • first assignable catch is selected, and Java will select parent classes if applicable
    • start with more specific exception types, then become more general
catch(NumberFormatException e) {} // even though it is an unchecked exception, if you know it is likely to happen, code for it
catch(FileNotFoundException e) {} // more specific than IO error
catch(IOException e) {} // least specific error handler

Exceptions and methods

  • Exceptions will bubble up the call stack, so you don't have to handle exceptions within each method, only make sure that the topmost / parent method handles errors
  • methods must be responsible for any checked exceptions that might occur
    • this can be done by catching that exception, or by using the throws clause
public void addPassengers(String filename) throws IOException {...} // indicates that we handled it furth up the method tree
  • when overriding a method that has a throws clause, the overriding method must be compatible with the throws clause of the overriden method
    • can include exceptions
    • have a throws clause that has the same exception
    • can have a derived exception (child exception of the overriden method)

Throwing Exceptions

  • use the throw keyword with the exception type
  • place as much detail as possible to help debug
    • most exception classes provde a constructor that accepts a String message or detail
    • when caused by another exception, include the original exception
    • all exception classes support initCause method that allows you to associate one exception with another
    • many exception classes provide a constructor that accepts the originating exception
  • you can create your own exception type
    • inherit directly from the Exception class
      • will become a checked Exception
    • constructors are often their only members
      • most functionality is inherited
    • you will want a constructor that accepts a required detail, and then a constructor that accepts the required detail and originating exception

Data types continued

String Class

  • Stores a sequence of unicode characters
  • enclosed in double quotes
  • can combines with + or +=
  • string objects are immutable, every time you change a string, it creates a new string object in memory
    • Manipulation can be inefficient
String name = "Jim";
name += " "; // will point to a new reference with "Jim "
  • has methods:
    • Length
    • valueOf: creates a string from a non-string
    • concat, replace, toLowerCase, toUpperCase, trim, split: creates new strings from existing
    • format
    • charAt, substring: extract substring
    • contains, endsWith, startsWith, indexOf, lastIndexOf: test substring
    • compareTo, compareToIgnoreCase, isEmpty, equals, equalsIgnoreCase: Comparison

String Equality

  • == only tests object instance, will not work for string comparison
  • .equals() compares the strings character by character
    • can become expensive, especially for long strings
  • .intern() is used to return an exact same String Object for a given string (canonicalization), so they can use == for comparison, which is quick
    • two strings of the same value, will reference the same object in memory
    • only needed when lots of string comparisons are being done, such as with search terms
    • there is some mild overhead, but not as much as .equals() in cases of heavy comparison useages

String representation of non-string

  • String.valueOf will handle most types
  • Java will also take care of conversions implicitly, usually with primitive types
int i = 2, j = 3;
int result = i * j;
System.out.println(i " * " + J " = " + result) // prints "2 * 3 = 6"
  • Object.toString() will convert an object into a string
    • can override within object to create a string that is more meaningful than the default

default:

Flight myFlight = new Flight(175);
System.out.println("My flight is" + myFlight); // "My flight is com.pluralsight.foo.Flight@74a14482"
  • returns the location of the Class, plus the name and hash
  • inferred conversion

overriden:

public class Flight {
  int flightNumber;
  char flightClass;
  
  @Override
  public String toString() { //overriding the Object.toString() method
    if(flightNumber > 0)
      return "Flight # " + flightNumber;
    else
      return "Flight class " + flightClass;
  } // returns something more meaningful than the default
}

...

Flight myFlight = new Flight(175);
System.out.println("My flight is" + myFlight); // "My flight is Flight #175"

String Builder Class

  • StringBuilder(# of characters desired) provides a mutable string buffer
    • best performance requires pre-size buffer
    • will grow automatically if needed, but has large overhead for each unintentional increase
  • most common methods are append and insert
StringBuilder sb = new StringBuilder(40); // create a buffer with space for 40 characters
Flight myFlight = new Flight(175);
String location = "Florida"

sb.append("I flew to ");
sb.append(location);
sb.append(" on ");
sp. append(myFlight); // sb: "I flew to Florida on Flight #175"

int time = 9;
int pos = sb.length() - " on ".length() - myFlight.toString().length(); // calculate the position of the "on" to insert the time prior to

sb.insert(pos, " at ");
sb. insert(pos + 4, time);

String message = sb.toString(); // must create a string from the buffer: "I flew to Florida at 9 on Flight #175"

Primitives vs Classes

  • Classes provide convenience
    • Common methods through the Object parent Class
    • Fields and Methods specific to the type
    • But classes have an overhead cost
  • Primitives provide effeciency
    • no fields or methods
    • cannot be treated as an Object
    • lightweight
  • Primitive wrapper classes allow primitive types to access Object class methods
    • will give up inefficiency
    • include: Boolean, Number, Character, Byte, Short, Integer, Long, Float, Double
    • instances are immutable
  • most common conversion scenarios between wrapper classes and primitives are handled by Java
Integer a = 100; // Java creates a reference to the Integer wrapper class called "a" and places the value 100 inside of that Integer Class
int b = a; // "b" is a primitive type, "a" is a class, Java will grab the 100 out of "a" and assign it to the primitive
  • explicit conversion
    • boxing is when you take a Primitive and convert to wrapper class with valueOf
    • unboxing is when you take a wrapper class and convert to primitive type with ___Value such as integterValue or characterValue
Integer d = Integer.valueOf(100); // converts the primitive 100 into an Integer class
int e = d.intValue(); // takes 100 out of the Integer class and asigns it to the primitive
Integer f = Integer.valueOf(e) // converts the Primitive e into an Integer class
  • Integer.valueOf() is usually unnecessary to write since Java compiler injects this for you via inferred
  • useful for converting strings to other types
  • .parse___ converts a String to primitive value like parseDouble. parseInt, etc.
  • .valueOf converts a primitive into a wrapped class
String s = "87.44";
double s1 = Double.parseDouble(s); // string to double primitive conversion
Double s2 = Double.valueOf(s); // string to Double class conversion

Using primitive wrapper Classes

  • Java will convert primitives to Object classes in cases where inference is made
    Object[] stuff = new Object[3];
    stuff[0] = new Flight();
    stiff[1] = 100; // Java will create an Integer class with a value of 100, since it is placed in an array of Objects
    
  • Classes allow for null references if they do not exist
    public class Flight {
      Integer flightNumber; //converted to class
      Character flightClass;
      
      @Override
      public String toString() {
        if(flightNumber != null) // can now check to be sure these values have been set
          return "Flight #" + flightNumber;
        else if(flightClass 1= null)
          return "Flight Class " + flightClass;
        else return "Flight identify not set";
      }
    }
    
  • wrapper classes can have members (methods), some examples are:
    • Byte, Short, Integer, Long: MIN_VALUE, MAX_VALUE, bitCount, toBinaryString
    • Float, Double: MIN_VALUE, MAX_VALUE, isInfinite, isNaN
    • Character: MIN_VALUE, MAX_VALUE, isDigit, isLetter
    • Boolean: TRUE, FALSE

Wrapper class equality

  • use .equals() to compare equality
  • Boxing conversions that always return the same wrapper class instance and will be equal with ==
    • int -128 to 128
    • short -128 to 128
    • byte -128 to 128
    • char \u0000 to \u00ff
    • boolean true, false

final fields

  • marking a field as final will prevent it from being changed once assigned (like const)
    • a simple final field is set during creation of an object instance
      • via field initializer, initialization block, or constructor
      public class Passenger {
        private final int freeBags; // once the value is set, it cannot be changed
      }
      
    • Adding the static modifier makes a final field a named constant across all instances of that class
      • convention is capital snake case
      • usually used to avoid "magic numbers"
      public class Flight {
        static final int MAX_FAA_SEATS = 550;
      }
      

enumeration types

  • useful for defining a type with finite list of valid values using the enum keyword
public enum FlightCrewJob {
  Pilot,
  CoPilot,
  FlightAttendant,
  AirMarshal
}

public class CrewMember {
  private FlightCrewJob job;
  
  public CrewMember(FlightCrewJob job) {
    this.job = job;
  }
  public void setJob(FlightCrewJob job) {
    this.job = job;
  }
}

...

CrewMember judy = new CrewMember(FlightCrewJob.CoPilot); // constructor from CrewMember sets the job to a valid value from the enum
judy.setJob(FlightCrewJob.Pilot); // can change the FlightCrewJob

Class Inheritance

basics

  • use the extends keyword to derive from another class
  • will have access to methods of parent class, and can add specialization
    • public class CargoFlight extends Flight{}
  • child class can be assigned to parent class typed references
    • only has access to methods available to the reference type (Flight, in this case)
    • why do this?
Flight f = new CargoFlight(); // creates a type reference to the parent class
Passenger jane = new Passenger(0,2); 
f.add1Passenger(jane); // can do since parent method has
f.add1package(1.0,2.5,1.5); // NOT A VALID CALL, since the reference was to Flight, not CargoFlight
  • this allows classes to be grouped by parent class
  • can do parent class type actions, without being concerened about the child class
Flight[] squadron = new Flight[5];
squadron[0] = new Flight();
squadron[1] = new CargoFlight();
... etc.
  • would then be able to loop over the array and do Flight methods to each

member hiding

  • if a child class has a field with the same name as the base class, it will only hide the parent class field for the child class methods as long as the child class is created with a type reference to the child class.
  • If the child class is created with a type reference to the parent class, the parent value field will be used instead
    • the shared child field is only visible when the instance is being worked with as a child instance, and using child methods
Flight f1 = new Flight();
f1.seats // 150

CargoFlight f2 = new CargoFlight();
f2.seats // 15

Flight f3 = new CargoFlight();
f3.seats // 150
  • if a child class attempts to use a parent method that utilizes a field that both the parent and child have by the same name, the parent method will use the parent field value on the parent
    • the parent method does not have access to the child field value
  • therefore, shared field names are bad practice

member overriding

  • if a method of the same signature (name and parameter list) exists on the child and parent class, the child overrides the parent no matter the type reference
Flight f1 = new Flight();
f1.getSeats() // 150

CargoFlight f2 = new CargoFlight();
f2.getSeats() // 15

Flight f3 = new CargoFlight();
f3.getSeats() // 15 EXPECTED VALUE
  • all methods are automatically overrideable unless you do something to say they should not be
  • you can tell Java that you intend to override a parent method by giving it the @Override annotation
public class CargoFlight extends Flight {
  @Override // Java will return an error if the parent class does not have a method by this signature, only used at compile time
  int getSeats() { return 12; }
}

Object Class

  • is the root of the Java class hierarchy
    • every class has characteristics of the Object class
  • useful for declaring variables, fields, and parameters that can reference any class or array instance
  • defines a number of methods that all objects inherit
  • all parent classes implicity extend the Object class public class Flight *extends Object* {...}

Object References

  • why would you declare a class with a type that does not allow it to acces the classes methods?
    • as a holding area
Object o = new Passenger();
o = new Flight[5];
o = new CargoFlight(); // all of these are valid objects and o can hold them, even if they cannot access their methods / characterists except the parent Object ones
~o.add1Package(..)~ // NOT VALID

if(o instanceof CargoFlight) { // prevents runtime error
  CargoFlight cf = (CargoFlight) o; // Can reassign the value of o to the properly typed reference, so the value of o can once again use methods of its class
}

Object methods

  • all objects get these
  • Clone: creates new object instance that duplicates the current instance
  • hashCode: gets a hash code for the current instance, useful for hashtables
  • getClass: return type information for current instance
  • finalize: Handle special resource cleanup scenarios, won't be used often
  • toString: returns a string of characters representing the current instance
  • equals: compare another object to current instance of equality

Equality

  • depends if you mean instance or value when it comes to class / objects
  • == checks for refernece type
  • .equals() default checks for reference type
    • can be overriden since it is the Object method
class Flight {
  private int flightNumber;
  private char flightClass;
  
  @Override
  public boolean equals (Object o) { // overrides the .equals!
    if(!(o instanceof Flight)) return false;
  
    Flight other = (Flight) o; // re-type casting so that other can have access to Flight methods
    return flightNumber == other.flightNumber && flightClass == other.flightClass;
  
  }
}
  • will have to define how the classes will be equal as each will be specific to problem-space

Special reference: Super

  • similar to this, super provides access to the current object
  • treats an object as if it is an instance of its parent class
    • can be useful to access overriden methods / features as they behaved in parent class
    • might be nice to check if one instance type reference equals another, after .equals has been overriden
  @Override
  public boolean equals (Object o) { // overrides the .equals!
    if(super.equals(o)) return true; // super accesses the parent .equals, which is the Object class
    if(!(o instanceof Flight)) return false;
  
    Flight other = (Flight) o; // re-type casting so that other can have access to Flight methods
    return flightNumber == other.flightNumber && flightClass == other.flightClass;
  
  }

Controlling inheritance and overriding

  • all classes can be extended, and derived classes have the option to override parent class methods
    • class can modify these permissions
  • final prevents further extension of that class or overriding certain methods
    • final public class Flight or public final class Flight work
    • public final void add1Package()
  • abstract requires overwriting in children
    • public abstract boolean canAccept(Flight f); methods do not have implementation on parent class, only signature. Children create implementation
    • if a single method on the class has abstract, the class must also
      • public abstract class Pilot

inheritance and Constructors

  • constructors are not inherited
  • base constructor must always be called
    • by default, base class no-argument constructor is called prior to running code within any child constructor
    • can explicitly call a base class constructor using super followed by parameter list
      • must be first line in constructor
Flight f175 = new Flight(175);
CargoFlight cf = new CargoFlight(); // works as null constructor is default
CargoFlight cf294 = new CargoFlight(294); // WILL NOT WORK, even though CargoFlight extends Flight, must explicitly call constructor in CargoFlight body

public class CargoFlight extends Flight {

   public CargoFlight(int flightNumber) { // required constructor for CargoFlight to have a flightnumber
     super(flightNumber); // can harness the parent class constructor using super
   }
   
   public CargoFlight(int flightNumber, float maxCargoSpace) {
     this(flightNumber); // harnesses the constructor above with the same signature, which in turn calls the parents constructor
     this.maxCargoSpace = maxCargoSpace;
     
   }
   
   public CargoFlight() {} // needed in order to keep the null constructor / call
}

Parameters

parameter immutability

  • when passing primitive parameters to a method, they are made via a copy of the value
  • changes made by methods to passed primitive parameters are not visible outside of the method, as they are located in different places in memory
  • when more complex arguments are passed, such as a class, the parameter is copied the reference in memory
    • any changes internally to the class is saved, since the parameter is only a reference pointer
    • why the creation of new objects is important in methods instead of mutating the original

overloading

  • a class may have multiple versions of its constructor or methods
  • each constructor and method must have a unique signature
    • made up of 3 parts: number of parameters, types of parameters, the name (does not matter for constructors since the name is the name of the class
    • allows for multiple constructors
  • Naming is more important for methods, but multiple methods can have the same name as long as other parts of their signatures do not match
  • overloaded methods can be anywhere in the class, order does not matter
public class Flight {
  public void add1Passenger() {}
  public void add1Passenger(int bags) {}
  public void add1Passenger(Passenger p) {}
  public void add1Passenger(int bags, int carryOns) {}
  public void add1Passenger(Passenger p, int carryons) {}
}
  • when there are multiple methods with similar type parameters, and the only difference is the an illegal type conversion when the class is called, java will select the method that does not have a lossy type conversion

variable number of parameters

  • a method can allow for a variable number of parameters
  • use ellipses to denote unknown amount of parameters: public void addPassenger(Passenger...list)
  • can only be used as the last parameter
  • java creates an array for you out of the listed parameters

Class initalizers and Constructors

establish initial state

  • 3 separate ways
    • field initalizers
    • constructors
    • initalizaztion blocks

field initial state and initalizers

  • object construction will establish fields with zero as default
    • byte, short, int, long: 0
    • float, double: 0.0
    • char: '\u000'
    • boolean: false
    • reference types: null
  • allow you to set a field's initial value as part of declaration
public class Earth {
  long circumferenceInMiles = 24901; // can be a simple assignment
  long circumferenceInKilometers = Math.round(circumferenceInMiles * 1.6d); // cam be an equation, since Math.round() converts the double into an int, long variable is valid
}

constructor

  • executeable code used during object creation to set initial state
  • is not a method, no return type
  • every class has at least one constructor
  • if no constructor is provided, java will create a default one for you, but it will not be seen in the code
    • if you write one constructor, you are responsible for all instances of your class dealing with that constructor
  • constructors must have different argument lists to differentiate from one another when called
    Passenger bob = new Passenger() // would no longer compile once constructor is added
    Passenger jane = new Passenger(2) // added a constructor, so values are passed into object creation
    
    • you could then fix this by adding a blank constructor like Java initially did for you
  • can have multiple constructors
  • one constructor can call another
    • calls to other constructors must be on the first line of the initial constructor
    • use this keyword with parameter: this(freeBags);
  • access modifiers can be used on constructors to control visibility
    • limits what code can preform specific creations
public class Passenger {
  public Passenger() {}
  
  public Passenger(int freeBags) { 
    this(freeBags > 1 ? 25.0d : 50.0d); // calls the private constructor
    this.freeBags = freeBags; 
    }
  public Passenger(int freeBags, int checkedBags) {
    this(freeBags);
    this.checkedBags = checkedBags;
    }
  private Passenger(double perBagFee) { this.perBagFee = perBagFee; } //prevents users from accessing the constructor directly
}

initalization blocks

  • initalization blocks are shared across all constructors, executed as if the code were placed at the start of each constructor
  • if there are multiple initalization blocks, they are executed from the top down
public class Flight {
  private int passengers, flightNumber, seats = 150;
  private char flightClass;
  private boolean[] isSeatAvailable;
  
  { //this code block will be applied to all constructors
    isSeatAvailable = new boolean[];
    for(int i = 0; i < seats: i++)
      isSeatAvailable[i] = true;
  }
  public Flight() {}
  public Flight(int flightNumber) { this.flightNumber = flightNumber; }
  public Flight(char flightClass) { this.flightClass = flightClass; }
}

Initalization and construction order

  • field initalization -> initalization bock -> constructor
  • in complex code, fields will begin to depend on one another so this order is important

Complex Types with Classes

  • Objects encapsulate data, operations, and usage semantics
    • allows storage and manipulation details to be hidden
    • separates "what" is to be done from "how" it is done
  • Classes provide a structure for creating an object
  • Classes go in their own source file, and that file will often be the name of the class
  • class fields store object state
  • classes also have methods that manipulate state and performs operations
  • classes can have a constructor method that is run when an object is first created, usually to set the initial state
class flight {
  int passengers; //field
  int seats; //field
  
  Flight() { //constructor
    seats = 150;
    passengers = 0;
  }
  
  void add1Passenger() { //method
    if(passengers < seats) passengers++;
  }
}

creating classes

  • must use the new keyword to create Flight nycToSf = new Flight();
  • just doing Flight nycToSf will create a reference in memory, but not instantiate the class until new is called
  • if a reference to an object is overwritten with a different reference, the previous object will disappear as there is no reference pointing to it

encapsulation and access modifiers

  • encapsulation hides the internal representation of an object
  • encapsulation is achieved by access modifiers
    • none: only usable within its own package (defaults to private)
    • public: usable everywhere
    • private: only accessible within own class (cannot use on other Classes), but is usable within nested classes

access modifiers

  • public classes must be inside of a file that has the same name as the class
public class flight { // can be used anywhere, has fileName: Flight.java
  private int passengers; //only used within class, cannot call Flight1.passengers
  private int seats; 
  
  public Flight() { // allows instantiation: new Flight()
    seats = 150;
    passengers = 0;
  }
  
  public void add1Passenger() { //can be called: Flight1.add1Passenger();
    if(passengers < seats) passengers++;
    else handleTooMany()
  }
  
  private void handleTooMany() { //cannot be called: Flight1.handleTooMany()
    System.out.println("Too Many")
  }
}

Naming Classes

  • same as variables, but uses PascalCase

methods

  • same conventions as variables, should be a verb / action
  • void is used when nothing is returned
    • must have a type if there is something returned
public boolean hasRoom(Flight f2) { // a instansiated class can be passed in
  int total = passengers + f2.passengers;
  return total <= seats;
}
  • brackets are required for methods, even if single lined statement

special references

  • this is implicit reference to the current object
    • allows an object to pass itself as a parameter
  • null represents an uncreated object and can be assigned to any reference variable

Accessors and Mutators

  • do not want outside of class to be able to manipulate state directly
  • use methods that are usually called getters and setters
    • getValues() and setValues(int values)

Java Condition Flow

Conditional Logic

  • == is the condition for equals, since the language is stict type unlike JS
  • {} block is not required for the first line after an if statement
if (condition)
  int answer = 7; //this is okay and is captured by the if block
  • if more statements are desired, {} become required
  • multiple variable declarations are okay single line as long as they are of the same type int v1 = 10, v2, diff;
  • all else works essentially the same

variable scope

  • variables are block scoped

logical operators

  • &, |, ^, !
  • ^ is exclusive or XOR
    • only one side can be true, both sides cannot be true unlike the regular |
  • will run both sides of operator, even if right side does not require the left to be run

conditional logical operators

  • only execute right side of code if needed to determine result
    • && only executes right side if left is true
    • || only exectues right side if left is false
  • ternary statements allow for expressions within the body of the ternary
    • int result = val2 != 0.0d ? val1 / val2 : 0.0d

looping

  • while, do-while, for-loop similar to JS

Arrays

  • stores values of a similar type
    • float[] theVals = new float[3];
  • store multiple values at once during declaration
    • float[] the Vals = {10, 2, 6, 20};
    • notation is curlybraces, unlike JS

for-each loop

  • executes statement once for each member in an array
    • for(loop-variable-declaration:array);
float[] theVals = {10.0f, 20.0f, 15.0f};
float sum = 0f;
for(float currentVal: theVals) sum += currentVal;

switch

  • works similarly to JS
  • will print out each statement after matching a single case due to "fall-through"
    • this is prevented with break statement after statements of each case

Java Introduction

intelliJ IDEA

  • creates a file structure for you. Will have a public static void main
    • This is required in classes as the method that starts the class
  • whitespace is not important in java. only ending a statement with ; is.
    • any amount of whitespace is alright, even whitespace created by enter
  • JavaDoc comments create documentation from comments, if comments are written according to the utility
    • /** */

packages

  • package comeName.example
  • provide organization
  • follow standarized naming
    • all lowercase
    • use a reserved domain name to assure global uniqueness
    • A common paradigm to ensure uniqueness is to name something by its domain backwards
      • pluralsight.com would be com.plurali\sight
    • add further qualifiers to assure uniqueness within a company / group
      • com.pluralsight.myproject;
  • members become part of the package

example:

package com.pluralsight.myproject;

public class Main {...}
  • the Main class is now part of the package and can be found at com.pluralsight.myproject.main
  • affect source code file structure
    • although java does not require a match between package names and source code file structure, most IDE's do require subfolder names to match package names
  • so in the example above, the file structure would be src -> com -> pluralsight -> example -> Main.java

variables

  • java is strongly typed, requires a type during variable declaration
  • java allows you to modify the value stored in a variable
  • java allows letters, numbers, $, and _
    • convention, only letters and numbers are used
    • rules require that the first character is not a number
  • convention of camelCase

primitive types

  • Primitive data types built into the language
    • integer, floating point, character, boolean
  • primitive types have further subtypes
    • int: byte, short, int, long
      • byte: -128 - 128 (8 in bits)
      • short: -32768 - 32767 (16 bits)
      • int: -2147483648 - 2147483648 (32 bits)
      • long: -large - large (64 bits)
        • note: long requires an L after the number: 1810000000000000L
    • floating point: can have pos, neg, zero values and stores values as a fractional portion
      • float: 1.4x10^-45 - 3.4x10^38 (32 bit)
        • note: float requires f after number: 1234.4f
      • double: 4.9x10^-324 - 3.4X10^308 (64 bit)
        • note: double can use d after number: 100000000000000000000000000000000d or just like a regular integer. Compiler will assume the later if there is no d attached.
    • character stores a single Unicode character, not a string
    • can use the actual unicode to designate the correct character \u00DA
  • primitive types are stored by-value. If you have one variable A point to a value, and then variable B point to A, that value is copied to a separate piece of memory
    • changes to the value of A after the assignment of B do not happen to B (same as JS)

Arithmetic operators

  • division operator behaves differently depending on floating point vs integer
    • float: 13.0 / 5.0 = 2.6 gives true answer
    • int: 13 / 5 = 2 rounds down to integer
  • modulus also behaves differently depending on type
    • float: 13%5 = 3.0
    • int: 13%5 = 3
  • prefix and postfix operators behave as such:
    • ++myvalue or --myvalue resolve prior to other operations
    • myvalue++ or myvalue-- resolve after other opperations
    • same as in javascript

order precedence

  • postfix, prefix, mulplicative, additive
  • operators of equal precedence are evaluated from left to right
  • order is overridden with parenthesis

type conversion

  • implicit conversions:
int iVal = 50;
long lVal = iVal;
  • compiler will convert the int to a long
  • explicit conversions:
long lVal = 50;
int iVal = (int) lVal;
  • take the lVal and count it down to a 30 bit integer
  • values that go from a smaller type to a larger type can be implicit (widening)
    • this is called type casting
    • if there are mixed types in an equation, will convert all to the largest type in equation
    • if there is a float type with integer types, will always go to float
  • explicit casting can do widening and narrowing
    • when narrowing use caution as the results are unpredictable
  • taking an integer to a float is also dangerous, as you can lose significant figures in conversion
  • an expression can be cast short result = (short) (byteVal - longVal)

Modern Java: Pluralsight

Java Platform

  • java language, runtime environment (JVM), Standard library (Java Standard Edition (SE) APIs)
  • known as the Java Development Kit (JDK)

Compiling and running Java code

  • all files end in .java
  • class declarations can start with public or private
  • require a main method, which often looks like public static void main()
  • compilied code will have a .class ending, and then can be run from the terminal
  • Java is portable to different environments due to JVM
  • automatically manages memory
  • collects garbage for you, removes unused objects in memory
  • multi-threading, unlike JavaScript
  • just-in-time compilation

Desktop Java

  • runs on single machine, interactive
  • graphical user interface (GUI)
  • Swing allows cross-platform look and feel, adheres for MVC paradigm
  • JavaFX declarative UIs: FXML, more advanced components, skinnable with CSS

Enterprise Java

  • works on top of Java SE APIs
  • These APIs can help with data persistence, web applications, security, messaging, JSON/XML handling, etc.
  • Application servers: Wildfly (Red Hat), WebSphere (IBM), WebLogic (Oracle), Tomcat (Apache)

Spring

  • At its core, a dependency injection container
  • When classes are instantiated within the dependency container, they are called Spring Beans
    • creates decoupling and is more flexible
    • testing is easier
    • can insert cross-cutting concerns
  • Integration with Java EE and data-access technologies
  • Spring has WebFlux

Utility libraries

  • Google Guava
  • Apache Commons
  • Apache Log4J

Distributed Systems Libraries

  • Netty
  • Akka
  • RxJava: Reactive programming
  • Apache Camel: Application integration

Data-access Libraries

  • Java Databe Connectivity (JDBC)
  • Hibernate, EclipseLink
  • jOOQ, QueryDSL

IDE

  • Eclipse / IntelliJ

Build Tools

  • Maven: Builds are described in XML file
  • Maven Central: a library of dependencies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment