While reading online, I came across the following:
public interface UnaryFunction<T>
{
T apply(T arg);
}
.......
private static UnaryFuntion<Object> ID_FUNC = new UnaryFunction<Object>
{
Object apply(Object arg)
{
return arg;
}
};
public static <T> UnaryFunction<T> idFunction()
{
return (UnaryFunction<T>) ID_FUNC;
}
In main:
public static void main(String[] args)
{
String[] strings = {"Peter", "Paul", "Mary"};
UnaryFunction<String> names = idFunction();
for(String s : strings)
{
System.out.println(names.apply(s));
}
Number[] numbers = {1, 2.0, 3L};
UnaryFunction<Number> nums = idFunction();
for(Number n : numbers)
{
System.out.println(nums.apply(n));
}
}
My question is, why do we need a generic interface here?
Would simply the following suffice:
public interface UnaryFunction
{
Object apply(Object arg); //Object as return type and argument type, instead.
}
? What is the need here to use generics?
And, what is actually a generic singleton factory? What is it good for?
Thanks.
The generic singleton factory is the idFunction in your example. Without it you would have a choice between two ugly alternatives, either require a cast wherever you use it, like this:
public class ExampleWithoutGenericSingletonFactory {
static UnaryFunction<Object> ID_FUNC = new UnaryFunction<Object>() {
public Object apply(Object arg) {
return arg;
}
};
public static void main(String[] args) {
BigDecimal b = new BigDecimal("1234.1241234");
BigDecimal b1 = (BigDecimal)(ID_FUNC.apply(b)); // have to cast here >_<
System.out.println("engineeringstring val of b1 = "
+ b1.toEngineeringString());
}
}
or make separate implementations for every type you want to support:
public static UnaryFunction<String> ID_FUNC_STRING = new UnaryFunction<String>() {
public String apply(String arg) {
return arg;
}
};
public static UnaryFunction<Number> ID_FUNC_NUM = new UnaryFunction<Number>() {
public Number apply(Number arg) {
return arg;
}
};
public static UnaryFunction<BigDecimal> ID_FUNC_DECIMAL = new UnaryFunction<BigDecimal>() {
public Number apply(BigDecimal arg) {
return arg;
}
};
giving you some ugly verbose cut-n-pasted code with a different name for every type that you have to keep straight. But since you know it's a pure function and the types get erased, you can have only one implementation (ID_FUNC) and have the singleton factory idFunction return it.
You would use this for cases where you have one function implementation that you want to be able to specify different types on, where the implementation is stateless.
The example could be better, since it only calls toString on the objects returned from the function call there's no demonstrated benefit from the factory. If the example showed using type-specific methods on the objects returned then the benefit might be more apparent.
An unchecked cast warning comes up when you do this, but it's safe to suppress it (which is what Joshua Bloch advises).
Related
So, I've got an object constructor:
public Func(Function<Var[], Var<T>> function, Var... arguments) {
// Function is a standart 1.8 class
//...
//secret stuff
}
I call it like that:
return new Func(new Function<Var[], Var>() {
#Override
public Var apply(Var[] args) {
return instance.getAttribute(args[0].value());
}
}, arguments[0].unpack(instance) // unpack(...) returns Var object
);
And it works. Now, my IDE (Intellij IDEA) suggests me to replace Function declaration with lambda. Okay, lets do it:
return new Func(
args -> instance.getAttribute(args[0].value()),
arguments[0].unpack(instance)
);
Now I have an error on args:
Array type expected; found: 'java.lang.Object'
So, apparently args now is Object. Why? Is that a bug in IDE or what?
Entire code:
Template:
public class Template {
public static void main(String[] args) {
SomeClass someClass = new SomeClass();
System.out.println(someMethod(someClass).value());
}
private static class SomeClass {
Var[] var = new Var[12];
SomeClass() {
var = new Var[12];
for ( int i = 0; i < var.length; i++) {
var[i] = new Var<>(i * 4);
}
}
Var getAttribute(int index) {
return var[index];
}
}
public static Var someMethod(SomeClass instance) {
return new Func(new Function<Var[], Var>() {
#Override
public Var apply(Var[] args) {
return instance.getAttribute((int)args[0].value());
}
}, new Var(4));
}
}
Var.java:
public class Var<T> {
private T value;
public Var(T value) {
this.value = value;
}
public T value() {
return value;
}
}
Func.java:
public class Func<T> extends Var<T> {
private Function<Var[], Var<T>> function;
private Var[] args;
public Func(Function<Var[], Var<T>> function, Var... args) {
super(null);
this.function = function;
this.args = args;
}
#Override
public T value() {
return function.apply(args).value();
}
}
The error message appers also in the Eclipse-IDE:
The type of the expression must be an array type but it resolved to Object
I think it is not an IDE-bug, neither in IntelliJ nor in Eclipse. The Compiler needs for the processing of a lambda expression always a target type which is a functional interface.
In the case of
args -> instance.getAttribute((int)args[0].value())
the target type is determined by the first argument of the Func-constructor
Function<Var[], Var<T>> function
However, this functional interface is a generic interface. Java compiles generics using type erasure which means the replacement of the generic parameter-types by the Object-type. Thus, the interface is compiled like
interface Function {
public Object apply(Object args);
}
and this is applied as target type. Thus, for args an Object-type instead of a Var[]-type is expected which results in an error message.
In case of an anonymous class this is different since more informations are provided for the determination of the target type.
new Function<Var[], Var>(){...}
explicitly contains the type-information. Because of this args is expected of Var[]-type and no error message is shown.
There are two possibilities to fix the error:
1) In the getAttribut-method cast args explicitly to Var[], i.e. replace
(int)args[0].value()
with
(int)((Var[])args)[0].value()
or 2) Don't use a generic interface i.e. change the interface to
interface Function {
public Var apply(Var[] args);
}
Then type information is preserved. Of course the rest of the code has to be adapted accordingly.
In my program, the user needs to input what type of players the game will have. The players are "human", "good" (for a good AI), "bad" (for a bad AI) and "random" (for a random AI). Each of these players have their own class that extend one abstract class called PlayerType.
My struggle is mapping a String to the object so I can A) create a new object using the String as sort of a key and B) get the related String from an object of its subclass
Ultimately, I just want the implicit String to only appear once in the code so I can change it later if needed without refactoring.
I've tried using just a plain HashMap, but that seems clunky with searching the keys via the values. Also, I'm guessing that I'll have to use the getInstance() method of Class, which is a little less clunky, which is okay if it's the only way.
What I would do is create an enum which essentially functions as a factory for the given type.
public enum PlayerTypes {
GOOD {
#Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
#Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
#Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
Because then you can just call it like so:
String input = getInput();
PlayerTypes.create(input);
Of course, you'll get an IllegalArgumentException which you should probably handle by trying to get the input again.
EDIT: Apparently in this particular case, you can replace that loop with just merely
return PlayerTypes.valueOf(input).newPlayer();
And it'll do the same thing. I tend to match for additional constructor parameters in the enum, so I didn't think of using valueOf(), but it's definitely cleaner.
EDIT2: Only way to get that information back is to define an abstract method in your PlayerType class that returns the PlayerTypes enum for that given type.
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
#Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
I like the answer provided by Epic but I don't find maps to be clunky. So it's possible to keep a map and get the constructor call directly.
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
The two main options I can think of:
Using Class.newInstance(), as you mentioned (not sure if you had this exact way in mind):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
You could use Class.getDeclaredConstructor.newInstance if you want to use a constructor with arguments (example).
Another option is using switch:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
One potential solution:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
#Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
#Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}
I've seen a question similar to this multiple times here, but there is one big difference.
In the other questions, the return type is to be determined by the parameter. What I want/need to do is determine the return type by the parsed value of a byte[]. From what I've gathered, the following could work:
public Comparable getParam(String param, byte[] data) {
if(param.equals("some boolean variable")
return data[0] != 0;
else(param.equals("some float variable") {
//create a new float, f, from some 4 bytes in data
return f;
}
return null;
}
I just want to make sure that this has a chance of working before I screw anything up. Thanks in advance.
I don't know what these people are talking about. You lose type safety, which is a concern, but you could easily accomplish this with generics...something like:
public <T> T getSomething(...) { }
or
interface Wrapper<T> { T getObject(); }
public <T> Wrapper<T> getSomething(...) { }
The latter promotes the possibility of a strategy pattern. Pass the bytes to the strategy, let it execute and retrieve the output. You would have a Byte strategy, Boolean strategy, etc.
abstract class Strategy<T> {
final byte[] bytes;
Strategy(byte[] bytes) { this.bytes = bytes; }
protected abstract T execute();
}
then
class BooleanStrategy extends Strategy<Boolean> {
public BooleanStrategy(byte[] bytes) { super(bytes); }
#Override
public Boolean execute() {
return bytes[0] != 0;
}
}
Your example code is a bad use case though and I wouldn't recommend it. Your method doesn't make much sense.
This CAN be done. The following code will work:
public byte BOOLEAN = 1;
public byte FLOAT = 2;
public static <Any> Any getParam(byte[] data) {
if (data[0] == BOOLEAN) {
return (Any)((Boolean)(boolean)(data[1] != 0));
} else if (data[0] == FLOAT) {
return (Any)((Float)(float)data[1]);
} else {
return null;
}
}
By using a generic for the return type any Java method can dynamically return any object or primitive types. You can name the generic whatever you want, and in this case I called it 'Any'. Using this code you avoid casting the return type when the method is called. You would use the method like so:
byte[] data = new byte[] { 1, 5 };
boolean b = getParam(data);
data = new byte[] { 2, 5 };
float f = getParam(data);
The best you can do without this trick is manually casting an Object:
float f = (float)getParam(data);
Java dynamic return types can reduce boilerplate code.
You can't do it. Java return types have to be either a fixed fundamental type
or an object class. I'm pretty sure the best you can do is return a wrapper type
which has methods to fetch various possible types of values, and an internal enum
which says which one is valid.
--- edit --- after Danieth's correction!
public <Any> Any getParam(boolean b){
return((Any)((Boolean)(!b)));
}
public <Any> Any getParam(float a) {
return((Any)((Float)(a+1)));
}
public <Any> Any getParam(Object b) {
return((Any)b);
}
public void test(){
boolean foo = getParam(true);
float bar = getParam(1.0f);
float mumble = getParam(this); // will get a class cast exception
}
You still incur some penalties for boxing items and type checking
the returned values, and of course if your call isn't consistent with
what the implementations of getParam actually do, you'll get a class
cast exception.
My 2 cents with an example with Google HTTP client:
static public <Any> Any getJson(final String url, final Class<Any> parseAs) throws IOException {
HttpRequestFactory requestFactory
= HTTP_TRANSPORT.createRequestFactory(
(HttpRequest request) -> {
request.setParser(new JsonObjectParser(JSON_FACTORY));
});
HttpRequest request = requestFactory.buildRequest(HttpMethods.GET, new GenericUrl(url), null);
return request.execute().parseAs(parseAs);
}
Can be use like this:
HashMap<String, Object> out = HttpUtils.getJson( "https://api.qwant.com", HashMap.class);
If you are really only returning a boolean or a float, then the best you can do is Object.
If you are returning variable objects, you have to choose a return type with the least common superclass. Primitives don't have a superclass, but they will be boxed into Object representations (like Boolean and Float) which have a common superclass of Object.
It can also be done as the below example:
public class Test
{
public <T> T dynamicReturnMethod(Class<T> clazz)
{
//your code
return class.getDeclaredConstructor().newInstance();
}
//usage
public static void main(String[] args)
{
Test t = new Test();
ClassObjectWhichNeedsToBeReturned obj =
t.dynamicReturnMethod(ClassObjectWhichNeedsToBeReturned.class)
}
}
This has been tested using java 11
I have an issue with one of my class. I'm using a "varargs" constructor for unknown number of parameter.
public Groupe(String...nom){
for(String item:nom){
this.nom.add(item.toLowerCase());
}
}
public Groupe(String nom){
String[] list =nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The first constructor is called...that's fine, but there is a conflict when passing only ONE parameter with the second contructor. I would like to use the second constructor when passing only one string, and the first if 2 and more parameters.
I'd want to handle this
new Groupe("Foo,Bar");
This is where I call it. I suspect the "error" comes from there
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
I don't pass a String, but a Varargs (tab?)...
It should be fine, with the caveat that null can be converted to either String[] or String:
public class Test {
public Test(String single) {
System.out.println("Single");
}
public Test(String... multiple) {
System.out.println("Multiple");
}
public static void main(String[] args) {
new Test("Foo"); // Single
new Test("Foo", "Bar"); // Multiple
new Test(); // Effectively multiple
// new Test(null); // Doesn't compile - ambiguous
new Test((String) null); // Single
}
}
EDIT: Now that you've shown us the calling code, that's definitely the problem:
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
Here, the type of nom is String[] - so it will always call the first constructor. You've got an array of strings there - under what circumstances do you want to call the second constructor?
To be honest, given that the two constructors act significantly differently, I would actually make both constructors private, and provide static methods:
public static Groupe fromStringArray(String... nom)
public static Groupe fromCommaSeparatedString(String nom)
Then it will be absolutely clear what you're expecting in each case.
Maybe this can be a solution:
public Groupe(String...nom){
if (nom.length == 1) {
add(nom[0].split(","));
} else {
add(nom);
}
}
private void add(String[] list) {
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The varargs part can be empty. So you can get what you want with
public Groupe(String nom){
String[] list = nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
public Groupe(String nom1, String nom2, String...nom){
this.nom.add(nom1);
this.nom.add(nom2);
for(String item:nom)
this.nom.add(item.toLowerCase());
}
You could also, of course, use one ctor with an if statement on the length of the input array, splitting out cases 0 (not handled with the code above), 1, and > 1.
public class OverloadVarArgs {
public static void main(String... args){
OverloadVarArgs a = new OverloadVarArgs("One Argument");
OverloadVarArgs b = new OverloadVarArgs("Two", "Arguments");
OverloadVarArgs c = new OverloadVarArgs("One, Argument");
}
public OverloadVarArgs(String a){
System.out.println("Constructor 1");
}
public OverloadVarArgs(String... a){
System.out.println("Constructor 2");
}
}
Output:
Constructor 1
Constructor 2
Constructor 1
I have a string (which is a message) that I get as input and I need to do one of 4 possible things depending on the string
I know that there is eunm.valueOf() option, but I have 4 different enums, each with few possible messages.
looks something like:
public enum first{ONE,TWO,THREE};
public enum second{FOUR,FIVE,SIX};
public enum third{SEVEN,EIGHT,NINE};
public void work(String message){
//Here I want to compare message string to one of the 3 enums
}
is it possible to do this in one method of the enum?
or should I just try to create one, and if I get an exception try the other and so on?
As others have commented, it may be better to think through whether you really need 4 distinct enums.
But if you do, you could have them implement a common interface. Then you can map the input strings to the appropriate enum member, and call its method to accomplish what you want. Something like
public interface SomeInterface {
void doSomething();
};
public enum First implements SomeInterface {
ONE,TWO,THREE;
#Override
public void doSomething() { ... }
};
...
Map<String, SomeInterface> myMap = new HashMap<String, SomeInterface>();
for (First item : First.values()) {
myMap.put(item.toString(), item);
}
...
public void work(String message){
SomeInterface obj = myMap.get(message);
if (obj != null) {
obj.doSomething();
}
}
This assumes that the 4 possible things you want to do correspond to the 4 enums. If not, you can override the method separately for each and any enum member too, e.g.
public enum First implements SomeInterface {
ONE,
TWO {
#Override
public void doSomething() { // do something specific to TWO }
},
THREE;
#Override
public void doSomething() { // general solution for all values of First }
};
Enumerations in Java are full blown classes. Individual values can even override the behavior to meet their needs. It's pretty cool. You can use this to your advantage:
public enum Value implements Worker
{
ONE,
TWO,
THREE
{
#Override
public void doWork(String message)
{
// overrides behavior of base enum
}
},
FOUR,
/* ... */,
NINE;
private final String message;
Value() { this(""); }
Value(String message) { this.message = message; }
public void doWork(String message)
{
if (this.message.equals(message))
{
/* ... */
}
}
}
public interface Worker
{
void doWork(String message);
}
You can create a Map of them all
static final Map<String, Enum> enumMap = new LinkedHashMap<String, Enum>(){{
for(First e: First.values()) put(e.name(), e);
for(Second e: Second.values()) put(e.name(), e);
for(Third e: Third.values()) put(e.name(), e);
}};
Enum e = enumMap.get(name);
What you're really looking for is a aggregation of the other enums. The easiest way to get that is to make a new enum that puts all of those choices in a new enum. Something to this effect:
public enum Combination {
NEWONE(first.ONE), NEWTWO(first.TWO), NEWTHREE(first.THREE),
NEWFOUR(second.FOUR), NEWFIVE(second.FIVE), NEWSIX(second.SIX),
NEWSEVEN(third.SEVEN), NEWEIGHT(third.EIGHT), NEWNINE(third.NINE);
private String contents;
public Combination(first f) {
contents = f.toString();
}
public Combination(second s) {
contents = s.toString();
}
public Combination(third t) {
contents = t.toString();
}
public String toString() {
return contents;
}
}
This will more correctly aggregate the previous enums into a single data structure.
Even given your odd/even example in the comments, I don't feel multiple enums are the way to go here. I would use something like (warning, untested):
public enum Numbers {
ONE("first"), TWO("first"), THREE("first"), FOUR("second"), FIVE("second"), SIX("second"), SEVEN("third"), EIGHT("third"), NINE("third")
private String type;
Numbers(String t) { this.type = t; }
String getType { return this.type; }
}
Then you can use valueOf() to look up the enum element, and getType() to find out which of your three categories it belongs to.
It isn't entirely clear what you are asking, but perhaps you want to define a mapping between strings and constants, like this:
enum Type { FIRST, SECOND, THIRD };
Map<String, Type> mapping = new HashSet<String, Type>(){{
put("ONE", Type.FIRST);
put("TWO", Type.FIRST);
//...
put("NINE", Type.THIRD);
}};
public Type getTypeFromString(String s) {
return mapping.get(s);
}