Monday, August 15, 2016
What is bound to generic types for method references in java 8, types and exceptions
Integer example = 1; // We can bind the instance variables, in this case just the return type is bound but there couple be method parameters also Supplier<String> s = example::toString; // We can bind to static method, here the generic parameter are the method parameter and return type Supplier<Long> f = System::currentTimeMillis; Function<Integer,Integer> f = example::compareTo;
A less common formulation is to pass in instance methods and find the first generic parameter of of the function to be the type, this allows you to easily pass in a range of actions to operate on a common type:
Function<Integer,String> f = Integer::toString
For example you can create an equals method that works on a subset of properties using functions mapped to instance methods as in the above example:
public static <T> boolean equals(T one, T two, Function<? super T, ?>... accessors) {
if (one == two) {
return true;
} else if (one==null || two==null) {
return false;
}
return Stream.of(accessors).allMatch(accessor ->
Objects.equals(accessor.apply(one),accessor.apply(two)));
}
if (equals(one, two, Thing::getName, Thing:getOtherProperty)) ...;
Finally you can also bind the exception thrown from the method to one of the generic parameters. (Here I am using ThrowingException and ThrowingSupplier my home brew interfaces that are like there namesakes but have a generic parameter E for the exception thrown) This allows you to make you "closure" transparent to exceptions. This is more useful in a lot of cases when compared to the Stream throw nothing and "throws Exception" extremes.
ThrowingException<String,Integer,NumberFormatException> te = Integer::parseInt;
You can write funky closure methods that will throw different exceptions based on the passed in method reference does, no more catch (Exception).
public static <T, E extends Exception> T withCC(Class<?> contextClass,
ThrowingSupplier<T,E> action) throws E {
Thread t = Thread.current();
ClassLoader cl = t.getContextClassLoader();
try {
t.setContextClassLoader(contextClass.getClassLoader());
return action.get();
} finally {
s.setContextClassLoader(cl);
}
}
// Throws IOException, complier knows that this method call throws IOException
String value = withCC(Example.class, () -> {
...
... new FileOutpuStream(file); ...
...
});
// Throws another exception, complier knows that this method call throws RMIExeption
String value = withCC(Example.class, () -> {
...
throw new RMIException();
});
Once you understand the last two, method reference start to become far more interesting.
Thursday, March 10, 2016
Lambda of Lambda, if/else from an Optional
isPresent method unless you are using an old school if statement. The second problem is of course the old chestnut that even if you could do that the methods would not be able to throw a checked exception. (Yes you can wrap with a RuntimeException but it is not the prettiest.)The workaround I found was to use the map function as the success case and the orElseGet to return the failure case. In both branches the code returns an instance of ThrowingRunnable by having a lambda return a lambda. The
run() is then called at the end and it can throw any exception it wants to.@FunctionalInterface
public interface ThrowingRunnable<E extends Throwable> {
public void run() throws E;
}
Optional<Credential> credential = ....
credential.<ThrowingRunnable<IOException>>map(auth -> () -> {
PasswordWrapper pw = auth.getToken();
... // something that might throw an IOException
}).orElseGet(() -> () -> {
response.setStatus(401);
LOGGER.log(Level.INFO, "credential is not found");
}
).run();
This is possibly excessive for this particular use case; but I can see this technique being useful elsewhere and it is worth knowing what it looks like so it is not a surprise in others code.
Update 14th March 2016: Thanks to Michael Rasmussen on the DZone version of this article he noted I could use
orElse rather than orElseGet to remove the second double lambda.credential.<ThrowingRunnable<IOException>>map(auth -> () -> {
PasswordWrapper pw = auth.getToken();
... // something that might throw an IOException
}).orElse(() -> {
response.setStatus(401);
LOGGER.log(Level.INFO, "credential is not found");
}
).run();
Tuesday, January 7, 2014
Post-hoc tracing using a debugger
Once nice little features of most debuggers that I have been exercising recently is the ability to log information on a breakpoint. This can be a really useful was to understand code without having to modify it is involve byte code modification.
Let's consider this very trivial and inefficient implementation of a function to return the n'th number in the Fibonacci sequence.
public class Fib {
public long fib(long number) {
return number < 1 ? 0 : // Breakpoint here
number < 2 ? 1 : fib(number - 2) + fib(number - 1);
}
public static void main(String[] args) {
Fib fib = new Fib();
System.out.println(fib.fib(10L));
}
}
Now we add a simple breakpoint, I am going to modify it slightly so that it doesn't halt; but it will log a simple expression which gives us the current value of number
This gives you the following output for our rather inefficient code:
ebugger connected to local process. Source breakpoint: Fib.java:11, evaluate(number)=10 (long) Source breakpoint: Fib.java:11, evaluate(number)=8 (long) Source breakpoint: Fib.java:11, evaluate(number)=6 (long) Source breakpoint: Fib.java:11, evaluate(number)=4 (long) Source breakpoint: Fib.java:11, evaluate(number)=2 (long) Source breakpoint: Fib.java:11, evaluate(number)=0 (long) Source breakpoint: Fib.java:11, evaluate(number)=1 (long) Source breakpoint: Fib.java:11, evaluate(number)=3 (long) Source breakpoint: Fib.java:11, evaluate(number)=1 (long) Source breakpoint: Fib.java:11, evaluate(number)=2 (long) ... sometime later Source breakpoint: Fib.java:11, evaluate(number)=1 (long) Source breakpoint: Fib.java:11, evaluate(number)=2 (long) Source breakpoint: Fib.java:11, evaluate(number)=0 (long) Source breakpoint: Fib.java:11, evaluate(number)=1 (long) 55
So what we have done here is to add trace post-hoc, you might not even have access to the source and still be able to get useful information out of what the code is doing.
Now the obvious take away from the above example is that we are computing the same value over and over again. So here is another version of the code which instead uses a Map to store previously computed values in the sequence. Note also it is more of a pain to add trace to this code than in the previous case without making the Lambda less pretty.
import java.util.HashMap;
import java.util.Map;
public class Fib {
Map<Long, Long> data = new HashMap<>();
{
data.put(1L, 1L);
}
public long fib(long number) {
return data.computeIfAbsent(number,
n -> n < 1 ? 0 : fib(n - 2) + fib(n - 1)); // Breakpoint here
}
public static void main(String[] args) {
Fib fib = new Fib();
System.out.println(fib.fib(10L));
}
}
It is worth noting two things here, first of all your breakpoint log expression should be evaluating the value of the Lambda parameter n and that the second is that you should always put your expression on a new line so that future developer can easily breakpoint it. (Not matter now much smaller/ prettier/ clever it would look if you put the code on one).
So the trace output is now as follows, much better as each value is only computed the once.
Debugger connected to local process. Source breakpoint: Fib.java:17, evaluate(n)=10 Source breakpoint: Fib.java:17, evaluate(n)=8 Source breakpoint: Fib.java:17, evaluate(n)=6 Source breakpoint: Fib.java:17, evaluate(n)=4 Source breakpoint: Fib.java:17, evaluate(n)=2 Source breakpoint: Fib.java:17, evaluate(n)=0 Source breakpoint: Fib.java:17, evaluate(n)=3 Source breakpoint: Fib.java:17, evaluate(n)=5 Source breakpoint: Fib.java:17, evaluate(n)=7 Source breakpoint: Fib.java:17, evaluate(n)=9 55
The screen grabs in this blog are from Jdeveloper; but similar features are available in Intelij, Netbeans and if you are a bit crafty you can get something similar in Eclipse.
Thursday, December 19, 2013
Lambda'ery WebSocket code (from UKTECH13 presentation)
if statements in the code.I would note that in a real world chat application that it unlikely different rooms would have different resource URIs but for the purposes of the presentation this made sense.
package websocket;
import static java.util.Collections.emptySet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint(value = "/chat/{room}")
public class ChatService {
private static final Set<Session> EMPTY_ROOM = emptySet();
static final ConcurrentMap<String, Set<Session>> rooms =
new ConcurrentHashMap<>();
@OnOpen
public void onOpen(Session peer, @PathParam("room") String room) {
rooms.computeIfAbsent(room,
s -> new CopyOnWriteArraySet<Session>()).add(peer);
}
@OnClose
public void onClose(Session peer, @PathParam("room") String room) {
rooms.getOrDefault(room, EMPTY_ROOM).remove(peer);
}
@OnError
public void onError(Session peer, Throwable th,
@PathParam("room") String room) {
System.out.println("Peer error " + room + " " + th);
}
@OnMessage
public void message(String message, Session peer,
@PathParam("room") String room) {
// Send a message to all peers in a room who are not the current
// peer and are still open. Send the message asynchronously to ensure
// that the first client is not hung up.
rooms.getOrDefault(room, EMPTY_ROOM).parallelStream()
.filter(s -> s != peer && s.isOpen())
.forEach(s -> s.getAsyncRemote().sendObject(message));
};
}
One of the problem with the above design is that there is no error logging when an invalid room is used. This could be useful to diagnose errors. Not wanting to use any conditional statements you could use an Optional object:
import java.util.Optional;
@OnClose
public void onClose(Session peer, @PathParam("room") String room) {
Optional.ofNullable(rooms.get(room))
.orElseThrow(() -> new IllegalStateException("Cannot find room " + room))
.remove(peer);
}
Of course you might want this on your method objects, so you can use default methods to create a mixin for this on all your Map objects with a trivial subclass.
import java.util.Optional;
public interface OptionalMap<K,V> extends ConcurrentMap<K,V> {
public default Optional<V> find(K key) {
return Optional.ofNullable(get(key));
}
}
public static class OptionalHashMap<K,V> extends ConcurrentHashMap<K,V>
implements OptionalMap<K,V> {
}
static final OptionalMap<String, Set<Session>> rooms =
new OptionalHashMap<>();
@OnClose
public void onClose(Session peer, @PathParam("room") String room) {
rooms.find(room)
.orElseThrow(() -> new IllegalStateException("Cannot find room " + room))
.remove(peer);
}
Whilst working on my presentation it became apparent that it was also possible to use the "openSessions" and "getUserProperties" method to store discrimination data against the Session. I don't have enough experience yet to say which is the better design for a particular case.
package websocket;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint(value = "/chat/{room}")
public class ChatService {
private static final String ROOM_PROPERTY = "ROOM";
@OnOpen
public void onOpen(Session peer, @PathParam("room") String room) {
peer.getUserProperties().put(ROOM_PROPERTY, room);
}
@OnClose
public void onClose(Session peer, @PathParam("room") String room) {
// No need to tidy up and data is store against peer
}
@OnError
public void onError(Session peer, Throwable th,
@PathParam("room") String room) {
System.out.println("Peer error " + room + " " + th);
}
@OnMessage
public void message(String message, Session peer,
@PathParam("room") String room) {
peer.getOpenSessions().parallelStream()
.filter(s -> room.equals(s.getUserProperties().get(ROOM_PROPERTY)))
.filter(s -> s != peer && s.isOpen())
.forEach(s -> s.getAsyncRemote().sendObject(message));
};
}
Wednesday, December 4, 2013
Lambda, will it serialize?
To this end I created a simple unit test class that would take my filter, serialise it to disk, read it back and in then execute it. It had a instance field "VALUE" that we could use to reference directly or indirectly to find out what would cause the serialisation to fail.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.function.Predicate;
import org.junit.Test;
public class SerializablePredicateFilterTest {
public String VALUE = "Bob";
public interface SerializablePredicate<T> extends Predicate<T>, Serializable {
}
public <T> void filter(SerializablePredicate<T> sp, T value) throws IOException, ClassNotFoundException {
sp.getClass().isLocalClass();
File tempFile = File.createTempFile("labmda", "set");
try (ObjectOutput oo = new ObjectOutputStream(new FileOutputStream(tempFile))) {
oo.writeObject(sp);
}
try (ObjectInput oi = new ObjectInputStream(new FileInputStream(tempFile))) {
SerializablePredicate<T> p = (SerializablePredicate<T>) oi.readObject();
System.out.println(p.test(value));
}
}
}
So just to calibrate lets make sure that an anonymous inner class will fail, because it will always contain a reference to enclosing object....
@Test(expected = NotSerializableException.class)
public void testAnonymousDirect() throws IOException, ClassNotFoundException {
String value = VALUE;
filter(new SerializablePredicate<String>() {
@Override
public boolean test(String t) {
return value.length() > t.length();
}
}, "Bob");
}
The same is true for local classes, what you don't use local classes?
@Test(expected = NotSerializableException.class)
public void testLocalClass() throws IOException, ClassNotFoundException {
class LocalPredicate implements SerializablePredicate<String> {
@Override
public boolean test(String t) {
// TODO Implement this method
return false;
}
}
filter(new LocalPredicate(), "Bobby");
}
So a standalone class will of course work, in this case a nested class for convenience.
public static class LengthPredicate implements SerializablePredicate<String> {
private String value;
public LengthPredicate(String value) {
super();
this.value = value;
}
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
@Override
public boolean test(String t) {
// TODO Implement this method
return false;
}
}
@Test
public void testStaticInnerClass() throws IOException, ClassNotFoundException {
filter(new LengthPredicate(VALUE), "Bobby");
}
So lets get down with JDK 8, it turns out that my first try also fails but it does confirm that the serialisation is quite happy to take a Lambda in general.
@Test(expected = NotSerializableException.class)
public void testLambdaDirect() throws IOException, ClassNotFoundException {
filter((String s) -> VALUE.length() > s.length(), "Bobby");
}
A slight modification to copy the value into a effectively final attributes, and voila the lambda is now serialised and retrieved properly.
@Test
public void testLambdaInDirect() throws IOException, ClassNotFoundException {
String value = VALUE;
filter((String s) -> value.length() > s.length(), "Bobby");
}
And of course if the value is a simple method parameter it also works fine.
@Test
public void testLambdaParameter() throws IOException, ClassNotFoundException {
invokeWithParameter(VALUE);
}
private void invokeWithParameter(String value) throws java.lang.ClassNotFoundException, java.io.IOException {
filter((String s) -> value.length() > s.length(), "Bobby");
}
So the answer is yes, you can get it to serialise if you are a bit careful.
