Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LANG-1733] Add null-safe Consumers.accept() and Functions.apply() #1215

Merged
merged 12 commits into from
May 29, 2024

Conversation

imbf
Copy link
Contributor

@imbf imbf commented May 12, 2024

JIRA Ticket: LANG-1733

Suggestion: Introduce null handling features working with with the java.util.function package, or more generally, with Java 8 lambdas.

  • It simplifies null handling by eliminating unnecessary steps such as using specific types or if/else statements.
  • It reduces the overhead associated with managing objects like the Optional type.
  • It decreases the complexity involved in other null handling methods.

Copy link
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imbf
Please follow the pattern established by the 'Suppliers' class in this package. There is no need for a new class. TY.

@jochenw
Copy link
Contributor

jochenw commented May 12, 2024

@garydgregory Have to admit, that even I don't understand, what you are suggesting?

@codecov-commenter
Copy link

codecov-commenter commented May 12, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.54%. Comparing base (f962e7b) to head (f2c71db).
Report is 219 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1215      +/-   ##
============================================
+ Coverage     92.07%   92.54%   +0.46%     
- Complexity     7587     7757     +170     
============================================
  Files           200      200              
  Lines         15844    15901      +57     
  Branches       2890     2819      -71     
============================================
+ Hits          14589    14715     +126     
+ Misses          682      648      -34     
+ Partials        573      538      -35     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@garydgregory
Copy link
Member

Our Suppliers class implements a null-safe get method. If you want to do a null-safe version of accept for Consumers, then that new method should go in our Consumers class, not a new class.

@imbf
Copy link
Contributor Author

imbf commented May 13, 2024

Thanks for your feedback.

I moved null handling features to Consumers and Functions class in the function package.

Copy link
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imbf
Thank you for your update. Please see my comments.

* @param consumer the consumer to consume.
* @param <T> the type of the argument the consumer accepts.
*/
public static <T> void acceptIfNotNull(final T object, final Consumer<T> consumer) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The name can just be accept.
  • Add a Javadoc since tag.
  • Add null-check for consumer, see Suppliers.get()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree that the API is noop if the input to the functional object is null. A lot of APIs accept null as valid input, for example to reset a value to its default.

@@ -21,7 +21,7 @@
import java.util.function.Function;

/**
* Provides {@link Consumer} instances.
* Provides {@link Consumer} instances and utilities for working with {@link Consumer}.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary edit.

* @param function the function to apply.
* @param <T> the type of the argument the function applies.
* @param <R> the type of the result the function returns.
* @return the value the function returns If the object is null; null otherwise.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The name can just be apply.
  • Add a Javadoc since tag.
  • Add null-check for function, see Suppliers.get()

Consumers.acceptIfNotNull(builder, sb -> sb.append("-bae"));
assertEquals("jay-bae", builder.toString());

assertDoesNotThrow(() -> Consumers.acceptIfNotNull((String) null, string -> fail()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for assertDoesNotThrow

@Test
public void testAcceptIfNotNull() {
StringBuilder builder = new StringBuilder("jay");
Consumers.acceptIfNotNull(builder, sb -> sb.append("-bae"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use your name as test data, just use data like foo and bar like you did in the other test.

@imbf imbf force-pushed the LANG-1733-null-handling-features branch from d419f9b to 2b689da Compare May 23, 2024 00:41
@imbf
Copy link
Contributor Author

imbf commented May 23, 2024

Thank you for your feedback.

I applied most of feedbacks. but the name suggestion is not good for me.
I think your suggestion is short and easy but the existing name describes the functionality of the method more accurately.

@garydgregory
Copy link
Member

Well, you can change the names now, and save me the work, or I'll change them after I review the PR and it is merged...

Copy link
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imbf
Please see my additional comments.
Are there call sites within Commons Lang where it would be beneficial to use these new APIs? If the potential call sites are already null-safe concerning the functional objects, then those would not be candidates, but, there may be others.

* @param consumer the consumer to consume.
* @param <T> the type of the argument the consumer accepts.
*/
public static <T> void acceptIfNotNull(final T object, final Consumer<T> consumer) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree that the API is noop if the input to the functional object is null. A lot of APIs accept null as valid input, for example to reset a value to its default.

* @since 3.15.0
*/
public static <T, R> R applyIfNotNull(final T object, final Function<T, R> function) {
return object != null && function != null ? function.apply(object) : null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree that the API is noop if the input to the functional object is null. A lot of APIs accept null as valid input, for example to reset a value to its default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds great. null can also be a valid input.

Thank you.

@imbf
Copy link
Contributor Author

imbf commented May 27, 2024

@garydgregory

Initially, I added apis that only work when the object is not null. In this case, there were many useful call sites in this project. (e.g. ArrayFill.fill()) After applying #1215 (comment), these apis accepted null as valid input and lost null-safe functionality.

This is not my intent. If you want to apply a functional interface regardless of whether the object is null or not, making other methods is better than fixing existing methods.

What do you think about my opinion?

Copy link
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @imbf
Thank you for your update.
I added one comment.

*/
@Test
public void testAccept() {
final StringBuilder builder = new StringBuilder("foo");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use mock testing here, it makes the test too obtuse; this is not a hard feature to test IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your feedback.
I modified my code to not use mock testing.

@garydgregory
Copy link
Member

@imbf
The latest changes break the build.
Run 'mvn' by itself to run all build checks before you push.

@garydgregory garydgregory merged commit 234c6a9 into apache:master May 29, 2024
18 checks passed
@garydgregory garydgregory changed the title LANG-1733: Add null handling features working with Java 8 specs [LANG-1733] Add null-safe Consumers.accept() and Functions.apply() May 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants