44

How do I write a lambda expression if it doesn't require arguments and hence its name is excessive?

This way doesn't compile:

setRowFactory(-> new TableRowCustom());

But this one does:

setRowFactory(__ -> new TableRowCustom());

Is there a better way?

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
Dims
  • 47,675
  • 117
  • 331
  • 600
  • 2
    What is the functional interface type (and method) expected by `setRowFactory`'s parameter? – Sotirios Delimanolis Jun 02 '16 at 16:54
  • 3
    you can also use a method reference with just TableRowCustom::new which is a replacement for the lambda – george Jun 02 '16 at 17:56
  • 2
    @george, you can't use a method reference to reference a method that does not take the same number of parameters as the target functional type (here 0 vs 1, apparently). – Didier L Jun 03 '16 at 08:58
  • @Didier L based on the Dims example he's got a default constructor and a supplier lambda interface so in his example what I've suggested will 100% work. You refer to cases when the constructor has parameters etc. but that's a different story than the question above. – george Jun 03 '16 at 09:05
  • 1
    @george His constructor has no parameters, and the expected interface obviously takes one (as he says that it compiles with `__`), so it cannot be a simple `Supplier`. In fact I think it is likely a JavaFX `Callback` by googling the method name, cf [TableView#setRowFactory(Callback)](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TableView.html#setRowFactory-javafx.util.Callback-). – Didier L Jun 03 '16 at 09:14
  • it doesn't really matter whether there are params or not, as long as the lambda interface finds a relevant constructor which satisfies the target type it will still work flawlessly with TableRowCustom::new at compile time. Based on your example with Callable it will look like Callable newOp = TableRowCustom::new; – george Jun 03 '16 at 09:34
  • 1
    @george the method reference will look for a constructor with 1 parameter, of a super type of TableView, so it won't work – Didier L Jun 03 '16 at 10:00
  • @Didier L the OP can always define a method called say createNewTB which accepts some parameter and returns a new TableRowCustom with no parameters. Then he only have to call TableRowCustom::createNewTB for the lambda – george Jun 03 '16 at 11:15
  • 2
    @george: just using constructor references without thinking about unintended functional parameters can lead to scenarios like in [“Horrendous performance & large heap footprint of Java 8 constructor reference”](http://stackoverflow.com/q/35296734/2711488) – Holger Jun 07 '16 at 14:30

2 Answers2

52

Since you've mentioned that this works

setRowFactory(__ -> new TableRowCustom());

I assume that the expected functional interface method must accept a single argument. The identifier _ is a reserved keyword since Java 8.

I would just use a throwaway single (valid identifier) character.

setRowFactory(i -> new TableRowCustom());
setRowFactory($ -> new TableRowCustom()); 

Although, you should probably avoid the use of the $, the Java Language Specification states

The dollar sign should be used only in mechanically generated source code or, rarely, to access pre-existing names on legacy systems. The underscore may be used in identifiers formed of two or more characters, but it cannot be used as a one-character identifier due to being a keyword.

You can also write out

setRowFactory(ignored -> new TableRowCustom());

to be explicit.

The Java Language Specification defines the syntax of a lambda expression

LambdaExpression:
  LambdaParameters -> LambdaBody 

and

LambdaParameters:
  Identifier
  ( [FormalParameterList] )
  ( InferredFormalParameterList )
InferredFormalParameterList:
  Identifier {, Identifier}

In other words, you cannot omit an identifier.


As Holger suggests, if and when they decide to use _ as an unused parameter name, it will be easy to change from __ to _ in your source code. You may want to just stick with that for now.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 9
    I wouldn’t object using `__` for an unnecessary parameter as apparently the single `_` is reserved because it is intended to become the throwaway identifier for unused parameters in the future. When this happened, changing `__ -> expression` to `_ -> expression` wouldn’t be a big deal. – Holger Jun 02 '16 at 17:08
  • 3
    Unfortunately __ doesn't work in the same way python placeholders work, because `(__,__,whatIcareAbout)` causes `java: variable __ is already defined in method` Error. ignored1, ignored2 may be preferable – gerardw Mar 29 '18 at 19:07
  • 3
    Use `(__,___,whatIcareAbout)` then... Not optimal for now, but it's clearly showing the purpose. – Michaela Elschner Aug 14 '19 at 16:51
  • Why "avoid this" for using dollar sign ? i know it is a special identifier meant for generated code, but is there some special case it represents or reasons why it should be avoided other than simple nomenclature ? – niken Apr 07 '21 at 15:58
  • @niken No that's pretty much it, I've added a note from the JLS to clarify the comment. – Sotirios Delimanolis Apr 07 '21 at 19:12
1

As of Java 21 (coming September 2023), you can do:

setRowFactory(_ -> new TableRowCustom());

_ is the so-called "unnamed variable" (preview feature). From JEP 443:

Enhance the Java language with unnamed patterns, which match a record component without stating the component's name or type, and unnamed variables, which can be initialized but not used. Both are denoted by an underscore character, _. This is a preview language feature.

[…]

An unnamed variable is declared when either the local variable in a local variable declaration statement, or an exception parameter in a catch clause, or a lambda parameter in a lambda expression is denoted by an underscore. It allows the identifier which follows the type or var in the statement or expression to be elided; e.g.,

  • int _ = q.remove();
  • ... } catch (NumberFormatException _) { ...
  • (int x, int _) -> x + x

In the case of single-parameter lambda expressions, such as _ -> "NODATA", the unnamed variable should not be confused with the unnamed pattern.

The terminology indeed is a bit confusing, but Nicolai Parlog comes to rescue:

Unnamed variables work as:

  • local variable
  • try-with-resource
  • for loop variable
  • exception parameter
  • lambda parameter

They work with var.

Unnamed pattern variables:

  • work as pattern variables
  • require explicit type

Unnamed patterns:

  • replace pattern with _
  • bind nothing
  • match everything
  • only in nested patterns
beatngu13
  • 7,201
  • 6
  • 37
  • 66