Java 8 Consumer with additional parameters - java

I want to write a generic DTO updater, which updates some of it's properties. My object looks like this:
class Person {
String firsName;
String lastName;
Integer age;
setter/getter
}
I have an enum which defines which fields can be overridden:
enum OverriddenType {
FIRST_NAME,
LAST_NAME,
AGE
}
Instead of doing a "hardcoded" setter like this...
public void override(Person person, Map<OverriddenType,Object> 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<Person> consumer;
OverriddenType(Consumer<Person> consumer) {
this.consumer = consumer;
}
public Consumer<Person> 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<OverriddenType,Object> 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..

A setter method is a BiConsumer<T,U>, where T is the object instance, and U is the value.
enum OverriddenType {
FIRST_NAME((person, value) -> person.setFirsName((String) value)),
LAST_NAME ((person, value) -> person.setLastName((String) value)),
AGE ((person, value) -> person.setAge((Integer) value));
private final BiConsumer<Person, Object> setter;
private OverriddenType(BiConsumer<Person, Object> setter) {
this.setter = setter;
}
public void override(Person person, Object value) {
this.setter.accept(person, value);
}
}
public void override(Person person, Map<OverriddenType, Object> newValuesForProperties) {
newValuesForProperties.forEach((type, value) -> type.override(person, value));
}

By definition a Consumer only ever takes one argument.
Since you need to be passed both the object to manipulate and the new value, you have to use an interface that allows two arguments to be passed. Luckily there's the BiConsumer interface for that.
BiConsumer<Person, String> personFirstNameSetter = Person::setFirstName;
Note that the use of a method reference here is roughly equivalent to writing (p, fn) -> p.setFirstName(fn).
However, this introduces a slight problem, because you need to know (and specify) the type of the parameter and your enum would like to have mixed types (the first two would return BiConsumer<Person,String> and the last one probably BiConsumer<Person,Integer>.

You need a BiConsumer which can consume the target object and the new value:
enum OverriddenType {
FIRST_NAME((p, v) -> p.setFirstName(v)),
LAST_NAME((p, v) -> p.setLastName(v)),
AGE((p, v) -> p.setAge(v));
BiConsumer<Person> consumer;
OverriddenType(BiConsumer<Person, Object> consumer) {
this.consumer = consumer;
}
public BiConsumer<Person> getConsumer();
}
(If your setter accepts an Object, you may even use method references:
OBJECT(Person::setObject)
)
Instead of exposing the consumer directly, consider defining a public assign or set method in your enum and make the consumer invisible to the outside (information hiding):
public void assign(final Person target, final Object newValue) {
this.consumer.accept(target, newValue);
}
then call as FIRST_NAME.assign(person, "new name").

Related

Java 8: Input a list of functional Interfaces and call them dynamically after .stream()

I have the following method:
public void caller(){
List<Class1> data1 = Arrays.asList(new Class1(), new Class1() ...);
List<Class2> data2 = Arrays.asList(new Class2(), new Class2() ...);
// The following is what I'm trying to implement:
List<BiConsumer<Class1, Double>> peeks1 = Arrays.asList(Class1::setOneNum, Class1::setAnotherNum, Class1:: setMoreNum);
List<BiConsumer<Class2, Double>> peeks2 = Arrays.asList(Class2::setSomeNum1, Class2::setSomeNum2);
helper(data1, peeks1);
helper(data2, peeks2);
...
}
private <T> List<T> helper(List<T> data, List<BiConsumer<T, Double>> peeks) {
for(BiConsumer<T, Double> singlePeek: peeks){
data = data.stream()
.peek(a -> singlePeek.accept(a, math.random()))
.collect(Collectors.toList());
}
return data;
}
There are other implementation in common for Class1 and Class2, the only difference are the methods called after the .stream() which is why I'm trying to "merge" the functions into one helper.
Where BiConsumer is a setter. I want to call a list of setters after stream(). But I cannot input a list of functional interface into helper() (what I tried was Arrays.asList(Class1::setNum, Class1::setAnotherNum, Class1::setMoreNum) won't work as an input since Array.asList() only accepts Object). So is there any work-around? Thanks!
#user7 Thanks for pointing it out. I was careless but I've fixed the "typo". And added the caller function.
You have to specify the target type, when you call the .asList method:
Arrays.<BiConsumer<Object, Double>>asList(Class1::setOneNum, ...)
Update:
According to the updated code of the question the result of Arrays.asList is not directly handed over to the helper method, so no explicit typing is required.
The only possible reasons left why the code is not working are:
At least one of the methods (setOneNum, setSomeNum1, ...) has wrong parameters types
At least one of the methods is not static
Could I advise you in trying to make it a little bit more functional?
For your code consider the following helper, this one will make use of function as a first class citizen concept and make some High Order Functions:
private <T, V> Function<Supplier<T>, Supplier<T>> helper(Supplier<V> v,
BiConsumer<T, V> bc) {
return (Supplier<T> r) -> {
bc.accept(r.get(), v.get());
return r;
};
}
This helper function expects a Supplier of some value kind of value and a BiConsumer that will be your setter function. The returns is a function of Suppliers of the same class you are working with.
With that we can make something like a pipe operator of functional languages. Their premises is that the data should processed in a pipeline operation.
List<Class1> data1 = Arrays.asList(new Class1(), new Class1());
List<Class2> data2 = Arrays.asList(new Class2(), new Class2());
Supplier<Double> random = () -> Math.random();
This will be our data, you have the same array and now a Supplier with the random value you want.
Now lets compose our pipeline with andThem:
data1.stream()//
.forEach(data -> {
helper(random, Class1::setOneNum)//
.andThen(helper(random, Class1::setAnotherNum))//
.andThen(helper(random, Class1::setMoreNum))//
.apply(() -> data);
System.out.println(data.toString());
});
data2.stream()//
.forEach(data -> {
helper(random, Class2::setSomeNum1)//
.andThen(helper(random, Class2::setSomeNum2))//
.apply(() -> data);
System.out.println(data.toString());
});
As you can see the helper function can be chained together with "andThem" method of Function interface. This will make Java execute the helper function and use it's return as the parameter of the next Function.
The data parameter will hole the values of classes and will be changed each chain. As we iterated all objects will
And the result:
Class1 [oneNum=0,047, anotherNum=0,482, moreNum=0,339]
Class1 [oneNum=0,131, anotherNum=0,889, moreNum=0,411]
Class2 [someNum1=0,18, someNum2=0,004]
Class2 [someNum1=0,497, someNum2=0,702]
I think it is the same result you want. And as you can see you don't need to pass any generics as the Java will understand it well.
The classes that I made for reference:
class Class1 {
double oneNum;
double anotherNum;
double moreNum;
public double getOneNum() {
return oneNum;
}
public void setOneNum(double oneNum) {
this.oneNum = oneNum;
}
public double getAnotherNum() {
return anotherNum;
}
public void setAnotherNum(double anotherNum) {
this.anotherNum = anotherNum;
}
public double getMoreNum() {
return moreNum;
}
public void setMoreNum(double moreNum) {
this.moreNum = moreNum;
}
#Override
public String toString() {
return MessageFormat.format("Class1 [oneNum={0}, anotherNum={1}, moreNum={2}]", oneNum, anotherNum, moreNum);
}
}
class Class2 {
double someNum1;
double someNum2;
public double getSomeNum1() {
return someNum1;
}
public void setSomeNum1(double someNum1) {
this.someNum1 = someNum1;
}
public double getSomeNum2() {
return someNum2;
}
public void setSomeNum2(double someNum2) {
this.someNum2 = someNum2;
}
#Override
public String toString() {
return MessageFormat.format("Class2 [someNum1={0}, someNum2={1}]", someNum1, someNum2);
}
}

How to dynamically create a generic lambda implementation by type?

For example, i have class
public class Human {
private String name;
...
}
and i want to implement something like this:
(1)
List<Human> humans = initHumans();
Equals<Human> humanEquals = new Equals<>();
Predicate<Human> filter = humanEquals.filter("name", "John");
List<Human> filteredHumans = humans
.stream()
.filter(filter)
.collect(Collectors.toList());
Equals:
public class Equals<T> extends AbstractPredicate<T> {
public java.util.function.Predicate<T> filter(String fieldName, String fieldValue) {
....
}
}
is it posible implement filter method to provide the (1) behavior?
I want to return a Predicate like this:
Predicate<Human> predicate = human -> human.getName().equals("John");
similarly should work for other classes:
Predicate<Car> filter = humanEquals.filter("color", "red");
//like this:
Predicate<Car> predicate= human -> human.getColor().equals("red");
Yes, this might be achieved by reflection:
public static <T> Predicate<T> filter(Class<T> clazz, String fieldName, Object fieldValue) {
// 1
return (T instance) -> {
try {
final Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return fieldValue.equals(field.get(instance));
} catch (NoSuchFieldException | IllegalAccessException e) {
// 2
}
return false;
};
}
I made a method static because I have no idea what the AbstractPredicate is and why you need to create an instance of a utility class.
I am getting the value from a field directly without using a getter - what naming convention should we adhere? (it might be improved)
The use is:
final Predicate<Human> filter = Equals.filter(Human.class, "name", "John");
System.out.println(filter.test(new Human("John"))); // true
System.out.println(filter.test(new Human("Andrew"))); // false
There are still a few questions we need to think of - validating parameters (1), handling exceptions (2).
Another option can be using a Function<T, E> to provide a reference to a getter:
public static <T, E> Predicate<T> filter(Function<T, E> supplier, E value) {
return (T instance) -> supplier.apply(instance).equals(value);
}
An example of use:
final Predicate<Human> predicate = Equals.filter(Human::getName, "John");
System.out.println(predicate.test(new Human("John"))); // true
System.out.println(predicate.test(new Human("Andrew"))); // false

function name as a string

I am trying to wrap my head around generic and functions... what I am trying to achieve: Passing function name as a string to get it executed:
I want to do Wrapper.useFunction("eleven") or Wrapper.useFunction("ten")
public class Wrapper<T> {
public F useFunction(Function<F, F> function) {
return function.apply(F);
}
Function<F, String> ten = s -> "10";
Function<F, String> eleven = s -> "11";
}
But this code not even close to compiling. Maybe it doesn't make any sense. Any suggestions?
If you have a finite set of functions which you would like to be able to call I would recommend building a Map which maps Strings to instances of Runnable (or similar functional interfaces). Your useFunction method may then look up the function implementation in the Map and call it if it exists.
Example:
public class SomeClass {
private final Map<String, Runnable> methods = new HashMap<>();
{
methods.put("helloworld", () -> {
System.out.println("Hello World!");
});
methods.put("test", () -> {
System.out.println("test!");
});
methods.put("doStuff", () -> {
System.out.println("doStuff!");
});
}
public void perform(String code) {
methods.getOrDefault(code,
() -> {
System.err.println("No such Method: "+code);
})
.run();
}
}
If you want to call arbitrary methods you should probably use Reflection as stated by others.

How can we pass a variable field /method name in Comparator.comparing

I have a Report {String name, Date date, int score } class.
I want to be able to sort a list of reports for any member variable using the new java 8 syntax
So java 8 provides this new
list.sort(Comparator.comparing(report -> report.name))
to sort the list on name.
Lets say instead of name I want to provide a variable field name to this method eg. something like
list.sort(Comparator.comparing(report -> report.anyField))
where anyField can be name or date or score. How do I achieve this behavior.
Just create a comparator for each property.
static Map<String,Comparator<Report>> ORDER;
static {
HashMap<String,Comparator<Report>> m=new HashMap<>();
m.put("name", Comparator.comparing(r -> r.name));
m.put("date", Comparator.comparing(r -> r.date));
m.put("score", Comparator.comparingInt(r -> r.score));
ORDER=Collections.unmodifiableMap(m);
}
public static void sort(List<Report> list, String order) {
Comparator<Report> c=ORDER.get(order);
if(c==null) throw new IllegalArgumentException(order);
list.sort(c);
}
You may consider using an enum as alternative to String, which eliminates the possibility of providing a non-existent property name:
enum ReportOrder {
NAME(Comparator.comparing(r -> r.name)),
DATE(Comparator.comparing(r -> r.date)),
SCORE(Comparator.comparingInt(r -> r.score));
private Comparator<Report> cmp;
private ReportOrder(Comparator<Report> c) { cmp=c; }
public void sort(List<Report> list) {
list.sort(cmp);
}
}
Now you can just say, e.g. ReportOrder.NAME.sort(list);. Of course, the other delegation style works as well:
public static void sort(List<Report> list, ReportOrder o) {
list.sort(o.cmp);
}
 
sort(list, ReportOrder.DATE);
One very generic solution is to use Java's Reflection and some casting:
String sortBy = "name";
list.sort(Comparator.comparing(report -> {
try {
return (Comparable) report.getClass().getDeclaredField(sortBy).get(report);
} catch (Exception e) {
throw new RuntimeException("Ooops", e);
}
}));
If you use an additional library like https://github.com/jOOQ/jOOR the code becomes even simpler:
String sortBy = "score";
list.sort(Comparator.comparing(report -> Reflect.on(report).field(sortBy).get()));
Please be aware that this solution only works with fields that implement Comparable and that it has some runtime overhead.
public class Report {
//properties and getters
public static void sort(List<Report> list, Function<Report, Comparable> sortKey) {
list.sort(Comparator.comparing(sortKey));
}
}
Report.sort(reports, Report::getName);
Report.sort(reports, Report::getDate);
Report.sort(reports, Report::getScore);
Could make this into a generic util class where you can pass in a List of any class:
public class MyUtil<T> {
void sort(List<T> t, Function<T, Comparable> sortKey) {
t.sort(Comparator.comparing(sortKey));
}
}
MyUtil<Report> util = new MyUtil();
util.sort(ppl, Report::getName);
If your Report has getter method of various field you can do like this
list.sort(Comparator.comparing(Report::getFieldName));
Or with lambda expression
list.sort((ob1, ob2) -> ob1.getFieldName().compareTo(ob2.getFieldName()));
At some place, you'll have to use a bit of reflection to pull this off. Here's an example using the bean introspection mechanism of java:
public static class MyBean {
private String name;
private Date birthday;
private Integer score;
...
... (constructor, getters, setters - the usual bean stuff)
}
PropertyDescriptor[] pdesc = Introspector.getBeanInfo(MyBean.class).getPropertyDescriptors();
for(PropertyDescriptor pd : pdesc) {
if(Comparable.class.isAssignableFrom(pd.getPropertyType())) {
System.out.println("Property " + pd.getName() + " could be used for comparison");
Function<MyBean, Comparable> extractor = b -> {
try {
return (Comparable) pd.getReadMethod().invoke(b);
}
catch(Exception e) {
throw new RuntimeException(e);
}
};
Comparator<MyBean> comp = Comparator.comparing(extractor);
// do something useful with the comparator :-)
}
}
Additionally, you could go a similar way for primitive types (e.g. int, which does not implement Comparable as opposed to Integer.)
If the set of properties is fixed (name, date, score) then I think a clean way would be to pass a Comparator:
private void someMethod(Comparator<Report> comparator){
...
list.sort(comparator);
...
}
...
someMethod(Comparator.comparing(report::getName));
someMethod(Comparator.comparing(report::getDate));
someMethod(Comparator.comparingInt(report::getScore));
someMethod(Comparator.comparing(report::getName).thenComparingInt(report::getScore));
There is a Comparator class called NamedMethodComparator that will work as a Comparator for any zero arg method that returns a Comparable posted here: How to use Comparator in Java to sort

Efficiently access fields by name

A little background as to what I'm trying to achieve:
I'm parsing JSON (over 15GB) and I must store it in memory so any wrappers and extra data is not welcomed, due to the framework and interfaces used within it I must provide functionality to access fields by name. By replacing some String with Enum, Integer with int, Double with double, etc. I'm able to shave about 90% of memory footprint (in comparison with Jackson).
I'm looking to efficiently access the fields at runtime in Java by their name. I'm aware of reflection, but for my case its performance is simply unacceptable, so I don't want to use it.
If it makes the problem easier to solve I'm not too bothered about setting the fields values. I also know at compile time the names of supported fields.
I don't want to store everything in a map i.e. Map<String,Object> due to the memory footprint of boxed object, but I don't mind returning them in a boxed form.
I'm sure this problem was encountered by others and I'm interested in any clever solutions - cleverer than tons of if ... else ... statements.
Let's say the interface to implement is:
public interface Accessor {
Object get(String fieldName);
}
The Object returned by get can be of any type including enum. A naive implementation would be:
public class TestObject implements Accessor {
public enum MyEnum {ONE, TWO, THREE};
private final MyEnum myEnum;
private final int myInt;
private final double myDouble;
private final String myString;
public TestObject(MyEnum myEnum, int myInt, double myDouble, String myString) {
this.myEnum = myEnum;
this.myInt = myInt;
this.myDouble = myDouble;
this.myString = myString;
}
#Override
public Object get(String fieldName) {
if ("myEnum".equals(fieldName)) {
return myEnum;
} else if ("myInt".equals(fieldName)) {
return myInt;
} else if ("myDouble".equals(fieldName)) {
return myDouble;
} else if ("myString".equals(fieldName)) {
return myString;
} else {
throw new UnsupportedOperationException(); // Or could simply return null
}
}
}
What you want is a mapping from a fieldName to a value, the type of which is determined by the fieldName. You know the set of field names up-front, so this is an ideal task for an Enum.
If you don't like the idea of hard-coding each field as an enum, then the variation would be an enum-per-type (MY_FIELD1 becomes MY_ENUM), with a mapping from fieldName to this EnumType.
In the code below I'm making assumptions about the relationship between fieldName and TestObject. Specifically it looks like TestObject is presenting various types of the same value (surely where reasonable), as opposed to a separate value for each field name?
So, to the code:
Rewrite:
#Override
public Object get(String fieldName) {
MyField field = MyField.mapNameToField(fieldName);
if (field == null)
throw new UnsupportedOperationException(); // Or could simply return null
return field.getValue(this);
}
Given (something like):
enum MyField {
MY_FIELD1("myField1") {
public Object getValue(TestObject obj) { return obj.myEnum; }
},
MY_FIELD2("myField2") {
public Object getValue(TestObject obj) { return obj.myInt; }
},
...
;
public abstract Object getValue(TestObject obj);
public String getName() { return name; }
public static MyField mapNameToField(String name) { return map.get(name); }
static {
map = new HashMap<String,MyField>();
for(MyField value: values()) {
map.put(value.getName(), value);
}
}
private MyField(String fieldName) { name = fieldName; }
private String name;
private static Map<String, MyField> map;
}
I've never used this, but looks promising:
http://labs.carrotsearch.com/download/hppc/0.4.1/api/
"High Performance Primitive Collections (HPPC) library provides typical data structures (lists, stacks, maps) template-generated for all Java primitive types (byte, int, etc.) to conserve memory and boost performance."
In particular, the Object{Type}OpenHashMap classes might be what you're looking for:
ObjectByteOpenHashMap
ObjectCharOpenHashMap
ObjectDoubleOpenHashMap
ObjectFloatOpenHashMap
ObjectIntOpenHashMap
ObjectLongOpenHashMap
ObjectShortOpenHashMap
I imagine you would have all 7 of these defined as fields (or whatever subset of them you like), and you would probe each one in turn to see if the key was present for that type of primitive value. E.g.,
if (byteMap.containsKey(key)) {
return byteMap.lget(); // last value saved in a call to containsKey()
} else if (charMap.containsKey(key)) {
return charMap.lget();
} else if {
// and so on...
}
Notice they have their own special lget() method call to optimize the containsKey() / get() usage pattern so typical with maps.

Categories