Functional Interfaces
A functional interface is an interface with a single abstract method, and the source uses it to represent a single method.
Why a Call Needs a Specification
Imagine you want to call a subroutine that someone else wrote. Before you write the call, you have to answer a few questions. What is the subroutine called? How many values does it expect you to pass in, and what type is each one? What type of value does it send back? If any of these answers is wrong, the call cannot be made correctly. The information that answers these questions is the subroutine's specification.
A functional interface is one way to write that specification down in a Java file. It is a file that holds a specification for exactly one subroutine, and it is defined in a .java file just as a class is. This article works through two short functional interface declarations taken from a Java source. Your goal is to learn what makes an interface count as functional, how to read its declaration, and how to check a use of the subroutine against the declaration.
Two Checks for a Functional Interface
A functional interface is an interface with a single abstract method. The source uses it to represent a single method.
The definition has two parts, and you should check them separately. The first check is that the type is an interface. A declaration that begins with the word interface, rather than class, passes this check. The second check is that the interface contains exactly one abstract method. Counting the methods inside the braces is how you apply it. If there is exactly one method, the declaration passes the second check.
Reading the FunctionR2R Declaration
The first example in the source is a whole functional interface squeezed onto one line. It is saved in a file named FunctionR2R.java, which matches the name of the interface, as with any Java class. The declaration reads as follows.
- public makes the interface visible
- interface marks this as an interface, not a class
- FunctionR2R is the interface name
- double before
valueAtis the return type valueAtis the method name- double x is the single parameter
Read the declaration from left to right. The word public makes the interface visible, and the word interface tells you this is an interface rather than a class. FunctionR2R is the interface name. Inside the braces there is one line that names a subroutine, valueAt. The first word before the method name is the return type, which here is double, so the subroutine gives back a double. The items inside the parentheses are the parameters. Here there is one parameter, of type double, named x. Put together, the declaration says: there is a subroutine called valueAt, it takes one double, and it returns a double. The source describes FunctionR2R as a functional interface representing a function that takes a double and returns a double.
The parameter name x is written in the declaration, but it is not really part of the specification. What matters to a caller is how many parameters there are and what type each one has. The name is a label that helps a reader, and it does not change what a valid call looks like.
Predicting What the File Contains
Before you look at the file's contents, make a prediction. Look at the one-line declaration again and ask yourself how much of the file is about how valueAt actually computes its answer, and how much is only about the shape of the call. Commit to an answer before you read the next block.
What do you think happens?
Does the FunctionR2R file contain any computation for how valueAt calculates its result?
Reveal answer
No, the file only states the shape of the call: name, parameter, and return type
The declaration ends with a semicolon after the parameter list. It has no method body, no fields, and no implementation logic. Inside the braces there is only the single line that names the subroutine and gives its parameter and return type. A computation would appear inside the braces if it were present, and it is not there.
Your prediction is checked by reading the declaration itself. The trace attached to this lesson runs the real Java declaration so you can watch the structure as it is read. If the file did contain computation, you would expect to find it inside the braces. You do not find it there, so the file records a specification and nothing more.
ArrayProcessor and the Void Return
The source gives a second example with a different shape. It describes a subroutine that does not return anything and takes two parameters, an array of strings and an int. The source does not name the array parameter in the excerpt, so this article uses items as an illustrative name. The declaration is shown below.
- ArrayProcessor is the interface name
- void is the return type: no value comes back
- process is the method name
- String[] items is an array of strings
- int count tells the processor how many entries to work with
The two declarations share one structure even though their contents differ. Each one names a single subroutine and then states its parameters and its return type. The difference is in the types. The return type of ArrayProcessor is void, which means the process method does not hand a value back to the caller. A void return type is still a return type, and it tells the caller that no value comes back. The count parameter tells the processor how many entries to work with, which contrasts with FunctionR2R, where the single input is one double.
| Feature | FunctionR2R | ArrayProcessor |
|---|---|---|
| Method name | valueAt | process |
| Parameters | One double, named x | A String array and an int named count |
| Return type | double (gives back a value) | void (gives back nothing) |
| Source's description | A function that takes a double and returns a double | A processor that operates on an array of strings |
The two functional interfaces differ in what they accept and what they return.
The Three Facts a Specification Records
The specification records three facts about one subroutine. The first is the subroutine's name. The second is its parameters, meaning how many there are and their types. The third is its return type. Each fact has a fixed place in the declaration. In FunctionR2R, the name is valueAt, the parameter is one double, and the return type is double. In ArrayProcessor, the name is process, the parameters are a String array and an int, and the return type is void.
The word one matters here. A single functional interface is about a single subroutine. If you need to describe two different subroutines, you write two interfaces. This is what the source means when it describes the interface as a specification for a single subroutine.
- 1Find the method name: the identifier immediately before the opening parenthesis.
- 2Find the return type: the word immediately before the method name.
- 3Find the parameters: the items inside the parentheses, counted and typed one by one.
- 4Check that the declaration contains exactly one method inside the braces.
Finding Where a Call Diverges
Once you know the three facts, you can debug a broken use of a subroutine by asking where the use departs from the specification. You do not need to guess. You compare the call against the declaration line by line, starting with the name, then the parameters, then the return type.
Locating a mismatch in a call to valueAt
Some code calls valueAt with two numbers, valueAt(3.0, 4.0), instead of one. Where does the call stop matching the specification?
- 1Read the specification
FunctionR2R declares
valueAtwith one double parameter and a double return type. - 2Check the name
The call uses
valueAt, which matches the declared method name. The name is not the problem. - 3Check the parameter count
The call passes two arguments, but the specification says there is one double parameter. The mismatch is here.
- 4Check the return type
The return type cannot be judged from this call alone, but the parameter count already shows the call is wrong.
The call diverges at the parameter list. The specification expects one double, and the call supplies two.
The before-and-after pair shows the fix. The first call passes two numbers, so it diverges from the one-double parameter list. The corrected call passes a single double, which matches the declaration. The return type is unchanged by this fix because the declaration already says the method returns a double.
Mistakes When Reading Signatures
Common mistake Treating the parameter name as part of the contract
What it looks likeBelieving that a call must use the name x in order to match the declaration.
Why it failsThe parameter name is written in the declaration, but the caller is judged by the number and types of parameters.
Do this insteadCompare parameter counts and types when checking a use.
Common mistake Reading the return type as the method name
What it looks likeThinking that double in public interface FunctionR2R { double valueAt(double x); } is the name of the method.
Why it failsThe word before the method name is the return type. The method name is the identifier that comes directly before the parentheses.
Do this insteadLocate the name by finding the identifier right before the opening parenthesis.
Common mistake Assuming void means the method is missing a return type
What it looks likeThinking the ArrayProcessor declaration is incomplete because it has no value after the word void.
Why it failsA void return type is still a return type. It tells the caller that no value comes back.
Do this insteadRead void as the declared answer: the subroutine returns nothing.
Common mistake Expecting computation inside a functional interface file
What it looks likeLooking in the FunctionR2R braces for the arithmetic that valueAt performs.
Why it failsA functional interface records a specification. The declaration has one method with no body, so it does not show how the work is done.
Do this insteadExpect the file to contain only the shape of the subroutine: name, parameters, and return type.
Checking Your Reading
Read the declaration public interface ArrayProcessor { void process(String[] items, int count); } and answer three questions. What is the method name? How many parameters does it take, and what are their types? What is the return type, and what does it tell the caller?
Hints
- The method name is the identifier directly before the opening parenthesis.
- Count the items inside the parentheses, separated by commas.
- The word immediately before the method name is the return type, and void means no value comes back.
A caller writes a call to process with only one argument, process(names). Using the ArrayProcessor declaration, state at which step the call diverges from the specification and explain why.
Hints
- Compare the number of arguments in the call with the number of parameters in the declaration.
- Ask whether the name and return type are also affected.
Key Takeaways
- A functional interface is an interface with a single abstract method, and it is a Java file that holds a specification for exactly one subroutine.
- Read a declaration from left to right: the word before the method name is the return type, the identifier before the parentheses is the method name, and the items inside the parentheses are the parameters.
- The specification records three facts about one subroutine: its name, its parameters (how many and their types), and its return type. The parameter name is not part of the specification.
- FunctionR2R takes one double and returns a double, while ArrayProcessor takes a String array and an int and returns void.
- A call that goes wrong can be located by comparing it against the specification fact by fact, starting with the parameter list.