Sto scrivendo una classe serializzabile che richiede diversi argomenti, tra cui un Function
:Qual è il modo migliore per garantire che un argomento Function sia serializzabile?
public class Cls implements Serializable {
private final Collection<String> _coll;
private final Function<String, ?> _func;
public Cls(Collection<String> coll, Function<String, ?> func) {
_coll = coll;
_func = func;
}
}
func
viene memorizzato in una variabile membro, e quindi ha bisogno di essere serializzabile. Java lambda are serializable if the type they're being assigned to is serializable. Qual è il modo migliore per garantire che il Function
venga passato nel mio costruttore è serializzabile, se è stato creato utilizzando un lambda?
creare un tipo
SerializableFunction
e l'uso che:public interface SerializableFunction<F, R> implements Function<F, R>, Serializable {} .... public Cls(Collection<String> coll, SerializableFunction<String, ?> func) {...}
Issues:
- ora C'è una mancata corrispondenza tra gli argomenti
coll
efunc
, in quelfunc
viene dichiarata come serializzabile nel firma, ma non lo ècoll
, ma entrambi devono essere serializzabili perché funzioni. - Non consente altre implementazioni di
Function
serializzabili.
- ora C'è una mancata corrispondenza tra gli argomenti
utilizzare un parametro di tipo sul costruttore:
public <F extends Function<String, ?> & Serializable> Cls(Collection<String> coll, F func) {...}
Issues:
- Più flessibile di 1, ma più confusa.
- C'è ancora una mancata corrispondenza tra i due argomenti - l'argomento
func
è tenuto ad attuareSerializable
nel tipo gerarchia in fase di compilazione, macoll
è solo richiesto di essere serializzabile qualche modo (anche se questo requisito può essere gettato via, se necessario) .
EDIT Questo codice realtà non compila quando si cerca di chiamare con un riferimento lambda o metodo.
lasciarlo fino al chiamante
Ciò richiede al chiamante di sapere (dai javadocs, o per tentativi ed errori) che l'argomento deve essere serializzabile, e gettato a seconda dei casi:
Cls c = new Cls(strList, (Function<String, ?> & Serializable)s -> ...);
o
Cls c = new Cls(strList, (Function<String, ?> & Serializable)Foo::processStr);
Questo è brutto IMO, e l'implementazione ingenua iniziale di utilizzare un lambda è garantito da rompere, piuttosto che funzionare come con
coll
(dato che la maggior parte delle collezioni è serializzabile in qualche modo). Questo spinge anche un implementazione dettaglio della classe sul chiamante.
Al momento sto appoggiato verso l'opzione 2, come quella che impone il minimo onere per il chiamante, ma io non credo che ci sia una soluzione ideale qui. Qualche altro suggerimento su come farlo correttamente?
MODIFICA: Forse è necessario uno sfondo. Questa è una classe che viene eseguita all'interno di storm, in un bullone, che viene serializzato per il trasferimento su un cluster rimosso da eseguire. La funzione sta eseguendo un'operazione sulle tuple elaborate durante l'esecuzione sul cluster. Quindi fa parte dello scopo della classe che è serializzabile e che l'argomento della funzione è serializzabile. Se non lo è, la classe non è affatto utilizzabile.
Il problema con l'opzione 2 non sarebbe lo stesso se non esistesse un secondo parametro? – biziclop
Non sono sicuro di come funzionerebbe se si riceve un lambda di cattura ... – assylias
Ah sì, l'opzione 2 in realtà non viene compilata. L'ho rimosso. – thecoop