Java consumer with two arguments

Where is the Java 8 Consumer with more than one argument?

Such as in .Net, which provides several implementations of the Action delegate (equivalent to Java Consumer functional interface) with different number and type of arguments, I was expecting that Java 8 provides some way of specifying a Consumer with more than one argument of different types.

I know that in Java we cannot define different types with the same name that just differ in the generic type parameters, but there would be nice fluent alternatives to provide a multi-argument Consumer .

Is there any easy way to do it, which does not require defining a new functional interface?

Java Solutions

Solution 1 — Java

For 3 and more arguments you could use curried(http://en.wikipedia.org/wiki/Currying) functions with last consumer:

FunctionDouble, FunctionInteger, ConsumerString>>> f = d -> i -> s -> < System.out.println("" + d+ ";" + i+ ";" + s); >; f.apply(1.0).apply(2).accept("s"); 

It’s enough to have a function of one argument to express function of any number of arguments: https://en.wikipedia.org/wiki/Currying#Lambda_calculi

Solution 2 — Java

By default you’re limited with only java.util.function.Consumer and java.util.function.BiConsumer . They are sufficient for current java streaming API. But you can create your own functional interfaces that will receive as many arguments as you like and use it in your own custom APIs.

Читайте также:  Animated Product Card using JavaScript - @code.scientist x @codingtorque

Solution 3 — Java

It’s pretty easy to define Functional Interfaces for yourself. In the project I am currently working on, I have found several occasions where passing a method as an argument has allowed me to keep my code nice and DRY. Here are some functional interfaces I’ve defined:

@FunctionalInterface public interface CheckedVoidFunction < void apply() throws Exception; > @FunctionalInterface public interface VoidFunction < void apply(); > @FunctionalInterface public interface SetCategoryMethod < void accept(ObservableList list, Document document, String pattern); > 

Here are a method that accepts these kinds of arguments:

private void loadAnnotations(String annotationType, VoidFunction afterLoadFunction, List documentPaths)  

And here is where I call these methods with different methods as arguments:

loadAnnotations(DocumentReader.REDACTION_ANNOTATION_TYPE, this::afterLoadRedactions, documentPaths); loadAnnotations(DocumentReader.HIGHLIGHT_ANNOTATION_TYPE, this::afterLoadHighlights, documentPaths); 

There may be better ways to do this, but I thought I'd share what has been useful for me.

Solution 4 - Java

> Is there any easy way to do it, which does not require defining a new functional interface?

An object can contain any number of other objects. The Streams API is designed to stream just one object at a time, and if you need more you would wrap these in an object which holds them all.

MapString, Long> map = new HashMap<>(); // each entry has a key and a value as Map.EntryString, Long> MapLong, String> revMap = map.entrySet().stream() .collect(groupingBy(Entry::getValue(), HashMap::new, Entry::getKey)); 

Источник

Interface BiConsumer

Type Parameters: T - the type of the first argument to the operation U - the type of the second argument to the operation Functional Interface: This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

Represents an operation that accepts two input arguments and returns no result. This is the two-arity specialization of Consumer . Unlike most other functional interfaces, BiConsumer is expected to operate via side-effects.

Method Summary

Returns a composed BiConsumer that performs, in sequence, this operation followed by the after operation.

Method Details

accept

andThen

Returns a composed BiConsumer that performs, in sequence, this operation followed by the after operation. If performing either operation throws an exception, it is relayed to the caller of the composed operation. If performing this operation throws an exception, the after operation will not be performed.

Report a bug or suggest an enhancement
For further API reference and developer documentation see the Java SE Documentation, which contains more detailed, developer-targeted descriptions with conceptual overviews, definitions of terms, workarounds, and working code examples. Other versions.
Java is a trademark or registered trademark of Oracle and/or its affiliates in the US and other countries.
Copyright © 1993, 2023, Oracle and/or its affiliates, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
All rights reserved. Use is subject to license terms and the documentation redistribution policy.

Источник

Java 8 functional interface (Consumer) additional parameter

Is it possible to somehow parametrize Java 8 Consumer? I want to have reusable Consumer where I can put additional arguments in place where I use it.

List dates = new ArrayList(); Set alarms = new HashSet(); Consumer entryConsumer1 = entry -> < LocalTime time = entry.getDate().toLocalTime(); Alarm alarm = new Alarm(time, calendar1.getPattern()); alarms.add(alarm); dates.add(entry.getDate()); >; Consumer entryConsumer2 = entry -> < LocalTime time = entry.getDate().toLocalTime(); Alarm alarm = new Alarm(time, calendar2.getPattern()); alarms.add(alarm); dates.add(entry.getDate()); >; calendar1.generateEntries(criteria).forEach(entryConsumer1); calendar2.generateEntries(criteria).forEach(entryConsumer2); 

calendar1, calendar2 are the same type As you can see both consumers differ only in one argument. Is it possible to simplify this code/don't duplicate?

2 Answers 2

Create a factory method for your consumers:

public Consumer createConsumer(Calendar calendar, Set alarms, List dates) < return entry -> < LocalTime time = entry.getDate().toLocalTime(); Alarm alarm = new Alarm(time, calendar.getPattern()); alarms.add(alarm); dates.add(entry.getDate()); >> 
calendar1.generateEntries(criteria).forEach(createConsumer(calendar1, alarms, dates)); calendar2.generateEntries(criteria).forEach(createConsumer(calendar2, alarms, dates)); 

But also: It is bad practice (against functional programming principles) to have a lambda expression or function with side effects, such as adding alarms to the set of alarms or adding dates to the list of dates inside the lambda. A more functional approach would be to use transformation methods like map and then collect the results. For example:

Set alarms = calendar1.generateEntries(criteria) .map(entry -> new Alarm(entry.getDate().toLocalTime(), calendar1.getPattern())) .collect(Collectors.toSet()); 

Источник

Java 8 Consumer with additional parameters

I want to write a generic DTO updater, which updates some of it's properties. My object looks like this:

public void override(Person person, Map newValuesForProperties) < newValuesForProperties.forEach((type,value)) -> < if(type == OverriddenType.FIRST_NAME) < person.setFirstName((String)value); >else if(type == OverriddenType.LAST_NAME) < person.setLastName((String)value); >else if(type == OverriddenType.AGE) < person.setAge((Integer)value); >>); > 

. I would like to use some Java 8 Function/Consumer features to define the setters in each enum. I tried something like this:

enum OverriddenType < FIRST_NAME(p ->p.setFirstName(. )), //don't know what to set here since the value is not here LAST_NAME(p -> p.setLastName(. )), AGE(p -> p.setAge(. )); Consumer consumer; OverriddenType(Consumer consumer) < this.consumer = consumer; >public Consumer getConsumer(); > 

But as you can see I cannot pass the dynamic value here. Also don't know how the logic would look like, but I would imagine something like this:

public void override(Person person, Map newValuesForProperties) < newValuesForProperties.forEach((type,value)) ->type.getConsumer().accept(person, value) // this doesn't exist, but I can imagine some additional parameter passing ); > 

Can you provide me a solution for this? Can it work? I am afraid that the incoming value is a dynamic therefore it won't work for enums..

Источник

Consumer with more than one argument in Java 8?

Such as in .Net, which provides several implementations of the Action delegate (equivalent to Java Consumer functional interface) with different number and type of arguments, I was expecting that Java 8 provides some way of specifying a Consumer with more than one argument of different types. I know that in Java we cannot define different types with the same name that just differ in the generic type parameters, but there would be nice fluent alternatives to provide a multi-argument Consumer . Is there any easy way to do it, which does not require defining a new functional interface?

There's the BiConsumer and variations of it involving primitive types (like ObjIntConsumer ), but no more

As a C# developer who started w/Java 15 years ago and am currently working w/Java, I'll go on record saying that Java's Consumer / Producer / Function /etc. classes along with all of the streaming feature are severely lacking when compared to the C# counterparts. I really wish these features were more complete and seamless.

A. Action and Func (up to 16) are built into dotnet(core). So this Single/BiSomething. geeze louise. B. For future readers, I found a "TriConsumer" in this library. You can either grab one of these, or define your own. docs.jboss.org/infinispan/9.4/apidocs/org/infinispan/util/… search.maven.org/search?q=a:infinispan-core

4 Answers 4

For 3 and more arguments you could use curried(http://en.wikipedia.org/wiki/Currying) functions with last consumer:

Function>> f = d -> i -> s -> < System.out.println("" + d+ ";" + i+ ";" + s); >; f.apply(1.0).apply(2).accept("s"); 

It's enough to have a function of one argument to express function of any number of arguments: https://en.wikipedia.org/wiki/Currying#Lambda_calculi

And, as it's already mentioned, there is no other approach w/o defining a new functional interface w/ 3 or more parameters in java8.

@roundar - for one off cases, sure, but if you need to write generic code (e.g., for a framework) that handles these multi-consumer cases, you'll quickly run into combinatorial explosion trying to cover all the bases.

By default you're limited with only java.util.function.Consumer and java.util.function.BiConsumer . They are sufficient for current java streaming API. But you can create your own functional interfaces that will receive as many arguments as you like and use it in your own custom APIs.

But, is it a good idea to have MultiConsumer ? Could it be possible that our code has design problems if we need to make a MultiConsumer ?

@MasterJoe2 you can think of any method that returns void as a consumer method. There's no design flaw in how many arguments it takes. It could be 0 or it could be 10. If you need that method then you can create a consumer functional interface for it.

It's pretty easy to define Functional Interfaces for yourself. In the project I am currently working on, I have found several occasions where passing a method as an argument has allowed me to keep my code nice and DRY. Here are some functional interfaces I've defined:

@FunctionalInterface public interface CheckedVoidFunction < void apply() throws Exception; >@FunctionalInterface public interface VoidFunction < void apply(); >@FunctionalInterface public interface SetCategoryMethod < void accept(ObservableListlist, Document document, String pattern); > 

Here are a method that accepts these kinds of arguments:

private void loadAnnotations(String annotationType, VoidFunction afterLoadFunction, List documentPaths)  

And here is where I call these methods with different methods as arguments:

loadAnnotations(DocumentReader.REDACTION_ANNOTATION_TYPE, this::afterLoadRedactions, documentPaths); loadAnnotations(DocumentReader.HIGHLIGHT_ANNOTATION_TYPE, this::afterLoadHighlights, documentPaths); 

There may be better ways to do this, but I thought I'd share what has been useful for me.

Источник

Оцените статью