Rational: ex14

Java Lambdas

On website: https://ucsb-cs56-pconrad.github.io/tutorials/rational_ex01/

Part of a series of tutorial articles about a Rational class.

Code examples referred to on this page can be found here: https://github.com/UCSB-CS56-pconrad/cs56-rational-ex14

Lambdas: An admittedly contrived example

My purpose here is to introduce lambdas in order to prepare us for

Having said that, the example shown here is admittedly a bit contrived.

Imaginary Dialog with the Ideal Student about this Contrived Example

Our contrived purpose

What we want is:

What would we use that for?

Suppose we wanted to make tables of rational numbers like this one. Here, the column headings are the numerators, and the row headings are the denominators.

  1 2 3 4
1 1 2 3 4
2 1/2 1 3/2 2
3 1/3 2/3 1 4/3

So we might add a method to the Rational class with this signature to produce such a table:

  public static String tableOfRationalsMarkdown(int rows, int cols)

You can imagine that this method might have a couple of nested for loops, and go through and for each of the entries, do something like this. (This is just a portion of the code; the part that generates everything except the first two lines.)

  for (int denom=1; denom<=rows; denom++) {                                  
    result += "|" + denom;                                                 
    for (int num=1; num<=cols; num++) {                                    
      Rational r = new Rational(num,denom);                              
      result += "|" + r.toString();                                                                     
    }                                                                      
    result += "|" + System.lineSeparator();
  }
  return result;

But, what if we also wanted a table of decimal approximations to these Rational numbers, like this?

  1 2 3 4
1 1.000 2.000 3.000 4.000
2 0.500 1.000 1.500 2.000
3 0.333 0.667 1.000 1.333

Or HTML notation to give fractions, which when formatted, produces this:

  1 2 3 4 5
1 1 2 3 4 5
2 12 1 32 2 52
3 13 23 1 43 53
4 14 12 34 1 54

And in raw Markdown plus HTML looks like this:

| |1|2|3|4|5|
|-|-|-|-|-|-|
|1|1|2|3|4|5|
|2|<sup>1</sup>&frasl;<sub>2</sub>|1|<sup>3</sup>&frasl;<sub>2</sub>|2|<sup>5</sup>&frasl;<sub>2</sub>|
|3|<sup>1</sup>&frasl;<sub>3</sub>|<sup>2</sup>&frasl;<sub>3</sub>|1|<sup>4</sup>&frasl;<sub>3</sub>|<sup>5</sup>&frasl;<sub>3</sub>|
|4|<sup>1</sup>&frasl;<sub>4</sub>|<sup>1</sup>&frasl;<sub>2</sub>|<sup>3</sup>&frasl;<sub>4</sub>|1|<sup>5</sup>&frasl;<sub>4</sub>|

Or LaTeX notation that, when formatted, produces this:

latex notation

latex notation

In raw UTF-8 (ASCII) LaTeX code (text), that looks like this:

| |1|2|3|4|
|-|-|-|-|-|
|1|1|2|3|4|
|2|$$\frac{1}{2}$$|1|$$\frac{3}{2}$$|2|
|3|$$\frac{1}{3}$$|$$\frac{2}{3}$$|1|$$\frac{4}{3}$$|

Each time we want a different format, we could go back into the Rational class each time, and copy/paste all of that for loop code, just to change the one line that produces the formatted string.

But that would be unpleasant, and wasteful. What we want instead, is a way to “plug in” a custom way of printing the Rational.

So, imagine that in addition the method we defined before, we also define this one:

The second version of the method takes an additional parameter of type Rational2String. This is an object that implements the Rational2String interface, and allows us to “customize” the way that the Rational object is printed. And it allows us to do that without having to change the code for the Rational class!

Then, what if we could define that new class inline?

There are at least four ways of defining a new class for that plugin:

  1. Separate class in a separate file
  2. Separate inner class (with a name) that we explicitly instantiate
  3. Inline anonymous inner class
  4. Lambda expression

Let’s show what each of those looks like.

Separate class in a separate file

We could define a class that implements the Rational2String interface in separate file. For example, see the file BasicRational2String.java.

Here’s what that file looks like:

package edu.ucsb.cs56.pconrad.rational;
public class BasicRational2String implements Rational2String {
    /**                                                                                            
        Return a string representation of a Rational number                                        
     */
    @Override
    public String r2s(Rational r) {
        return r.toString();
    }
}

Here is an example of using that:

        BasicRational2String br2s = new BasicRational2String();
        String actual = Rational.markdownTable(3,4,br2s);

Separate named inner class that we explicitly instantiate

The named inner class might look like this. This code would appear INSIDE another class where MyPlugin is being used.

  public class MyPlugin implements Rational2String {
        public String r2s(Rational r) { return r.toString(); }
    }

to use it, you’d write:

        String actual = Rational.markdownTable(3,4,new MyPlugin());

Note that in the above line of code, the instance of the class MyPlugin is anonymous, but the class itself has a name.

Inline anonymous inner class

   Rational2String r2s = new Rational2String() {
                public String r2s(Rational r) { return r.toString(); }
            };
   String actual = Rational.markdownTable(3,4,r2s);

We could also write it like this:

  String actual =
            Rational.markdownTable(3, 4 ,new Rational2String() {
                    public String r2s(Rational r) { return r.toString(); }
                });

Lambda expression

We compress the entire anonymous instance of the anonymous inner class down to its essentials:

(r) is the parameter to the r2s method (function). -> says: we are mapping that Rational r to its return value r.toString() is the return value for the r2s method (function).

 String actual = Rational.markdownTable(3, 4 , (r)->r.toString() );