I am trying to create a method reference with the variable, which holds method name for some method from an object:
SomeClass obj = new SomeClass();
String methodName = "someMethod";
I am looking for way to create exactly obj::someMethod, but using variable methodName for this. Is it possible?
I know how to create functional interface instance from methodName and obj:
() -> {
try {
return obj.getClass().getMethod(methodName).invoke(obj);
} catch (NoSuchMethodException | IllegalAccessException e) {
return null;
}
};
but I am wondering is this can be done in more shorthand way.
If you strive for brevity rather than performance, there are Expression and Statement since Java 1.4.
Object obj="example";
String methodName="substring";
Object[] arg={ 2, 5 };
try {
Object result=new Expression(obj, methodName, arg).getValue();
new Statement(System.out, "println", new Object[]{ result }).execute();
} catch (Exception ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
}
But if you want to use them in the context of the standard function interfaces, which don’t allow checked exceptions, the exception handling will dominate the source code.
You can bind a reflectively acquired method to a functional interface even under Java 7:
Object obj="example";
String methodName="substring";
Object[] arg={ 2, 5 };
Supplier<String> s;
Consumer<String> c;
try {
MethodHandle mh=MethodHandles.insertArguments(
MethodHandles.lookup().bind(obj, methodName,
MethodType.methodType(String.class, int.class, int.class)),
0, arg);
s = MethodHandleProxies.asInterfaceInstance(Supplier.class, mh);
mh=MethodHandles.lookup().bind(System.out, "println",
MethodType.methodType(void.class, String.class));
c = MethodHandleProxies.asInterfaceInstance(Consumer.class, mh);
} catch(NoSuchMethodException | IllegalAccessException ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return;
}
String result=s.get();
c.accept(result);
This is not shorter, but avoids performing the reflective lookup in each function evaluation.
Potentially more efficient is to use the LambdaMetafactory introduced in Java 8, which is the back-end of the lambda expressions and method references at runtime.
Object obj="example";
String methodName="substring";
Object[] arg={ 2, 5 };
Supplier<String> s;
Consumer<String> c;
try {
final MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh=lookup.findVirtual(String.class, methodName,
MethodType.methodType(String.class, int.class, int.class));
s = (Supplier<String>)LambdaMetafactory.metafactory(lookup, "get",
mh.type().changeReturnType(Supplier.class),
MethodType.methodType(Object.class), mh, MethodType.methodType(String.class))
.getTarget().bindTo(obj).invokeWithArguments(arg);
mh=MethodHandles.lookup().findVirtual(PrintStream.class, "println",
MethodType.methodType(void.class, String.class));
c = (Consumer<String>)LambdaMetafactory.metafactory(lookup, "accept",
MethodType.methodType(Consumer.class, PrintStream.class),
MethodType.methodType(void.class, Object.class), mh,
MethodType.methodType(void.class, String.class))
.getTarget().bindTo(System.out).invokeExact();
} catch(Throwable ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return;
}
String result=s.get();
c.accept(result);
This has a higher creation complexity, but the subsequent execution of the functions will have an efficiency on par with compile-time method references as there is no technical difference anymore.
This is a very rare case - it's highly unlikely that the Java8 syntax sugar has been optimised for this. In particular, it would be impossible for the usual compile-time type checking to occur (remember that a method reference is just syntax sugar for an anonymous class that adheres to a particular type contract).
If this pattern is common in your codebase (hopefully it's not!), you could just move it to, say, a static utility method, and then do () -> Utils.invoke(obj, methodName).
Related
While trying out the multi-catch feature I found in my m1() method everything is working fine as expected.
However, in m2() the same code does not compile. I have just changed the syntax to reduce the number of lines of code.
public class Main {
public int m1(boolean bool) {
try {
if (bool) {
throw new Excep1();
}
throw new Excep2();
//This m1() is compiling abs fine.
} catch (Excep1 | Excep2 e) {
return 0;
}
}
public int m2(boolean b) {
try {
throw b ? new Excep1() : new Excep2();
//This one is not compiling.
} catch (Excep1 | Excep2 e) {
return 0;
}
}
private static interface I {
}
private static class Excep1 extends Exception implements I {
}
private static class Excep2 extends Exception implements I {
}
}
Why doesn't method m2() compile?
The type of the expression
b ? new Excep1() : new Excep2()
is Exception, since that's the common supertype of Excep1 and Excep2.
However, you are not catching Exception, so the compiler complains about it.
If you catch Exception, it will pass compilation:
public int m2(boolean b) {
try {
throw b ? new Excep1() : new Excep2();
} catch (Exception e) {
return 0;
}
}
I tried to find the JLS entry that explains the type of conditional ternary expression in your example.
All I could find was that this particular expression is a 15.25.3. Reference Conditional Expression.
I'm not entirely sure if it counts as a poly expression or a standalone expression. I think it's standalone (since poly expressions involve an assignment context or an invocation context, and I don't think a throw statement counts as either of those).
For a standalone expression: "If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression."
In your case, the second and third operands have three common types - Object, Throwable and Exception - the type of the expression must be one of the latter two, since, "The Expression in a throw statement must either denote a variable or value of a reference type which is assignable (§5.2) to the type Throwable."
It appears that the compiler picks the most specific common type (Exception), and therefore a catch (Exception e) solves the compilation error.
I also tried to replace your two custom exceptions with two sub-classes of IOException, in which case catch (IOException e) solves the compilation error.
You're confusing the compiler with this line:
throw b ? new Excep1() : new Excep2();
The compiler sees that the result of the expression (to the right of the throw) is the common super class between Except1 and Except2, which is Exception, and therefore the effective type you are throwing becomes Exception. The catch statement cannot pick up that you're trying to throw Excep1 or Except2.
Java restrict you to catch or declare all exception types that method can throws,
It search for common parent for both (/all) Exceptions and expect you to catch or declare as throws, for example if Excep1 extends Throwable you will have to catch also Throwable
In first case Java is sure you are either throwing Excep1 or Excep2
I can't figure out how to factor out this code.
private CompletionStage<Response<String>> foo(RequestContext rc) {
final Optional<String> campaignIdOpt = rc.request().parameter("campaignId").filter(s -> !s.isEmpty());
final Optional<String> creativeIdOpt = rc.request().parameter("creativeId").filter(s -> !s.isEmpty());
Optional<Uuid> campaignIdOptOfUuid = Optional.empty();
if (campaignIdOpt.isPresent()) {
try {
campaignIdOptOfUuid = Optional.of(UuidUtils.fromString(campaignIdOpt.get()));
} catch (IllegalArgumentException e) {
LOG.error(String.format("Invalid campaignId: %s", campaignIdOpt.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST.withReasonPhrase("Invalid campaignId provided.")));
}
}
Optional<Uuid> creativeIdOptOfUuid = Optional.empty();
if (creativeIdOpt.isPresent()) {
try {
creativeIdOptOfUuid = Optional.of(UuidUtils.fromString(creativeIdOpt.get()));
} catch (IllegalArgumentException e) {
LOG.error(String.format("Invalid creativeId: %s", creativeIdOpt.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST.withReasonPhrase("Invalid creativeId provided.")));
}
}
// Simplified, do something with Uuids.
return bar(campaignIdOptOfUuid, creativeIdOptOfUuid);
}
Basically, we very frequently need to parse Google protobuf Uuids from a query string to pass on to another service that will find (or not find). We need to pass along an empty optional if a parameter was not set or an empty string, as both cases mean, "Don't filter by this parameter." Finally, if the string doesn't parse at all, then we want to immediately return an error 400 (Bad Request), rather than pass along a non-sense param to the service.
So, codewise, I want a utility method that
takes an Optional<String>, and
returns an Optional<Uuid> if present, Optional.empty() otherwise, and
if an exception is thrown, return an error from the original context.
But obviously, I can't "double-return." What pattern do I use to achieve this though? I tried to create an encapsulator for both an Optional<Uuid> and a CompletionStage<Response<String>> but it was awkward. Is there some idiomatic way of doing this?
You can use a loop. A loop allows you to handle all elements equally, thus removing the code duplication, while still allowing to return immediately:
private CompletionStage<Response<String>> foo(RequestContext rc) {
String[] parameters = {"campaignId", "creativeId" };
List<Optional<Uuid>> uuids = new ArrayList<>(parameters.length);
for(String param: parameters) {
Optional<String> o1 = rc.request().parameter(param).filter(s -> !s.isEmpty());
Optional<Uuid> o2;
try {
o2 = o1.map(UuidUtils::fromString);
} catch(IllegalArgumentException e) {
LOG.error(String.format("Invalid %s: %s", param, o1.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST
.withReasonPhrase("Invalid "+param+ " provided.")));
}
uuids.add(o2);
}
// Simplified, do something with Uuids.
return bar(uuids.get(0), uuids.get(1));
}
Otherwise, you would need to create a method returning an object holding two alternative results (like Either); the JDK does not provide such a type yet. A method could simply throw on an erroneous condition but that would bring you back to square one when the common code is mostly the exception handling.
Note that calling Optional.map on an empty optional will already return an empty optional, without evaluating the provided function, so you don’t need to check via ifPresent, etc.
Background:
I have hundreds of XXXFaultMsg classes generated from a WSDL file, they all have a method getFaultMsg() but they are extended from Exception directly. I have a function with argument Exception e, where e might be instance of one of the XXXFaultMsg classes.
Challenge:
I want to invoke getFaultMsg() on e if it is an instance of XXXFaultMsg.
I have written if (e.getClass().getName().endsWith("FaultMsg")) to detect whether e is an instance of XXXFaultMsg. Then how can I declare a var with type XXXFaultMsg and cast e to it and call getFaultMsg() on it?
P.S. I don't want to construct a long list of if (e instanceof XXXFaultMsg) cause there are over 100 XXXFaultMsg classes.
Say you have one method which takes no args:
Method methodToFind = null;
if (e.getClass().getName().endsWith("FaultMsg")){
try {
methodToFind = e.getClass().getMethod("getFaultMsg", (Class<?>[]) null);
} catch (NoSuchMethodException | SecurityException e) {
// Your exception handling goes here
}
}
Invoke it if present:
if(methodToFind == null) {
// Method not found.
} else {
// Method found. You can invoke the method like
methodToFind.invoke(e, (Object[]) null);
}
I'm beginning with Java 8 and I was wondering if I can convert a loop with a try-catch clause, into a lambda function?
Below is the method code I would like to convert into:
for (File f: files) {
JSONOject obj;
try (FileWriter fw= new FileWriter("path.csv")) {
obj= (JSONObject) parser.parse(new FileWriter(f));
readOBJ(valueType,results,obj);
results.put(day, new JobClass(day,work, time,description));
Date d= results.keySet();
Calendar c= Calendar.getinstance();
c.setTime(d);
Map<Date, JobClass> daysList= new HashMap<>();
j.insertDaysList(results,c,fw,daysList);
results.putAll(daysList);
j.resSort(results,resDayList);
} catch (IOException ex) {
e.printStacktrace();
}
}
return resDaysList;
Assuming it's the files iteration you want to convert to a Stream, that can easily be done. At the moment, your loop contents don't even throw uncaught exceptions, so there's no difficulty here (though I would suggest refactoring it into its own method first).
As lambda expressions in Java are just a means to conveniently provide implementations of single-abstract-method (SAM) interfaces as anonymous objects and the standard Stream interface offers the forEach() method for internal iteration, you can encapsulate pretty much everything you want to within your expression.
forEach(Consumer<? super T> action) expects you to provide it with an object of the Consumer interface, which need only have one method implementation consuming an object of any kind and returning no value.
So you simply put the code within your loop into the expression (or, as already proposed, transfer it into it's own method first) and you're done. The only thing you'll need to think about is how to treat your return statement, as it's not possible to return values from within the forEach() method (due to it being a so called "terminal" method of return type void). But you'll be able to pass your list into the lambda expression, modify your values in any way you see fit and keep working with it after the lambda is done, without any problem.
The try-catch-block does not affect the lambda expression itself. After all, the following two segments of code are equivalent:
List<String> someList = Arrays.asList("example", "of", "lambda", "code");
// lambda style
someList.stream().forEach( item -> {
try {
System.out.println(item.toString());
} catch (Exception e) {
e.printStackTrace();
}
});
// anonymous object style
someList.stream().forEach(new Consumer<String>() {
#Override
public void accept(String s) {
try {
System.out.println(item.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
Two questions regarding the MethodHandle class:
Is it true that every call to invokeExact() requires type casting of the return value (except for target methods that return void or Object) ?
It seems that a MethodHandle can only be bound once to a receiver. Given an arbitrary MethodHandle instance, is there any way to determine whether it has already been bound and if so, to what type?
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle handle = lookup.bind(new Object(), "toString", MethodType.methodType(String.class));
String s = (String) handle.invokeExact();
System.out.println(s);
try {
handle.invokeExact();
}
catch (WrongMethodTypeException e) {
System.out.println(e);
}
try {
handle.bindTo(new Object());
}
catch (IllegalArgumentException e) {
System.out.println(e);
}
}
You can call bindTo multiple times, but you should not. The implementation assumes you want to set the receiver, if you start using this to also set arguments you produce a more complicated handle, that is more difficult to compile into lambda forms and then potentially less efficient. I advise using MethodHandles#insertArguments instead