I've got a simple Method that returns me always "-undefined-".
public static String getStereoType(Class<?> clazz) {
String result = "-undefined-";
if (clazz.isEnum()) {
result = "enum";
} else if (clazz.isInterface()) {
result = "interface";
} else if (clazz.isLocalClass() || clazz.isMemberClass()) {
result = "class";
}
return result;
}
When I call this Method with Object.class or Long.class always is the result "-undefined-".
List<Class<?>> superClazzes = ClassUtil.getSuperClazzList(clazz);
for (Class<?> c: superClazzess){
String stereoType = ClassUtil.getStereoType(c.getClass());
}
public static List<Class<?>> getSuperClazzList(Class<?> clazz) {
List<Class<?>> resultList = new ArrayList<Class<?>>();
Class<?> superClass = clazz.getSuperclass();
if (superClass != null) {
resultList.add(superClass);
resultList.addAll(getSuperClazzList(superClass));
}
return resultList;
}
What are you trying to get? So what are the possible stereo types you need? What I know of is:
Enum
Interface
Primitive (e.g. double, but not Double)
Class (everything else!)
And from the class API I can find that you might also differ between:
annotation (actual an interface in java)
synthetic (I'm not sure what this is)
local (defined inside a method)
But they might not be interesting for ULM diagrams at all.
Implementation of toString() from the JVM Class is:
public String toString() {
return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + getName();
}
This might give you some hint as well.
Hope it helps.
Edit: This should do the job:
public static String getStereoType(Class<?> clazz) {
String result = "class";
if (clazz.isEnum()) {
result = "enum";
} else if (clazz.isInterface()) {
result = "interface";
}
else if (clazz.isPrimitive()) {
result = "primitive";
}
return result;
}
To answer the question in your title, isLocalClass() does not always return false: it returns true for types declared within a method. Similarly, isMemberClass() returns true for types declared within another type.
Consider:
public class Outer {
interface MemberClass {}
public static void main(String[] args) {
class LocalClass {}
System.out.printf(
"%s/%s%n",
LocalClass.class.isLocalClass(),
LocalClass.class.isMemberClass()
);
System.out.printf(
"%s/%s%n",
MemberClass.class.isLocalClass(),
MemberClass.class.isMemberClass()
);
}
}
This code, when executed, prints out true/false followed by false/true. Together, they only account for types which are defined within another class, or within a method. Neither strictly depends on the target type being a class as opposed to an interface or enum, so you cannot use it to filter that way.
See #Tarion's excellent answer for the approach you should be taking (and accept his answer, as it more completely solves your problem).
Related
public void etisLogAround(ProceedingJoinPoint joinPoint, EtisLog etisLog) throws Throwable {
Object[] args = joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature) joinPoint.getStaticPart().getSignature();
Method method = methodSignature.getMethod();
String[] paramNames = ((MethodSignature) joinPoint
.getSignature()).getParameterNames();
for(String paramName: paramNames) {
logger.info("paramName:" +paramName);
}
try {
Object result = joinPoint.proceed();
if(methodSignature instanceof MethodSignature) {
final Class<?>[] parameterTypes = methodSignature.getParameterTypes();
for(final Class<?> pt : parameterTypes){
logger.info("Parameter type:" + pt);
}
}
#SuppressWarnings("unchecked")
ResponseEntity<CaseOutlineHeader> returnValue = (ResponseEntity<CaseOutlineHeader>) result;
result = etisLog.trasactionDetail().toString()+" "+returnValue.getBody().getCode().toString();
} catch (IllegalArgumentException e) {
throw e;
}
}
The class CaseOutlineHeader is what I want to be changed. the parameterTypes variable contains the name of the class that I would like to pass inside the tag of the ResponseEntity<>. What if I would like to pass a different class Name. How should I do that to be flexible to accept the different class name?
If i do : ResponseEntity<parameterTypes> returnValue = (ResponseEntity<parameterTypes>) result;
it will say an error parameterTypes cannot be resolved to a type.
The problem is that your AOP method need to cast the result to something in order to get the code value it needs to log. That something must be known in advance, since you can't use type parameters in annotations, and therefore can't pass it to AOP methods. This means that all methods you access in AOP must come from a known interface, like this:
public interface LogCodeProvider {
String getLogCode();
}
public class CaseOutlineHeader implements LogCodeProvider {
#Override
public String getLogCode() {
return "My Code";
}
}
And then in your AOP method you can do like this:
#SuppressWarnings("unchecked")
ResponseEntity<LogCodeProvider> returnValue = ResponseEntity<LogCodeProvider>) result;
result = etisLog.trasactionDetail().toString()+" "+returnValue.getBody().getLogCode();
In my example I have implemented special method getLogCode() which returns a string, so each class can decide exactly what to output.
It does however look confusing to reuse the result variable to store the value returned from etisLog.trasactionDetail().
Below sample code ,
ResponseEntity<?> anyRandomMethod(){
if(any condition){
return new ResponseEntity<Animal>(new Animal(), httpstatus.OK);
}else{
return new ResponseEntity<SpaceShip>(new SpaceShip(), httpstatus.OK);
}
}
Caller:
switch (type){
case "creature":
Creature returnActor2 = getNextCreature();
boolean isEat2 = actOnNearby(getRightChromosome(Config.HardCode.creature), returnActor2.getLocation());
if (isEat2) {
actOnCreature(returnActor2);
}
break;
case "monster":
Monster returnActor3 = getNextMonster();
boolean isEat3 = actOnNearby(getRightChromosome(Config.HardCode.monster), returnActor3.getLocation());
if (isEat3) {
actOnMonster(returnActor3);
}
break;
}
It will call the following 2 methods:
private Monster getNextMonster() {
ArrayList<Actor> nearbyActors = getActors();
Monster mine = new Monster();
for (Actor a : nearbyActors) {
if (a instanceof Monster) {
mine = (Monster) a;
}
}
return mine;
}
private Creature getNextCreature() {
ArrayList<Actor> nearbyActors = getActors();
Creature mine = new Creature();
for (Actor a : nearbyActors) {
if (a instanceof Creature) {
mine = (Creature) a;
}
}
return mine;
}
The question
As you can see, the getNextXXXXX() method are pretty the same, just return different object, the logic is same, how to DRY? the actOnXXXX() seems falls in the DRY category as well, but it all about the same, use same logic against different object. How to solve this?
Make it accept a classtype:
private <T> T getNext(Class<T> type) {
for (Actor a : getActors()) {
if (type.isAssignableFrom(a.getClass())) {
return (T) a;
}
}
return null; //or type.newInstance(); if you want a guaranteed object, but this restricts your constructor.
}
Or with Java 8:
private <T> T getNext(Class<T> type) {
return (T) getActors().stream()
.filter(a -> type.isAssignableFrom(a.getClass()))
.findFirst().orElse(null);
}
But the usage is the same:
Monster next = getNext(Monster.class);
Breaking down the problem, you know two categories of things:
What you need:
A next object of t type.
A way of determining if an object is t
type
What you have:
The type t you want
A collection of objects, one of which might be t type
A new object via a no-args constructor (or null) if none are there
Additionally, the only variance between all these methods is one thing: Which type it is. So we literally "make that a variable", and as such it becomes a method parameter.
Breaking this down we simply need to organize the code in a manner which accomplishes this:
method: //receives a "type" as a parameter
iterate the list of possible `t`s //our list of objects
if some_t == type //our comparison, previously `a instanceof Type`
return some_t //our result is found
return null //or a new object, but essentially our "default"
The only primary differences here were:
Replacing some_t instanceof Type with type.isAssignableFrom(some_t.getClass())
Reason being here that this is simply how you determine this when using Class<T>
Our default can either be null or a new object
Making the object dynamically via reflection restricts your options and has exceptions to deal with. Returning null or an empty Optional<T> would help signify that you did not have a result, and the caller can act accordingly. You could potentially also just pass the default object itself, and then go back to the instanceof check.
Asking yourself this same hypothesis of "what do I need, and what can I provide/have", will help you map out breaking down the problem into smaller steps, and solving the larger puzzle.
I think, there is a confusion in your code and logic.
FOr example, if you need to iterate on list, you dont need to create a new object. That is, in the following code snippet, "new Monster()" doesn't need to be written
Monster mine = null; // new Monster();
for (Actor a : nearbyActors) {
if (a instanceof Monster) {
mine = (Monster) a;
}
}
Anyway, the answer is the "Type Inference in Java."
https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
The answer to your question is
package __TypeInference;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
new Main().doLogic();
}
private void doLogic() {
List<Actor> nearbyActors = getActors();
for (Actor actor : nearbyActors) {
// do with the next actor
System.out.println(actor.toString());
}
}
private List<Actor> getActors() {
List<Actor> actors = new ArrayList<Actor>();
actors.add(new Monster());
actors.add(new Creature());
actors.add(new Monster());
actors.add(new Creature());
return actors;
}
class Monster extends Actor {
#Override
public String toString() {
return "Monster";
}
}
class Creature extends Actor {
#Override
public String toString() {
return "Creatue";
}
}
class Actor {
}
}
I think what you want is to combine getNextMonster and getNextCreature because they have repeated code.
The best thing to do here is to write a generic method that does this:
private <T extends Actor> T getNextActor(T newActor) {
ArrayList<Actor> nearbyActors = getActors();
T mine = newActor;
for (Actor a : nearbyActors) {
if (a instanceof T) {
mine = (T) a;
}
}
return mine;
}
And you can call it like this:
// This is equivalent to calling getNextCreature()
getNextActor(new Creature());
// This is equivalent to calling getNextMonster()
getNextActor(new Monster());
Let me explain the code.
The new method returns a type of Actor. You tell it what kind of actor you want by passing the argument. The argument is necessary because you cannot just initialize a generic type argument like this:
new T();
Because the parameterless constructor might not be available. So that's the job of the caller.
I don't really know what I'm talking about...
This method has the following advantages:
It reduces repeated code
It is flexible - when you want to add another method called getNextXXX (where XXX is a subclass of Actor), you don't need to. Just call getNextActor(new XXX())!
It increases maintainability - if you want to change the implementation of getNextXXX, you can just change one method instead of 2.
I am trying to get method regardless of what parameters that method takes (as of now there is no method overloading and there wouldn't be in future). The only possible solution that i could come up with was
private Method getMethod(Class<?> clas, String methodName) {
try {
Method[] methods = clas.getMethods();
for (Method method : methods) {
if (method.getName().equalsIgnoreCase(methodName)) {
return method;
}
}
} catch (SecurityException e) {
e.printStackTrace();
}
return null;
}
What i want to ask that is there a way to fetch a method regardless of its parameters ? I was looking at clas.getMethod ("methodName", parameters) and if i provide null in there it will try to fetch a method which has no parameters. Which wouldn't be no case.
Any ideas ?
EDIT
Thanks guys for input. In my case, i know that there would be only one method regardless of its case. The reason i am using ignoreCase is because the input will be coming from a developer (in other team) and he will be providing the name as a hard-coded string. So to keep things from spilling out of our hands, I am using a safe approach.
No. The way you've done it is the way to go. A method is identified by its signature and the signature includes the name and the parameter types.
Here is a solution that retrieves all methods with the specified class and method name regardless of the method's parameters:
public class Test
{
private class Foo
{
public void bar()
{
}
public void bar(String s)
{
}
public void goo()
{
}
}
private static Method[] getMethods(Class<?> clazz, String methodName)
{
List<Method> methods = new ArrayList<Method>();
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod: declaredMethods)
{
if (declaredMethod.getName().equals(methodName))
{
methods.add(declaredMethod);
}
}
return methods.toArray(new Method[methods.size()]);
}
public static void main(String[] args)
{
Method[] methods = getMethods(Foo.class, "bar");
System.out.println(Arrays.toString(methods));
}
}
This generates the following output:
[public void com.example.Test$Foo.bar(java.lang.String), public void com.example.Test$Foo.bar()]
You've done just fine. This is basically the same as the solution to a similar problem I dealt with four years ago, creating a means to create callback methods in Java. The constructors for my Callback class were:
public Callback(Class<?> clazz, String methodName, Object parentObj) {
// Find a method with the matching name
Method[] allMethods;
try { allMethods = clazz.getMethods(); }
catch(SecurityException se) { allMethods = new Method[0]; }
int count = 0;
Method single = null;
for(Method m : allMethods) {
if(m.getName().equals(methodName)) {
single = m;
count++;
}
// Can't have more than one instance
if(count > 1)
throw new IllegalArgumentException(clazz.getName()
+ " has more than one method named " + methodName);
}
if(count == 0) // No instances found
throw new IllegalArgumentException(clazz.getName()
+ " has no method named " + methodName);
this.parentObj = parentObj;
this.method = single;
this.parameters = single.getParameterTypes();
}
public Callback(
Class<?> clazz,
String methodName,
Object parentObj,
Class<?>...parameters)
{
try { this.method = clazz.getMethod(methodName, parameters); }
catch(NoSuchMethodException nsme) { nsme.printStackTrace(); }
catch(SecurityException se) { se.printStackTrace(); }
this.parentObj = parentObj;
this.parameters = parameters;
}
My Callback class isn't really useful any more in the era of Java 8, but at the time the only real means for a "callback" in java was anonymous interface implementations, which wasn't sufficient for my use-case.
As you can see in the first constructor, it throws an exception if it finds multiple methods with the same name.
Using java streams there is a really short method of finding a method, the first match, by its name only:
Stream.of(type.getMethods())
.filter((m) -> m.getName().equals(searchedName))
.findFirst()
.get();
I think this is a short and readable possibility in this case.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Anything wrong with instanceof checks here?
I have this code
public static int getNumberOfOwned(Player owner, String type){
int count = 0;
for (Field f: board.fieldList)
if (type == "Shipping" && f instanceof Shipping)
if (((Shipping)f).getOwnedBy() == owner)
count++;
else if (type == "Brewery" && f instanceof Brewery)
if (((Brewery)f).getOwnedBy() == owner)
count++;
return count;
}
I don't think this is very elegant and future proof. How can i avoid those instanceof operators.
You can always use an enum, and use a method on Field which returns the type. Here I'll go a little further and surmise that you do not want to update the count for certain types, so the enum is also "adorned" with a boolean expressing that:
enum FieldType {
SHIPPING(true),
BREWERY(true),
NOTME(false);
private final boolean countUpdate;
FieldType(boolean countUpdate) { this.countUpdate = countUpdate; }
public boolean mustUpdateCount() { return countUpdate; }
};
abstract class Field {
protected final FieldType type;
protected Field(FieldType type) { this.type = type; }
public final FieldType getType() { return type; }
public final boolean mustUpdateCount() { return type.mustUpdateCount(); }
}
class Brewery implements Field {
Brewery() {
super(BREWERY);
}
}
and in your code:
FieldType expectedType = Enum.valueOf(type.toUpperCase());
for (Field f: board.fieldlist) {
if (field.getType() != expectedType)
continue;
if (!f.getOwnedBy().equals(owner))
continue;
// Correct type, owned by the correct guy:
// check that we must update; if so, update
if (expectedType.mustUpdateCount())
count++;
}
Since Shipping and Brewery are derived from Field, Field could provide a getter that tells you its type, something like getFieldType(). When Shipping or Brewery are instantiated, they set the appropriate value, or you make getFieldType() abstract and have Shipping and Brewery implement them.
Pass Shipping.class or Brewery.class to your function instead of a string representing the class and check that your Field belongs to that class:
public static int getNumberOfOwned(Player owner, Class<? extends Field> type){
int count = 0;
for (Field f: board.fieldList) {
if (type.isInstance(f) && f.getOwnedBy() == owner) {
count++;
}
}
return count;
}
The best solution would be to use the visitor pattern for this problem, you can look it up here: Visitor pattern
At least it's the object oriented way of handling the problem, but it certainly needs more coding than your current solution.
Add an "isType(String type)" method to Field. For that matter, add "isOwnedBy(String owner)" to Field as well.
for (Field f: board.fieldList)
if (f.isType(type) && f.isOwnedBy(owner))
count++;
return count;
first of all be advice you are using the "==" operator to test the equality of objects, this is most of the the times wrong, and definitely wrong in this case :)
If you want to determine if an object is of an particular type you could use the instanceof operator, see if they have the same class reference (here you could use the "==" operator) or try a cast and check for an exception, the last option is more of a fantasy because in the real world you should not try this.
I am not quite sure what you are trying to do, but you could definitely tailor your objects to avoid the instanceof/class/cast stuff, something like:
class Foxtrot implements Sub {
private SubType type = SubType.ATACK;
public SubType getType() {
return type;
}
}
interface Sub {
enum SubType{ ATACK, BOOMER }
public SubType getType();
}
And you can treat object as implementations of the Sub interface and check with their getType() method what kind they are, it should pretty much work.
You should rewrite this code
1)
class Field
add method getType();
2) code:
public static int getNumberOfOwned(Player owner, String type){
int count = 0;
for (Field f: board.fieldList){
if (f.getType.equals(type)&& f.getOwnedBy().equesl(owner))
count++;
}
return count;
}
Make string getTypeString() a property of Field, and avoid having a bunch of if statements (check type.equals(f.getTypeString())) Make getOwnedBy a property of Field, and don't use a cast. (fields that don't have owners can return null)
What specification supports optional parameters?
There are several ways to simulate optional parameters in Java:
Method overloading.
void foo(String a, Integer b) {
//...
}
void foo(String a) {
foo(a, 0); // here, 0 is a default value for b
}
foo("a", 2);
foo("a");
One of the limitations of this approach is that it doesn't work if you have two optional parameters of the same type and any of them can be omitted.
Varargs.
a) All optional parameters are of the same type:
void foo(String a, Integer... b) {
Integer b1 = b.length > 0 ? b[0] : 0;
Integer b2 = b.length > 1 ? b[1] : 0;
//...
}
foo("a");
foo("a", 1, 2);
b) Types of optional parameters may be different:
void foo(String a, Object... b) {
Integer b1 = 0;
String b2 = "";
if (b.length > 0) {
if (!(b[0] instanceof Integer)) {
throw new IllegalArgumentException("...");
}
b1 = (Integer)b[0];
}
if (b.length > 1) {
if (!(b[1] instanceof String)) {
throw new IllegalArgumentException("...");
}
b2 = (String)b[1];
//...
}
//...
}
foo("a");
foo("a", 1);
foo("a", 1, "b2");
The main drawback of this approach is that if optional parameters are of different types you lose static type checking. Furthermore, if each parameter has the different meaning you need some way to distinguish them.
Nulls. To address the limitations of the previous approaches you can allow null values and then analyze each parameter in a method body:
void foo(String a, Integer b, Integer c) {
b = b != null ? b : 0;
c = c != null ? c : 0;
//...
}
foo("a", null, 2);
Now all arguments values must be provided, but the default ones may be null.
Optional class. This approach is similar to nulls, but uses Java 8 Optional class for parameters that have a default value:
void foo(String a, Optional bOpt) {
Integer b = bOpt.isPresent() ? bOpt.get() : 0;
//...
}
foo("a", Optional.of(2));
foo("a", Optional.absent());
Optional makes a method contract explicit for a caller, however, one may find such signature too verbose.
Update: Java 8 includes the class java.util.Optional out-of-the-box, so there is no need to use guava for this particular reason in Java 8. The method name is a bit different though.
Builder pattern. The builder pattern is used for constructors and is implemented by introducing a separate Builder class:
class Foo {
private final String a;
private final Integer b;
Foo(String a, Integer b) {
this.a = a;
this.b = b;
}
//...
}
class FooBuilder {
private String a = "";
private Integer b = 0;
FooBuilder setA(String a) {
this.a = a;
return this;
}
FooBuilder setB(Integer b) {
this.b = b;
return this;
}
Foo build() {
return new Foo(a, b);
}
}
Foo foo = new FooBuilder().setA("a").build();
Maps. When the number of parameters is too large and for most of the default values are usually used, you can pass method arguments as a map of their names/values:
void foo(Map<String, Object> parameters) {
String a = "";
Integer b = 0;
if (parameters.containsKey("a")) {
if (!(parameters.get("a") instanceof Integer)) {
throw new IllegalArgumentException("...");
}
a = (Integer)parameters.get("a");
}
if (parameters.containsKey("b")) {
//...
}
//...
}
foo(ImmutableMap.<String, Object>of(
"a", "a",
"b", 2,
"d", "value"));
In Java 9, this approach became easier:
#SuppressWarnings("unchecked")
static <T> T getParm(Map<String, Object> map, String key, T defaultValue) {
return (map.containsKey(key)) ? (T) map.get(key) : defaultValue;
}
void foo(Map<String, Object> parameters) {
String a = getParm(parameters, "a", "");
int b = getParm(parameters, "b", 0);
// d = ...
}
foo(Map.of("a","a", "b",2, "d","value"));
Please note that you can combine any of these approaches to achieve a desirable result.
varargs could do that (in a way). Other than that, all variables in the declaration of the method must be supplied. If you want a variable to be optional, you can overload the method using a signature which doesn't require the parameter.
private boolean defaultOptionalFlagValue = true;
public void doSomething(boolean optionalFlag) {
...
}
public void doSomething() {
doSomething(defaultOptionalFlagValue);
}
There is optional parameters with Java 5.0. Just declare your function like this:
public void doSomething(boolean... optionalFlag) {
//default to "false"
//boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}
you could call with doSomething(); or doSomething(true); now.
You can use something like this:
public void addError(String path, String key, Object... params) {
}
The params variable is optional. It is treated as a nullable array of Objects.
Strangely, I couldn't find anything about this in the documentation, but it works!
This is "new" in Java 1.5 and beyond (not supported in Java 1.4 or earlier).
I see user bhoot mentioned this too below.
There are no optional parameters in Java. What you can do is overloading the functions and then passing default values.
void SomeMethod(int age, String name) {
//
}
// Overload
void SomeMethod(int age) {
SomeMethod(age, "John Doe");
}
VarArgs and overloading have been mentioned. Another option is a Bloch Builder pattern, which would look something like this:
MyObject my = new MyObjectBuilder().setParam1(value)
.setParam3(otherValue)
.setParam6(thirdValue)
.build();
Although that pattern would be most appropriate for when you need optional parameters in a constructor.
In JDK>1.5 you can use it like this;
public class NewClass1 {
public static void main(String[] args) {
try {
someMethod(18); // Age : 18
someMethod(18, "John Doe"); // Age & Name : 18 & John Doe
} catch (Exception e) {
e.printStackTrace();
}
}
static void someMethod(int age, String... names) {
if (names.length > 0) {
if (names[0] != null) {
System.out.println("Age & Name : " + age + " & " + names[0]);
}
} else {
System.out.println("Age : " + age);
}
}
}
You can do thing using method overloading like this.
public void load(String name){ }
public void load(String name,int age){}
Also you can use #Nullable annotation
public void load(#Nullable String name,int age){}
simply pass null as first parameter.
If you are passing same type variable you can use this
public void load(String name...){}
Short version :
Using three dots:
public void foo(Object... x) {
String first = x.length > 0 ? (String)x[0] : "Hello";
int duration = x.length > 1 ? Integer.parseInt((String) x[1]) : 888;
}
foo("Hii", );
foo("Hii", 146);
(based on #VitaliiFedorenko's answer)
Overloading is fine, but if there's a lot of variables that needs default value, you will end up with :
public void methodA(A arg1) { }
public void methodA(B arg2) { }
public void methodA(C arg3) { }
public void methodA(A arg1, B arg2) { }
public void methodA(A arg1, C arg3) { }
public void methodA(B arg2, C arg3) { }
public void methodA(A arg1, B arg2, C arg3) { }
So I would suggest use the Variable Argument provided by Java.
You can use a class that works much like a builder to contain your optional values like this.
public class Options {
private String someString = "default value";
private int someInt= 0;
public Options setSomeString(String someString) {
this.someString = someString;
return this;
}
public Options setSomeInt(int someInt) {
this.someInt = someInt;
return this;
}
}
public static void foo(Consumer<Options> consumer) {
Options options = new Options();
consumer.accept(options);
System.out.println("someString = " + options.someString + ", someInt = " + options.someInt);
}
Use like
foo(o -> o.setSomeString("something").setSomeInt(5));
Output is
someString = something, someInt = 5
To skip all the optional values you'd have to call it like foo(o -> {}); or if you prefer, you can create a second foo() method that doesn't take the optional parameters.
Using this approach, you can specify optional values in any order without any ambiguity. You can also have parameters of different classes unlike with varargs. This approach would be even better if you can use annotations and code generation to create the Options class.
If it's an API endpoint, an elegant way is to use "Spring" annotations:
#GetMapping("/api/foos")
#ResponseBody
public String getFoos(#RequestParam(required = false, defaultValue = "hello") String id) {
return innerFunc(id);
}
Notice in this case that the innerFunc will require the variable, and since it's not api endpoint, can't use this Spring annotation to make it optional.
Reference: https://www.baeldung.com/spring-request-param
Java now supports optionals in 1.8, I'm stuck with programming on android so I'm using nulls until I can refactor the code to use optional types.
Object canBeNull() {
if (blah) {
return new Object();
} else {
return null;
}
}
Object optionalObject = canBeNull();
if (optionalObject != null) {
// new object returned
} else {
// no new object returned
}
This is an old question maybe even before actual Optional type was introduced but these days you can consider few things:
- use method overloading
- use Optional type which has advantage of avoiding passing NULLs around
Optional type was introduced in Java 8 before it was usually used from third party lib such as Google's Guava. Using optional as parameters / arguments can be consider as over-usage as the main purpose was to use it as a return time.
Ref: https://itcodehub.blogspot.com/2019/06/using-optional-type-in-java.html
Default arguments can not be used in Java. Where in C#, C++ and Python, we can use them..
In Java, we must have to use 2 methods (functions) instead of one with default parameters.
Example:
Stash(int size);
Stash(int size, int initQuantity);
http://parvindersingh.webs.com/apps/forums/topics/show/8856498-java-how-to-set-default-parameters-values-like-c-
We can make optional parameter by Method overloading or Using DataType...
|*| Method overloading :
RetDataType NameFnc(int NamePsgVar)
{
// |* Code Todo *|
return RetVar;
}
RetDataType NameFnc(String NamePsgVar)
{
// |* Code Todo *|
return RetVar;
}
RetDataType NameFnc(int NamePsgVar1, String NamePsgVar2)
{
// |* Code Todo *|
return RetVar;
}
Easiest way is
|*| DataType... can be optional parameter
RetDataType NameFnc(int NamePsgVar, String... stringOpnPsgVar)
{
if(stringOpnPsgVar.length == 0) stringOpnPsgVar = DefaultValue;
// |* Code Todo *|
return RetVar;
}
If you are planning to use an interface with multiple parameters,
one can use the following structural pattern and implement or override apply - a method based on your requirement.
public abstract class Invoker<T> {
public T apply() {
return apply(null);
}
public abstract T apply(Object... params);
}