Chapter 12 Java Fundamentals Flashcards

1
Q

Applying the final Modifier

A
  • Marking a variable final means the value cannot be changed after it is assigned.
  • Marking a method or class final means it cannot be overridden or extended
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

DECLARING FINAL LOCAL VARIABLES

A
  • don’t need to assign a value when a final variable is declared.
  • The rule is only that it must be assigned a value before it can be used.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Just because a variable reference is marked final does not mean the object associated with it cannot be modified.

A

Consider the following code snippet:

final StringBuilder cobra = new StringBuilder();
cobra.append("Hssssss");
cobra.append("Hssssss!!!");

In the cobra example, the object reference is constant, but that doesn’t mean the data in the class is constant.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

ADDING FINAL TO INSTANCE AND STATIC VARIABLES

A
  • Instance and static class variables can also be marked final.
  • If an instance variable is marked final, then it must be assigned a value when it is declared or when the object is instantiated.
  • it cannot be assigned a value more than once

instance final variables
- declared
- instance initializers
- cosntructors

static final variables
- declared
- instance initializers

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

WRITING FINAL METHODS

A
  • Methods marked final cannot be overridden by a subclass.
  • This essentially prevents any polymorphic behavior on the method call
  • ensures that a specific version of the method is always called.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

MARKING CLASSES FINAL

A

final modifier can be applied to class declarations as well.
A final class is one that cannot be extended.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

implicit modifier

A

a modifier that is inserted automatically by the compiler is referred to as an implicit modifier

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Working with Enums

A
  • a type that can only have a finite set of values, such as days of the week, seasons of the year, primary colors, etc.
  • An enumeration is like a fixed set of constants.
  • In Java, an enum, short for “enumerated type,”
  • can be a top-level type like a class or interface,
  • as well as a nested type like an inner class.
  • enum provides type-safe checking
  • Cannot extend and enum
  • an enum is a type of class that mainly contains static members. It also includes some helper methods like name()
  • An enum provides a values() method to get an array of all of the values.
  • retrieving an enum value from a String using the valueOf() method.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

CREATING SIMPLE ENUMS
~~~
public enum Season {
WINTER, SPRING, SUMMER, FALL
}
~~~

A
  • To create an enum, use the enum keyword.
  • Then list all of the valid types for that enum.
  • semi-colon (;) is optional for this example (optional when our enum is composed solely of a list of values, it is required if there is anything in the enum besides the values.)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Enum values are considered constants and are commonly written using snake case, often stylized as snake_case.

A

snake_case

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q
Season s = Season.SUMMER;
System.out.println(Season.SUMMER); // SUMMER
System.out.println(s == Season.SUMMER); // true
A
  • enums print the name of the enum when toString() is called.
  • can use equals() or == to compare enums, since each enum value is initialized only once in the Java Virtual Machine (JVM).
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q
for(Season season: Season.values()) {
    System.out.println(season.name() + " " + season.ordinal());
}
A
  • An enum provides a values() method to get an array of all of the values.
  • name() return string, value name
  • ordinal() return int, the order of value declared

The output shows that each enum value has a corresponding int value, and the values are listed in the order in which they are declared.

WINTER 0
SPRING 1
SUMMER 2
FALL 3
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q
if ( Season.SUMMER == 2) {} // DOES NOT COMPILE
A

You can’t compare an int and enum value directly anyway since an enum is a type, like a Java class, and not a primitive int.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q
Season s = Season.valueOf("SUMMER"); // SUMMER
A

retrieving an enum value from a String using the valueOf() method.

Season t = Season.valueOf("summer"); // Throws an exception at runtime

There is no enum value with the lowercase name summer. Java throws an IllegalArgumentException.

Exception in thread "main" java.lang.IllegalArgumentException:
No enum constant enums.Season.summer
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q
public enum ExtendedSeason extends Season { } // DOES NOT COMPILE
A

One thing that you can’t do is extend an enum.

The values in an enum are all that are allowed.

You cannot add more by extending the enum.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

USING ENUMS IN SWITCH STATEMENTS

A

Pay attention to the case values in this code:

Season summer = Season.SUMMER;
switch (summer) {
    case WINTER:
        System.out.println("Get out the sled!");
        break;
    case SUMMER:
        System.out.println("Time for the pool!");
        break;
    default:
        System.out.println("Is it summer yet?");
}
switch (summer) {
    case Season.FALL: // DOES NOT COMPILE
        System.out.println("Rake some leaves!");
        break;
    case 0: // DOES NOT COMPILE
        System.out.println("Get out the sled!");
        break;
}
  • The first case statement does not compile because Season is used in the case value.
  • the second case statement does not compile becuase can’t compare enums with int values,
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

ADDING CONSTRUCTORS, FIELDS, AND METHODS

A
1: public enum Season {
2:     WINTER("Low"), SPRING("Medium"), SUMMER("High"), FALL("Medium");
3:     private final String expectedVisitors;
4:     private Season(String expectedVisitors) {
5:         this.expectedVisitors = expectedVisitors;
6:     }
7:     public void printExpectedVisitors() {
8:         System.out.println(expectedVisitors);
9:     } }
  • On line 2, the list of enum values ends with a semicolon ( ;). While this is optional when our enum is composed solely of a list of values, it is required if there is anything in the enum besides the values.
  • We mark the instance variable final on line 3 so that our enum values are considered immutable.
  • Although this is certainly not required, it is considered a good coding practice to do so.
  • Since enum values are shared by all processes in the JVM, it would be problematic if one of them could change the value inside an enum.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

How do we call an enum method?

A
Season.SUMMER.printExpectedVisitors();
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q
public enum OnlyOne {
    ONCE(true);
    private OnlyOne(boolean b) {
        System.out.print("constructing,");
    }
}
public class PrintTheOne {
    public static void main(String[] args) {
        System.out.print("begin,");
        OnlyOne firstCall = OnlyOne.ONCE; // prints constructing,
        OnlyOne secondCall = OnlyOne.ONCE; // doesn't print anything
        System.out.print("end");
    }
}
A

The first time that we ask for any of the enum values, Java constructs all of the enum values. After that, Java just returns the already constructed enum values.

This class prints the following:

begin,constructing,end

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

CREATING IMMUTABLE OBJECTS

A

The immutable objects pattern is an object-oriented design pattern
in which an object cannot be modified after it is created.

Instead of modifying an immutable object,
you create a new object that contains any properties from the original object you want copied over.

Immutable objects are invaluable in concurrent applications
since the state of the object cannot change or be corrupted by a rogue thread.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

enum abstract method

A
  • The enum itself has an abstract method.
  • This means that each and every enum value is required to implement this method.
  • If we forget to implement the method for one of the values, then we get a compiler error.
public enum Season {
    WINTER {
        public String getHours() { return "10am-3pm"; }
    },
    SPRING {
        public String getHours() { return "9am-5pm"; }
    },
    SUMMER {
        public String getHours() { return "9am-7pm"; }
    },
    FALL {
        public String getHours() { return "9am-5pm"; }
    };
    public abstract String getHours();
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

default implementation and override

A

If we don’t want each and every enum value to have a method, we can create a default implementation and override it only for the special cases.

public enum Season {
    WINTER {
        public String getHours() { return "10am-3pm"; } //override
    },
    SUMMER {
        public String getHours() { return "9am-7pm"; } //override
    },
    SPRING, FALL;
    public String getHours() { return "9am-5pm"; } //default implemenation
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

> [!NOTE]
You might have noticed that in each of these enum examples, the list of values came first.
This was not an accident. Whether the enum is simple or contains a ton of methods, constructors, and variables, the compiler requires that the list of values always be declared first.

A

the compiler requires that the list of values always be declared first.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Creating Nested Classes

A

A nested class is a class that is defined within another class. A nested class can come in one of four flavors.
* Inner class: A non-static type defined at the member level of a class
* Static nested class: A static type defined at the member level of a class
* Local class: A class defined within a method body
* Anonymous class: A special case of a local class that does not have a name

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

> [!NOTE]
By convention and throughout this chapter, we often use the term inner or nested class to apply to other Java types, including interfaces and enums.
Although you are unlikely to encounter this on the exam, interfaces and enums can be declared as both inner classes and static nested classes, but not as local or anonymous classes.

A

interfaces and enums can be declared as both inner classes and static nested classes, but not as local or anonymous classes.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q

DECLARING AN INNER CLASS

A

An inner class, also called a member inner class, is a non-static type defined at the member level of a class (the same level as the methods, instance variables, and constructors). Inner classes have the following properties:

  • Can be declared public, protected, package‐private (default), or private
  • Can extend any class and implement interfaces
  • Can be marked abstract or final
  • Cannot declare static fields or methods, except for static final fields
  • Can access members of the outer class including private members

The last property is actually pretty cool. It means that the inner class can access variables in the outer class without doing anything special.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q
1: public class Outer {
2:     private String greeting = "Hi";
3:
4:     protected class Inner {
5:         public int repeat = 3;
6:         public void go() {
7:             for (int i = 0; i < repeat; i++)
8:                 System.out.println(greeting);
9:        }
10:    }
11:
12:     public void callInner() {
13:         Inner inner = new Inner();
14:         inner.go();
15:     }
16:     public static void main(String[] args) {
17:         Outer outer = new Outer();
18:         outer.callInner();
19: } }
A
20: public static void main(String[] args) {
21:     Outer outer = new Outer();
22:     Inner inner = outer.new Inner(); // create the inner class
23:     inner.go();
24: }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q

Inner classes can have the same variable names as outer classes

1: public class A {
2:     private int x = 10;
3:     class B {
4:         private int x = 20;
5:         class C {
6:             private int x = 30;
7:             public void allTheX() {
8:                 System.out.println(x); // 30
9:                 System.out.println(this.x); // 30
10:               System.out.println(B.this.x); // 20
11:               System.out.println(A.this.x); // 10
12: } } }
13:     public static void main(String[] args) {
14:         A a = new A();
15:         A.B b = a.new B();
16:         A.B.C c = b.new C();
17:         c.allTheX();
18: }}
A
  • Line 15 uses the awkward syntax to instantiate a B. Notice the type is A.B. We could have written B as the type because that is available at the member level of B. Java knows where to look for it.
  • On line 16, we instantiate a C. This time, the A.B.C type is necessary to specify. C is too deep for Java to know where to look.
  • Then line 17 calls a method on c.
  • Lines 8 and 9 are the type of code that we are used to seeing. They refer to the instance variable on the current class–the one declared on line 6 to be precise.
  • Line 10 uses this in a special way. We still want an instance variable. But this time we want the one on the B class, which is the variable on line 4.
  • Line 11 does the same thing for class A, getting the variable from line 2.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q

.CLASS FILES FOR INNER CLASSES

A

test

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q

INNER CLASSES REQUIRE AN INSTANCE

public class Fox {
    private class Den {}
    public void goHome() {
        new Den(); // COMPILE
    }
    public static void visitFriend() {
        new Den(); // DOES NOT COMPILE
    }
}
public class Squirrel {
    public void visitFox() {
        new Den(); // DOES NOT COMPILE
    }
}
A
  • The first constructor call compiles because goHome() is an instance method, and therefore the call is associated with the this instance.
  • The second call does not compile because it is called inside a static method. You can still call the constructor, but you have to explicitly give it a reference to a Fox instance.
  • The last constructor call does not compile for two reasons. Even though it is an instance method, it is not an instance method inside the Fox class. Adding a Fox reference would not fix the problem entirely, though. Den is private and not accessible in the Squirrel class.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q

WRITING A LOCAL CLASS

1: public class PrintNumbers {
2:     private int length = 5;
3:     public void calculate() {
4:         final int width = 20;
5:         class MyLocalClass {
6:             public void multiply() {
7:                 System.out.print(length * width);
8:             }
9:         }
10:        MyLocalClass local = new MyLocalClass();
11:         local.multiply();
12:     }
13:     public static void main(String[] args) {
14:         PrintNumbers outer = new PrintNumbers();
15:         outer.calculate();
16:     }
17: }
A
  • A local class is a nested class defined within a method.
  • Like local variables, a local class declaration does not exist until the method is invoked, and it goes out of scope when the method returns.
  • This means you can create instances only from within the method. Those instances can still be returned from the method. This is just how local variables work.

Local classes have the following properties:

  • They do not have an access modifier.
  • They cannot be declared static and cannot declare static fields or methods, except for static final fields.
  • They have access to all fields and methods of the enclosing class (when defined in an instance method).
  • They can access local variables if the variables are final or effectively final.
32
Q
public void processData() {
    final int length = 5;
    int width = 10;
    int height = 2;
    class VolumeCalculator {
        public int multiply() {
            return length * width * height; // DOES NOT COMPILE
        }
    }
    width = 2;
}
A

The length and height variables are final and effectively final, respectively, so neither causes a compilation issue. On the other hand, the width variable is reassigned during the method so it cannot be effectively final. For this reason, the local class declaration does not compile.

33
Q

> [!NOTE]
Local classes are not limited to being declared only inside methods. They can be declared inside constructors and initializers too. For simplicity, we limit our discussion to methods in this chapter.

A
34
Q

> [!NOTE]
effectively final refers to a local variable whose value does not change after it is set. A simple test for effectively final is to add the final modifier to the local variable declaration. If it still compiles, then the local variable is effectively final.

A

effectively final

35
Q

DEFINING AN ANONYMOUS CLASS

1: public class ZooGiftShop {
2:     abstract class SaleTodayOnly {
3:         abstract int dollarsOff();
4:     }
5:     public int admission(int basePrice) {
6:         SaleTodayOnly sale = new SaleTodayOnly() {
7:             int dollarsOff() { return 3; }
8:         }; // Don't forget the semicolon!
9:         return basePrice - sale.dollarsOff();
10: } }
1: public class ZooGiftShop {
2:     interface SaleTodayOnly {
3:         int dollarsOff();
4:     }
5:     public int admission(int basePrice) {
6:         SaleTodayOnly sale = new SaleTodayOnly() {
7:             public int dollarsOff() { return 3; }
8:         };
9:         return basePrice - sale.dollarsOff();
10: } }
A
  • An anonymous class is a specialized form of a local class that does not have a name.
  • It is declared and instantiated all in one statement using the new keyword, a type name with parentheses, and a set of braces {}.
  • Anonymous classes are required to extend an existing class or implement an existing interface.
  • They are useful when you have a short implementation that will not be used anywhere else.
36
Q
1: public class ZooGiftShop {
2:     interface SaleTodayOnly {
3:         int dollarsOff();
4:     }
5:     public int pay() {
6:        return admission(5, new SaleTodayOnly() {
7:             public int dollarsOff() { return 3; }
8:         });
9:     }
10: public int admission(int basePrice, SaleTodayOnly sale) {
11: return basePrice - sale.dollarsOff();
12: }}
A
  • Lines 6 through 8 are the anonymous class. We don’t even store it in a local variable. Instead, we pass it directly to the method that needs it. Reading this style of code does take some getting used to. But it is a concise way to create a class that you will use only once.
37
Q
public class Gorilla {
    interface Climb {}
    Climb climbing = new Climb() {};
}
A

You can even define anonymous classes outside a method body. The following may look like we are instantiating an interface as an instance variable, but the {} after the interface name indicates that this is an anonymous inner class implementing the interface.

38
Q

ANONYMOUS CLASSES AND LAMBDA EXPRESSIONS

A

Prior to Java 8, anonymous classes were frequently used for asynchronous tasks and event handlers.

Button redButton = new Button();
redButton.setOnAction(new EventHandler<ActionEvent>() {
    public void handle(ActionEvent e) {
    System.out.println("Red button pressed!");
}
});

Since Java 8, though, lambda expressions are a much more concise way of expressing the same thing.

Button redButton = new Button();
redButton.setOnAction(e -> System.out.println("Red button pressed!"));
39
Q

REVIEWING NESTED CLASSES

A

test

40
Q

Understanding Interface Members

A

Interface member types

  1. Constant variable, implicit modifier: public, static, final
  2. Abstract method, implicait modifier: public, abstract
  3. Default method, implicit modifier: public ,required modifier: default
  4. Static method, implicit modifier: public, required modifier: static
  5. Private method, required modifier: private
  6. Private static method, required modifier: private, static
41
Q

IMPORTING A STATIC NESTED CLASS

// Toucan.java
package bird;
public class Toucan {
    public static class Beak {}
}
// BirdWatcher.java
package watcher;
import bird.Toucan.Beak; // regular import ok
public class BirdWatcher {
    Beak beak;
}
A

Since it is static, you can also use a static import.

import static bird.Toucan.Beak;

Remember, Java treats the enclosing class as if it were a namespace.

42
Q

CREATING A STATIC NESTED CLASS

1: public class Enclosing {
2:     static class Nested {
3:         private int price = 6;
4:     }
5:     public static void main(String[] args) {
6:         Nested nested = new Nested();
7:         System.out.println(nested.price);
8: } }
A
  • A static nested class is a static type defined at the member level.
  • Unlike an inner class, a static nested class can be instantiated without an instance of the enclosing class.
  • The trade-off, though, is it can’t access instance variables or methods in the outer class directly. It can be done but requires an explicit reference to an outer class variable.

In other words, it is like a top‐level class except for the following:

  • The nesting creates a namespace because the enclosing class name must be used to refer to it.
  • It can be made private or use one of the other access modifiers to encapsulate it.
  • The enclosing class can refer to the fields and methods of the static nested class.
43
Q

RELYING ON A DEFAULT INTERFACE METHOD

A

The name default comes from the concept that it is viewed as an abstract interface method with a default implementation.

44
Q

PURPOSE OF DEFAULT METHODS

A
  • One motivation for adding default methods to the Java language was for backward compatibility. A default method allows you to add a new method to an existing interface, without the need to modify older code that implements the interface.
  • Another motivation for adding default methods to Java is for convenience.
public interface IsWarmBlooded {
    boolean hasScales();
    default double getTemperature() {
        return 10.0;
    }
}
45
Q

DEFAULT INTERFACE METHOD DEFINITION RULES

A
  1. A default method may be declared only within an interface.
  2. A default method must be marked with the default keyword and include a method body.
  3. A default method is assumed to be public.
  4. A default method cannot be marked abstract, final, or static.
  5. A default method may be overridden by a class that implements the interface.
  6. If a class inherits two or more default methods with the same method signature, then the class must override the method.

These rules also apply to methods with the same signature but different return types or declared exceptions. If a default method is overridden in the concrete class, then it must use a declaration that is compatible, following the rules for overriding methods introduced in Chapter 8, “Class Design”.

46
Q

Inheriting Duplicate default Methods

what value would the following code output?

public interface Walk {
    public default int getSpeed() { return 5; }
}

public interface Run {
    public default int getSpeed() { return 10; }
}

public class Cat implements Walk, Run { // DOES NOT COMPILE
    public static void main(String[] args) {
        System.out.println(new Cat().getSpeed());
    }
}
A

If the class implementing the interfaces overrides the duplicate default method, then the code will compile without issue.

By overriding the conflicting method, the ambiguity about which version of the method to call has been removed.

public class Cat implements Walk, Run {
    public int getSpeed() { return 1; }
    public static void main(String[] args) {
        System.out.println(new Cat().getSpeed());
    }
}
47
Q

Calling a Hidden default Method

public class Cat implements Walk, Run {
    public int getSpeed() { return 1; }
    public int getWalkSpeed() {
        return \_\_\_\_\_\_\_\_\_\_\_; // TODO: Call Walk's version of getSpeed()
    }
    public static void main(String[] args) {
        System.out.println(new Cat().getWalkSpeed());
    }
}
A
public class Cat implements Walk, Run {
    public int getSpeed() {
        return 1;
    }
    public int getWalkSpeed() {
        return Walk.super.getSpeed();
    }
    public static void main(String[] args) {
        System.out.println(new Cat().getWalkSpeed());
    }
}
  • first use the interface name,
  • followed by the super keyword,
  • followed by the default method we want to call.
  • We also put the call to the inherited default method inside the instance method getWalkSpeed(), as super is not accessible in the main() method.
48
Q

USING STATIC INTERFACE METHODS

A

Static Interface Method Definition Rules

  1. A static method must be marked with the static keyword and include a method body.
  2. A static method without an access modifier is assumed to be public.
  3. A static method cannot be marked abstract or final.
  4. A static method is not inherited and cannot be accessed in a class implementing the interface without a reference to the interface name.
public interface Hop {
    static int getJumpHeight() {
        return 8;
    }
}
public class Bunny implements Hop {
    public void printDetails() {
        System.out.println(getJumpHeight()); // DOES NOT COMPILE
    }
}

the problem can be easily fixed by using the interface name and calling the public static method.

public class Bunny implements Hop {
    public void printDetails() {
        System.out.println(Hop.getJumpHeight());
    }
}
49
Q

INTRODUCING PRIVATE INTERFACE METHODS

A

private interface methods can be used to reduce code duplication.

public interface Schedule {
    default void wakeUp() { checkTime(7); }
    default void haveBreakfast() { checkTime(9); }
    default void haveLunch() { checkTime(12); }
    default void workOut() { checkTime(18); }
    private void checkTime(int hour) {
        if (hour> 17) {
            System.out.println("You're late!");
        } else {
            System.out.println("You have "+(17-hour)+" hours left " + "to make the appointment");
        }
    }
}

Private Interface Method Definition Rules

  1. A private interface method must be marked with the private modifier and include a method body.
  2. A private interface method may be called only by default and private (non-static) methods within the interface definition.
  • Private interface methods behave a lot like instance methods within a class.
  • Like private methods in a class, they cannot be declared abstract since they are not inherited.
50
Q

INTRODUCING PRIVATE STATIC INTERFACE METHODS

A
  • the purpose of private static interface methods is to reduce code duplication in static methods within the interface declaration.
  • Furthermore, because instance methods can access static methods within a class, they can also be accessed by default and private methods.
public interface Swim {
    private static void breathe(String type) {
        System.out.println("Inhale");
        System.out.println("Performing stroke: " + type);
        System.out.println("Exhale");
    }

    static void butterfly() { breathe("butterfly"); }
    public static void freestyle() { breathe("freestyle"); }
    default void backstroke() { breathe("backstroke"); }
    private void breaststroke() { breathe("breaststroke"); }
}

Private Static Interface Method Definition Rules

  1. A private static method must be marked with the private and static modifiers and include a method body.
  2. A private static interface method may be called only by other methods within the interface definition.
51
Q

WHY MARK INTERFACE METHODS PRIVATE?

A

The answer is to improve encapsulation, as we might not want these methods exposed outside the interface declaration. Encapsulation and security work best when the outside caller knows as little as possible about the internal implementation of a class or an interface. Using private interface methods doesn’t just provide a way to reduce code duplication, but also a way to hide some of the underlying implementation details from users of the interface.

52
Q

REVIEWING INTERFACE MEMBERS

A

Interface member access

53
Q

ABSTRACT CLASSES VS. INTERFACES

A

test

54
Q

Introducing Functional Programming

A
  • Functional interfaces are used as the basis for lambda expressions in functional programming.
  • A functional interface is an interface that contains a single abstract method.
  • single abstract method (SAM) rule.
  • A lambda expression is a block of code that gets passed around, sort of like an anonymous class that defines one method.
55
Q

DEFINING A FUNCTIONAL INTERFACE

A
@FunctionalInterface
public interface Sprint {
    public void sprint(int speed);
}
public class Tiger implements Sprint {
    public void sprint(int speed) {
        System.out.println("Animal is sprinting fast! " + speed);
    }
}

adding the @FunctionalInterface annotation to a functional interface is optional.

56
Q

which of the following are functional interfaces?

@FunctionalInterface
public interface Sprint {
    public void sprint(int speed);
}

public interface Dash extends Sprint {}

public interface Skip extends Sprint {
    void skip();
}

public interface Sleep {
    private void snore() {}
    default int getZzz() { return 1; }
}

public interface Climb {
    void reach();
    default void fall() {}
    static int getBackUp() { return 100; }
    private static boolean checkHeight() { return true; }
}
A

All four of these are valid interfaces, but not all of them are functional interfaces.

  • The Dash interface is a functional interface because it extends the Sprint interface and inherits the single abstract method sprint().
  • The Skip interface is not a valid functional interface because it has two abstract methods: the inherited sprint() method and the declared skip() method.
  • The Sleep interface is also not a valid functional interface. Neither snore() nor getZzz() meet the criteria of a single abstract method. Even though default methods function like abstract methods, in that they can be overridden in a class implementing the interface, they are insufficient for satisfying the single abstract method requirement.
  • Finally, the Climb interface is a functional interface. Despite defining a slew
    of methods, it contains only one abstract method: reach().
57
Q

DECLARING A FUNCTIONAL INTERFACE WITH OBJECT METHODS

A

all classes inherit certain methods from Object. For the exam, you should be familiar with the
following Object method declarations:

  • String toString()
  • boolean equals(Object)
  • int hashCode()

If a functional interface includes an abstract method with the same signature as a public method found in Object, then those methods do not count toward the single abstract method test. The motivation behind this rule is that any class that implements the interface will inherit from Object, as all classes do, and therefore always implement these methods.

58
Q

Is the Soar class a functional interface?

public interface Soar {
abstract String toString();
}
A

It is not.
Since toString() is a public method implemented in Object, it does not count toward the single abstract method test.

59
Q

functional interface?

public interface Dive {
    String toString();
    public boolean equals(Object o);
    public abstract int hashCode();
    public void dive();
}
A

Yes.
The dive() method is the single abstract method, while the others are not counted since they are public methods defined in the Object class.

60
Q

Do you see why the following is not a valid functional interface?

public interface Hibernate {
    String toString();
    public boolean equals(Hibernate o);
    public abstract int hashCode();
    public void rest();
}
A

NO.
Because this does not match the method signature of the equals(Object) method defined in the Object class, this interface is counted as containing two abstract methods:
equals(Hibernate) and rest().

61
Q

OVERRIDING TOSTRING() EQUALS(OBJECT) AND HASHCODE()

A

While knowing how to properly override toString(), equals(Object), and hashCode() was part of Java certification exams prior to Java 11, this requirement was removed on all of the Java 11 exams. As a professional Java developer, it is important for you to know at least the basic rules for overriding each of these methods.

  • toString(): The toString() method is called when you try to print an object or concatenate the object with a String. It is commonly overridden with a version that prints a unique description of the instance using its instance fields.
  • equals(Object): The equals(Object) method is used to compare objects, with the default implementation just using the == operator. You should override the equals(Object) method anytime you want to conveniently compare elements for equality, especially if this requires checking numerous fields.
  • hashCode(): Any time you override equals(Object), you must override hashCode() to be consistent. This means that for any two objects, if a.equals(b) is true, then a.hashCode()==b.hashCode() must also be true. If they are not consistent, then this could lead to invalid data and side effects in hash‐based collections such as HashMap and HashSet.
62
Q

IMPLEMENTING FUNCTIONAL INTERFACES WITH LAMBDAS

A
public interface Predicate<T> {
boolean test(T t);
}

The relationship between functional interfaces and lambda expressions is as follows: any functional interface can be implemented as a lambda expression.

1: import java.util.*;
2: import java.util.function.Predicate;
3: public class TraditionalSearch {
4:     public static void main(String[] args) {
5:
6: // list of animals
7:     var animals = new ArrayList<Animal>();
8:     animals.add(new Animal("fish", false, true));
9:     animals.add(new Animal("kangaroo", true, true));
10:     animals.add(new Animal("rabbit", true, false));
11:     animals.add(new Animal("turtle", false, true));
12:
13: // Pass lambda that does check
14:     print(animals, a -> a.canHop());
15: }
16:     private static void print(List<Animal> animals, 
17:  Predicate<Animal> checker) {
18:         for (Animal animal : animals) {
19:             if (checker.test(animal))
20:                 System.out.print(animal + " ");
21:        }
22:     }
23: }
63
Q

> [!NOTE]
Lambda expressions rely on the notion of deferred execution.
Deferred execution means that code is specified now but runs later. In this case, later is when the print() method calls it. Even though the execution is deferred, the compiler will still validate that the code syntax is correct.

A
64
Q

WRITING LAMBDA EXPRESSIONS

A

Lambda syntax omitting optional parts

a -> a.canHop()
  • A single parameter specified with the name a
  • The arrow operator to separate the parameter and body
  • A body that calls a single method and returns the result of that method

Lambda syntax, including optional parts
~~~
(Animal a) -> {return a.canHop;}
~~~

  • A single parameter specified with the name a and stating the type is Animal
  • The arrow operator to separate the parameter and body
  • A body that has one or more lines of code, including a semicolon and a return statement

Optional parts:

  • The parentheses can be omitted only if there is a single parameter and its type is not explicitly stated.
  • It shouldn’t be news to you that we can omit braces when we have only a single statement.
  • What is different here is that the rules change when you omit the braces. Java doesn’t require you to type return or use a semicolon when no braces are used.
  • This special shortcut doesn’t work when we have two or more statements. At least this is consistent with using {} to create blocks of code elsewhere.
65
Q

> [!NOTE]
As a fun fact, s ‐> {} is a valid lambda. If the return type of the functional interface method is void, then you don’t need the semicolon or return statement.

A
66
Q

valid lambda expressions

() -> new Duck()
d -> {return d.quack();}
(Duck d) -> d.quack()
(Animal a, Duck d) -> d.quack()
A
67
Q

Do you see what’s wrong with each of these?

3: a, b -> a.startsWith("test") // DOES NOT COMPILE
4: Duck d -> d.canQuack(); // DOES NOT COMPILE
5: a -> { a.startsWith("test"); } // DOES NOT COMPILE
6: a -> { return a.startsWith("test") } // DOES NOT COMPILE
7: (Swan s, t) -> s.compareTo(t) != 0 // DOES NOT COMPILE
A
  • Lines 3 and 4 require parentheses around each parameter list. Remember that the parentheses are optional only when there is one parameter and it doesn’t have a type declared.
  • Line 5 is missing the return keyword, which is required since we said the lambda must return a boolean.
  • Line 6 is missing the semicolon inside of the braces, {}.
  • Finally, line 7 is missing the parameter type for t. If the parameter type is specified for one of the parameters, then it must be specified for all of them.
68
Q

WORKING WITH LAMBDA VARIABLES

A

Variables can appear in three places with respect to lambdas:
1. the parameter list,
2. local variables declared inside the lambda body,
3. and variables referenced from the lambda body.

69
Q

Parameter List

A
  • type of parameters is optional.
  • var can be used in a lambda parameter list.
Predicate<String> p = x -> true;
Predicate<String> p = (var x) -> true;
Predicate<String> p = (String x) -> true;
70
Q

Can you figure out the type of x?

public void whatAmI() {
    test((var x) -> x>2, 123);
}
public void test(Predicate<Integer> c, int num) {
    c.test(num);
}
A

Integer

71
Q

What do you think the type of x is here?

public void counts(List<Integer> list) {
    list.sort((var x, var y) -> x.compareTo(y));
}
A

Integer

72
Q

Restrictions on Using var in the Parameter List

which of the following lambda expressions do not compile if they were assigned to a variable?

3: (var num) -> 1
4: var w -> 99
5: (var a, var b) -> "Hello"
6: (var a, Integer b) -> true
7: (String x, var y, Integer z) -> true
8: (var b, var k, var m) -> 3.14159
9: (var x, y) -> "goodbye"
A

If var is used for one of the types in the parameter list, then it must be used for all parameters in the list.

  • Line 3 compiles and is similar to our previous examples.
  • Line 4 does not compile because parentheses, (), are required when using the parameter name.
  • Lines 5 and 8 compile because all of the parameters in the list use var.
  • Lines 6 and 7 do not compile, though, because the parameter types include a mix of var and type names.
  • Finally, line 9 does not compile because the parameter type is missing for the second parameter, y. Even when using var for all the parameter types, each parameter type must be written out.
73
Q

Local Variables Inside the Lambda Body

A
(a, b) -> { int c = 0; return 5;}
74
Q

Do you see what’s wrong here?

(a, b) -> { int a = 0; return 5;} // DOES NOT COMPILE
A

We tried to redeclare a, which is not allowed. Java doesn’t let you create a local variable with the same name as one already declared in that scope.

75
Q

How many syntax errors do you see in this method?

11: public void variables(int a) {
12: int b = 1;
13: Predicate<Integer> p1 = a -> {
14: int b = 0;
15: int c = 0;
16: return b == c;}
17: }
A
  • There are actually three syntax errors.
  • The first is on line 13. The variable a was already used in this scope as a method parameter, so it cannot be reused.
  • The next syntax error comes on line 14 where the code attempts to redeclare local variable b.
  • The third syntax error is quite subtle and on line 16. The variable p1 is missing a semicolon at the end. There is a semicolon before the }, but that is inside the block. While you don’t normally have to look for missing semicolons, lambdas are tricky in this space, so beware!
76
Q

Variables Referenced from the Lambda Body

A

Lambda bodies are allowed to use static variables, instance variables, and local variables if they are final or effectively final.

Lambdas follow the same rules for access as local and anonymous classes! This is not
a coincidence, as behind the scenes, anonymous classes are used for lambda expressions.

4: public class Crow {
5:     private String color;
6:     public void caw(String name) {
7:         String volume = "loudly";
8:         Predicate<String> p = s -> (name+volume+color).length()==10;
9:     }
10: }

if the local variable is not final or effectively final, then the code does not compile.

4: public class Crow {
5:     private String color;
6:     public void caw(String name) {
7:         String volume = "loudly";
8:         color = "allowed";
9:         name = "not allowed";
10:       volume = "not allowed";
11:         Predicate<String> p =
12: s -> (name+volume+color).length()==9; // DOES NOT COMPILE
13:     }
14: }