10

I know about the Oracle Java naming conventions and I've read similar SO questions (like Java constant variable, naming convention) but what naming should I use for constant functions?

E.g. if I have the functional interface

public interface StringDecider {
  public boolean decide(String str);
}

and now I'm using it to define a constant function. Should the naming be 'upper snake case', like

public final static StringDecider STRING_NOT_EMPTY = (str) -> (str!=null && !str.isEmpty());
STRING_NOT_EMPTY.decide("Example");

or camel case

public final static StringDecider stringNotEmpty = (str) -> (str!=null && !str.isEmpty());
stringNotEmpty.decide("Example");
Community
  • 1
  • 1
Kris
  • 4,595
  • 7
  • 32
  • 50
  • 3
    @sotirios-delimanolis I disagree that this duplicates the linked question. OP knows that historically static final variables are capitalised. They are asking whether to make an exception for functions. I think it "feels" right to do so. Was looking for precedent, when the question was closed. – slim Nov 07 '16 at 17:19
  • I agree it feels weird to write `STRING_NOT_EMPTY.decide("Example");`. But maybe I just have to get used to it. – Kris Nov 07 '16 at 17:24
  • 2
    I suggest you change your question to use the Java 8 function types. i.e. `final static Predicate STRING_NOT_EMPTY` versus `final static Predicate stringNotEmpty`. This underlines that it's a question inspired by Java 8's addition of lambdas. – slim Nov 07 '16 at 17:28
  • 1
    Anyhow, short version of the answer that I would have posted: your IDE will probably advise you to use SNAKE_CASE_CAPS like any other `static final` variable. I failed to find any examples in the JDK source. I found some examples in Guava that use SNAKE_CASE_CAPS. I myself feel that a local convention in which you do different would be OK, because `myStream.map(MY_FUNCTION)` feels ugly. I feel static final functions should be sort-of peers to methods, and capitalised accordingly. But that's just me. – slim Nov 07 '16 at 17:43
  • 3
    Of course, it feels weird to write `STRING_NOT_EMPTY.decide("Example")`, but that’s because it makes no sense to create a function object via lambda expression, just to call directly a method on it. The natural way is to write a *method* `static boolean isNotEmpty(String str) { … }` and call `isNotEmpty("Example")`. Then, *if* you need a function object, e.g. of type `StringDecider` just use `ContainingType::isNotEmpty`. No sane programmer would call `String.CASE_INSENSITIVE_ORDER .compare(s1, s2)`; the natural way is using an ordinary method, i.e. `s1.compareToIgnoreCase(s2)`… – Holger Nov 07 '16 at 17:58
  • I'm confused. Why should this be different from any other constant? – shmosel Nov 08 '16 at 02:33
  • Why not just write `public static boolean isNotEmpty(String s)`? – xiaofeng.li Nov 08 '16 at 05:04
  • @LukeLee because you can do some things with functions that you can't do with methods... although you could get at your `isNotEmpty` with the `::` syntax. – slim Nov 08 '16 at 09:33
  • @shmosel: Because constants are usually integers or strings, maybe a logger class - but this here is a constant function. Functions as variables are possible since Java 8. – Kris Nov 08 '16 at 09:35
  • @Kris A constant can be any immutable value. I don't see why the type matters. – shmosel Nov 08 '16 at 09:36
  • @shmosel I see your logic. It just looks unusual to have something like `FUNCTION.apply();` don't you think? And since there is some discussion going on for others it seems to be confusing too. – Kris Nov 08 '16 at 09:40
  • @slim the whole point is that functions and methods are essentially interchangeable, any functional interface constant you could write can also be analogously rewritten as a method. (For the sake of the question, I'm of the camp of capitalizing a constant function expression). I personally like it for simple math one-liners, like formulas. Outside of that I would use a method – Rogue Nov 08 '16 at 10:16
  • 2
    I don't think `ALL_CAPS_THING.method(foo);` feels weird to write at all. Not if you've used `enum`s in earnest. Or pre-compiled regex patterns. – biziclop Nov 08 '16 at 10:19
  • @Kris: Functions as variables are **not** “possible since Java 8”. You are just declaring a field of type `StringDecider`. The entire code, except for the lambda expression, works even in Java 1. That’s why I brought up the [`String.CASE_INSENSITIVE_ORDER`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#CASE_INSENSITIVE_ORDER) example, a constant of the `Comparator` type, which is a functional interface, that exists since Java 1.2. Whether you implement the `Comparator` via lambda expression or explicit class is irrelevant to the constant field `CASE_INSENSITIVE_ORDER`. – Holger Nov 08 '16 at 13:58
  • It somehow reminds be of [`Collections#EMPTY_LIST`](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#EMPTY_LIST) which is exposed via [`Collections#emptyList`](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#emptyList--). I would probably use a similar pattern here. (And beyond that: Offering an `isNotEmpty` method is certainly reasonable, **regardless** of whether it is "wrapped" in a `StringDecider` instance or not!) – Marco13 Dec 26 '16 at 17:46

3 Answers3

4

In Java, there is no such thing as a "constant function": A lambda constructs an object which has a single method, and, like all other objects, it can be assigned to a reference — including a final reference. At the level of your reference StringDecider STRING_NOT_EMPTY, there is no distinction between an object which has been created using a lambda and one created through any other means. Therefore, the term "constant" doesn't have a different meaning depending on what constructs were used to define and construct the constant object.

In fact, beyond their definition in code, there is no discernible difference between a lambda function object and e.g. an anonymous class object:

public final static StringDecider STRING_NOT_EMPTY_LAMBDA = str -> (str != null && !str.isEmpty());

public final static StringDecider STRING_NOT_EMPTY_ANON = new StringDecider() {

    @Override
    public boolean decide(final String str) {
        return str != null && !str.isEmpty();
    }

};

For all intents and purposes, STRING_NOT_EMPTY_LAMBDA and STRING_NOT_EMPTY_ANON have an equivalent function — they were simply defined using different syntax, which may or may not be implemented differently.

Conclusion

At the level of referencing, there is no distinction of whether an object was defined using a lambda or not. Therefore, for constants created using a lambda, you probably should use the same conventions you use for constants created in other ways for consistency's sake:

public final static int ANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42;

public final static StringDecider STRING_NOT_EMPTY = str -> (str != null && !str.isEmpty());

If, for whatever reason, you and/or your team want to discern between the two, feel free to do so... but make sure to stay consistent.


In fact, lambdas and anonymous classes need not be implemented in the same way. However, their usage is identical once they are created (there are few differences such as in variable scope, but, once the object is created and assigned to StringDecider STRING_NOT_EMPTY, these differences are no longer relevant).

Community
  • 1
  • 1
errantlinguist
  • 3,658
  • 4
  • 18
  • 41
1

When something is constant, you use uppercase letters with underscores to separate the words. That's the same for everything, variables, fields, objects and constant lambdas too.

from Oracle's site:

The names of variables declared class constants and of ANSI constants should be all uppercase with words separated by underscores ("_"). (ANSI constants should be avoided, for ease of debugging.)

Bálint
  • 4,009
  • 2
  • 16
  • 27
  • 5
    Define _constant_. – Sotirios Delimanolis Nov 07 '16 at 17:19
  • @SotiriosDelimanolis Based on a dictionary: Constant a situation/object that does not change. – Bálint Nov 07 '16 at 17:33
  • 4
    Don't base it on a dictionary definition. Base it on a language specification. What does the Java language consider a constant? How does it apply to this example? – Sotirios Delimanolis Nov 07 '16 at 17:34
  • I guess he means `static final` fields by the term _constant_ in Java context. Though it's true that _constant_ per se is not semantically defined in Java terms. I'd say something being _constant_ has more to do with being `final` and _immutable_. – Nándor Előd Fekete Nov 07 '16 at 17:50
  • @NándorElődFekete The Java uses _constant_ for multiple language constructs. That's why I asked for clarification here. Which one(s) does this answer refer to? – Sotirios Delimanolis Nov 07 '16 at 18:05
  • Anything with the final keyword in this case – Bálint Nov 07 '16 at 18:17
  • Please add that to your answer. Is this your opinion or is this based on an organization's conventions, some standard? – Sotirios Delimanolis Nov 07 '16 at 18:24
  • @SotiriosDelimanolis BTW, oracle also uses the term "constant" – Bálint Nov 07 '16 at 18:41
  • 1
    @Bálint They do, but in the JLS it's used in a more restricted sense in terms such as "constant expression", which is an entirely different beast. Hence why it's important that you explicitly define what you mean by it: there is no single definition in Java for the word "constant". If you for example define it as "any field marked as `final`", I'd disagree that they should all be captialised. – biziclop Nov 08 '16 at 10:17
  • I think this is subjective. There are some clear cases, e.g. a value known at compile time is definitely a constant that should use snake case caps, whereas there are even some static final objects whose value can only be determined by the program state at the time the class is loaded: I don't think such runtime constants should normally be in caps. The dividing line, somewhere in between, is a grey area. – Klitos Kyriacou Nov 08 '16 at 10:59
0

Your IDE will probably warn you if you fail to use SNAKE_CASE_CAPS like any other static final variable.

Nothing I could find from Oracle suggests that you should treat a lambda differently from any other type, in this respect.

I failed to find any examples in the JDK source. I found some examples in Guava that use SNAKE_CASE_CAPS.


However teams and individuals can and do invent local conventions (for example, some projects use snake_case_lower_case_for_test_methods_in_jUnit()), and if you feel it's useful, you could adopt a local convention in your case.

I personally feel that:

  • myStream.map(MY_FUNCTION) feels a bit ugly.
  • declaring lambdas at the top of the file, among the other variables, feels a bit ugly.

I feel static final functions should be "sort-of peers" to methods, capitalised and placed accordingly, so it feels more natural to me to have something like:

private List<String> asStrings(List<Foo> foos) {
     return foos.stream().map(fooToString).collect(toList());
}

private static final Function<Foo,String> fooToString = f -> 
     "Foo: " + foo.id;

... than to declare the function at the top of the file as FOO_TO_STRING. We usually write private methods below the public methods that use them. It seems reasonable to me to write private functions below the public methods that use them, too.

But note, there's a lot of "feels" in my justification here, which may or may not be enough reason.


I note that in the Oracle Java source, the standard code sidesteps this issue, by not using static variables when it could. For example, in Function.java:

 static <T> Function<T, T> identity() {
      return t -> t;
 }

... returns an inline new Function object, rather than reusing a shared Function object stored in a class or object variable.


Note also that you can declare ordinary static methods and use them as functions, with the slight overhead of using this or the class name with :::

private static String slimify(String s) {
    return "Slim says: " + s;
}

...

out = stream.map(this::slimify).collect(Collectors.toList());

(I don't currently get a compiler warning about using this in a static context)

slim
  • 40,215
  • 13
  • 94
  • 127