简体   繁体   中英

How to define a function taking a Serializable lambda as parameter

Is it possible to declare a method taking a Serializable lambda as parameter without having to declare a dedicated interface or ask the client to cast the lambda ?

Lets use this toy example to illustrate my question:

 static <T, R> void serialize(Function<T, R> f) throws IOException {
    try (ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream())) {
      oos.writeObject(f);
    }
  }

  public static void main(String[] args) throws IOException {
    serialize(e -> e);
  }

Lambdas are not Serializable by default, and the expected NotSerializableException is thrown.

To make it work, we can cast the lambda to add an additional Serializable bound.

  static <T, R> void serialize(Function<T, R> f) throws IOException {
    try (ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream())) {
      oos.writeObject(f);
    }
  }

  public static void main(String[] args) throws IOException {
    serialize((Function<Object, Object> & Serializable) e -> e);
  }

However, this solution is unpleasant since it forces every caller to cast their lambda and the method signature does show that f must be serializable. It is verbose and error prone.

To remove the boilerplate and make it type safe, we can define a dedicated interface:

  interface SerFunction<T, R> extends Function<T, R>, Serializable { }

  static <T, R> void serialize(SerFunction<T, R> f) throws IOException {
    try (ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream())) {
      oos.writeObject(f);
    }
  }

  public static void main(String[] args) throws IOException {
    serialize(e -> e);
  }

It does the job and almost suit my needs. The only drawback of this pattern is that I have to create a dedicated interface on top of each functional interface which is a bit cumbersome. Is it possible to get ride of the extra interface and declare the multiple bounds directly in the method signature ?

I know this question is quite old, but as it doesn't have an answer, I'll give it a try.

However, this solution is unpleasant since it forces every caller to cast their lambda and the method signature does show that f must be serializable. It is verbose and error prone.

Even though this solution will still require you to state that your lambda expression also implements the Serializable interface, this does require you to do so.

So, it gives an error when it is not implemented. It also allows children of Function to be used when they do not implement SerFunction.

public static <T, R, F extends Function<T, R> & Serializable> void serialize(F f) throws IOException
{
    try (ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream()))
    {
        oos.writeObject(f);
    }
}

public static void main(String[] args) throws IOException
{
    serialize((Function<Object, Object> & Serializable) e -> e);
    // all happy

    serialize((Function<Object, Object>) e -> e);
    // compiler error "no instance(s) of type variable(s) exist so that Function<Object, Object> conforms to Serializable
    // inference variable F has incompatible bounds:
    // lower bounds: Function<Object, Object>
    // upper bounds: Function<T, R>, Serializable"

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM