Java snippets have long memories!...

Hi all,

Before you get reading what is maybe a tl;dr… I should say this isn’t asking a question or raising a problem, but is just a discussion/interest point related to java snippets! :wink:

For some of you, what I am writing here won’t come as a surprise, but I thought it worth writing as it might avoid the mistake I made, and it also can potentially be quite useful.

While playing with Java snippets I was surprised to stumble on some interesting behaviour. I had “incorrectly” initialised the variables and not really considered how Java Snippets are implemented so at first I was surprised, but after playing with them for a few minutes, the reason for the behaviour made sense.

It was, however, what I would term a “gotcha”. We are generally given to believe that a java snippet acts only on the data from the single row that is presented to it, and so data from other rows cannot be accessed. Well this is still true, we cannot directly reference other rows, but that is not to say that a java snippet cannot be coded to be presented with data acquired from other (earlier) rows…

Let me explain what I am talking about by way of an example.
Here is some sample data in a Table Creator:
image

and here is a small java snippet:

What would you expect the result of the output “Message” column to be for each of these rows? (The code is relatively simple so hopefully you can take a guess, even if you don’t know java)

Taken literally, you might think that the “message” variable gets set to " is a girl", and then, if the “Sex” column on a given row is “Male”, the message gets changed to " is a boy", so (for our sample data) the resulting output would be alternating phrases of “[name] is a boy”, and “[name] is a girl

Something like this perhaps?
image

Except this would be wrong. The resulting output from the above java snippet is this:

image

Did that come as a surprise? It did to me. You may be thinking, as I did…“How can that be when the girls are clearly marked as “Female” (i.e. not “Male”) in the Sex column?”

Well, the correct snippet to produce the expected behaviour is this:

image

This is because the section marked “Your custom variables” is (I am guessing) only processed during the instantiation (the creation) of the object built from this piece of java. If you ever wondered why that section is split away, now you know (at least one of) the reasons. They are “Global” variables and so the variables created there are not re-initialised for each row. Hence when “message” gets set to " is a boy" on the first row, it remains as " is a boy" for the processing of every other row, as nothing changes it.

This got me thinking that whilst this could lead to unexpected consequences if care is not taken to correctly initialise variables for each invocation of the snippet, they could actually have some quite beneficial consequences that I hadn’t previously realised was possible with this node.

Since beginning to write this post, I have re-read the help for “Java Snippet”, I see now that it does say : Note that the snippet allows defining custom global variables I hadn’t read that bit before, and in my defence, I don’t think it is obvious in the snippet dialog that “Your custom variables” actually means “Your custom global variables”. Maybe that should be made clearer for people like me! :wink: I had previously just been putting all my variable declarations in that section without giving it a second thought!

So, now that we have this information, what can we do with it?

For example, how about calculating a running total (cumulative sum)…

image

Or a java snippet “lag column” :wink:

image

Or some sort of “progressive concatenation” of names…

A sequence generation within a some form of grouping:

image

A “counter generator” (another one!) :wink:

image

So for some (or maybe all) of the above, there are other nodes available that can do the job maybe better, or more efficiently, and these examples are only for demonstration, but they do demonstrate a (not always obvious) side-effect of the implementation of the java snippets which could potentially trip people up, but could also be useful on occasion.

If there is a purpose-built node that can do the job, I would strongly advise using it, rather than writing a java snippet to do it, both for reasons of performance/efficiency and because it’s already been tested, but there might just be a time when this feature could prove useful.

All of the above can be seen demonstrated in the attached workflow.

Java Snippets Have Memory.knwf (18.1 KB)

Hope you all have a great weekend!

4 Likes

@takbb thank you for this discussion. I would like to point you to my meta collection about KNIME and Java without claiming a very deep expertise with Java itself.

Two remarks about your example with the message. You might want to consider

  • checking for Null values in order not to crash the node once they may appear
  • use .equals() instead of =
  • complete the condition with an else clause that would complete the logic
5 Likes

Thanks @mlauber71 for both taking the time to read what I have written, and for this additional info that I’ll have a look through over a coffee later.

Re the specific points. Yes you are quite right about the null test. My code assumes the “Male” / “Female” value is always present, which isn’t good defensive coding, and I agree it should really test for null first (thus making use of java’s short-circuit evaluation to not crash the node!) such as:

image

With regard use of .equals() rather than =… as far as I can see my code does use equals() throughout where it is appropriate to do so. The only use of “=” I have (I think) is in assignment, and I use == for testing of a null in the “sequence within group” snippet which is correct. Certainly .equals() is always to be used for testing object equality as otherwise it simply won’t produce the correct result (it would compare object addresses rather than values), but == has to be used for testing of null, or else that itself would result in a NullPointerException.

Yes, I agree with what you say about completing the if with an else. I was using this to demonstrate the point in a trivial way, rather than as a proper demo on how to write (bad :wink: ) java, but the point you make is perfectly valid.
:slight_smile:

2 Likes

Hi @takbb & @mlauber71

Crystal clear. Kudos to both of you for sharing and commenting all this information at the KNIME community for the benefit of all its members :smiley: :+1: !

Thanks & best wishes

Ael

3 Likes