cos’è un buon framework di collezioni persistenti per l’uso in java?

Per collezioni persistenti intendo collezioni come quelle in clojure.

Ad esempio, ho una lista con gli elementi (a, b, c). Con una lista normale, se aggiungo d, la mia lista originale avrà (a, b, c, d) come suoi elementi. Con un elenco persistente, quando chiamo list.add (d), torno a una nuova lista, tenendo premuto (a, b, c, d). Tuttavia, l’implementazione tenta di condividere elementi tra gli elenchi laddove ansible, quindi è molto più efficiente in termini di memoria rispetto alla semplice restituzione di una copia dell’elenco originale. Ha anche il vantaggio di essere immutabile (se tengo un riferimento alla lista originale, restituirà sempre i 3 elementi originali).

Tutto ciò è spiegato molto meglio altrove (ad es. Http://en.wikipedia.org/wiki/Persistent_data_structure ).

Ad ogni modo, la mia domanda è … qual è la migliore libreria per fornire questa funzionalità per l’uso in java? Posso usare le collezioni di clojure in qualche modo (oltre che usando direttamente il clojure)?

Basta usare quelli in Clojure direttamente. Anche se ovviamente potresti non voler usare il linguaggio in modo autonomo, puoi comunque utilizzare le raccolte persistenti direttamente poiché sono tutte solo classi Java.

import clojure.lang.PersistentHashMap; import clojure.lang.IPersistentMap; IPersistentMap map = PersistentHashMap.create("key1", "value1"); assert map.get("key1").equals("value1"); IPersistentMap map2 = map.assoc("key1", "value1"); assert map2 != map; assert map2.get("key1").equals("value1"); 

(disclaimer: non ho effettivamente compilato quel codice 🙂

il lato negativo è che le raccolte non sono state digitate, cioè non ci sono generici con loro.

Che mi dici di pcollections ?

Puoi anche verificare l’implementazione di collezioni permanenti di Clojure ( PersistentHashMap , ad esempio).

Stavo cercando un sottile, persistente framework di raccolta “amichevole” di Java e ho preso TotallyLazy e PCollection menzionati in questa discussione per un testdrive, perché mi sembravano molto promettenti.

Entrambi forniscono interfacce semplici e ragionevoli per manipolare elenchi persistenti:

 // TotallyLazy PersistentList original = PersistentList.constructors.empty(String.class); PersistentList modified = original.append("Mars").append("Raider").delete("Raider"); // PCollections PVector original = TreePVector.empty(); PVector modified = original.plus("Mars").plus("Raider").minus("Raider"); 

Sia PersistentList che PVector estendono java.util.List , quindi entrambe le librerie dovrebbero integrarsi bene in un ambiente esistente.

Risulta, tuttavia, che TotallyLazy si imbatte in problemi di prestazioni quando si tratta di elenchi più grandi (come già menzionato in un commento sopra di @levantpied). Sul mio MacBook Pro (fine 2013) inserendo 100.000 elementi e restituendo la lista immutabile sono stati necessari TotallyLazy ~ 2000ms, mentre quelli di PClet sono terminati in ~ 120ms.

I miei (semplici) casi di test sono disponibili su Bitbucket , se qualcuno vuole dare un’occhiata più approfondita.

https://github.com/andrewoma/dexx è una porta delle collezioni persistenti di Scala in Java. Include:

  • Set, SortedSet, Map, SortedMap e Vector
  • Schede per visualizzare le raccolte persistenti come equivalenti java.util
  • Aiutanti per una facile costruzione

Potrebbe voler controllare clj-ds . Non l’ho usato, ma sembra promettente. In base ai readme del progetto, ha estratto le strutture dati da Clojure 1.2.0.

Java funzionale implementa un elenco persistente, Elenco pigro, Set, Mappa e Albero. Potrebbero essercene altri, ma sto solo passando per le informazioni sulla prima pagina del sito.

Mi interessa anche sapere qual è la migliore libreria di strutture dati persistente per Java. La mia attenzione è stata rivolta a Functional Java perché è menzionata nel libro, Functional Programming for Java Developers .

C’è la pcollections di pcollections (Persistent Collections) che puoi usare:

http://code.google.com/p/pcollections/

Paguro fornisce versioni sicure del tipo delle collezioni Clojure attuali per l’uso in Java 8+. Include: Elenco (Vector), HashMap, TreeMap, HashSet e TreeSet. Si comportano esattamente come specificato nella domanda e sono stati accuratamente adattati alle interfacce di raccolte java.util esistenti per la massima compatibilità Java sicura dal tipo. Sono anche un po ‘più veloci di quelli di PC .

La codifica del tuo esempio in Paguro si presenta così:

 // List with the elements (a,b,c) ImList list = vec(a,b,c); // With a persistent list, when I call list.add(d), // I get back a new list, holding (a,b,c,d) ImList newList = list.append(d); list.size(); // still returns 3 newList.size(); // returns 4 

Tu hai detto,

L’implementazione tenta di condividere elementi tra gli elenchi laddove ansible, quindi è molto più efficiente in termini di memoria e veloce rispetto alla semplice restituzione di una copia dell’elenco originale. Ha anche il vantaggio di essere immutabile (se tengo un riferimento alla lista originale, restituirà sempre i 3 elementi originali).

Sì, è esattamente come si comporta. Daniel Spiewak spiega la velocità e l’efficienza di queste raccolte molto meglio di quanto avrei potuto.

Allo stesso modo di Cornelius Mund, Pure4J porta le collezioni Clojure in Java e aggiunge il supporto di Generics.

Tuttavia, Pure4J ha lo scopo di introdurre la semantica della programmazione pura alla JVM attraverso la compilazione del controllo del timecode, quindi va oltre l’introduzione dei vincoli di immutabilità alle classi, in modo che gli elementi della collezione non possano essere mutati mentre la collezione esiste.

Questo potrebbe o meno essere ciò che si vuole ottenere: se si è appena dopo aver usato le raccolte Clojure sulla JVM, sceglierei l’approccio di Cornelius, altrimenti, se sei interessato a perseguire un approccio di programmazione pura all’interno di Java, potresti dare Pure4J una prova.

Divulgazione: sono lo sviluppatore di questo

La risposta più votata suggerisce di utilizzare direttamente le collezioni di clojure che ritengo sia una buona idea. Sfortunatamente il fatto che il clojure sia un linguaggio tipizzato dynamicmente e Java non rende le librerie di clojure molto scomode da usare in Java.

Per questo motivo e per la mancanza di involucri leggeri e di facile utilizzo per i tipi di clojure collection ho scritto la mia libreria di wrapper Java usando i generici per i tipi di clojure collection con particolare attenzione alla facilità d’uso e alla chiarezza quando viene alle interfacce.

https://github.com/cornim/ClojureCollections

Forse questo sarà utile a qualcuno.

PS: Al momento solo PersistentVector, PersistentMap e PersistentList sono stati implementati.

totallylazy è una libreria FP molto buona che ha implementazioni di:

  • PersistentList : le implementazioni concrete sono LinkedList e TreeList (per accesso casuale)
  • PersistentMap : le implementazioni concrete sono HashTreeMap e ListMap
  • PersistentSortedMap
  • PersistentSet : l’implementazione concreta è TreeSet

Esempio di utilizzo:

 import static com.googlecode.totallylazy.collections.PersistentList.constructors.*; import com.googlecode.totallylazy.collections.PersistentList; import com.googlecode.totallylazy.numbers.Numbers; ... PersistentList list = list(1, 2, 3); // Create a new list with 0 prepended list = list.cons(0); // Prints 0::1::2::3 System.out.println(list); // Do some actions on this list (eg remove all even numbers) list = list.filter(Numbers.odd); // Prints 1::3 System.out.println(list); 

totalmente tranquillo viene costantemente mantenuto. Lo svantaggio principale è la totale assenza di Javadoc.

https://github.com/arnohaase/a-foundation è un’altra porta delle librerie di Scala.

È anche disponibile da Maven Central: com.ajjpj.a-foundation: a-foundation

Sono sorpreso che nessuno abbia menzionato vavr. Lo uso da molto tempo adesso.

http://www.vavr.io

Descrizione dal loro sito:

Vavr core è una libreria funzionale per Java. Aiuta a ridurre la quantità di codice e ad aumentare la robustezza. Un primo passo verso la programmazione funzionale è iniziare a pensare in valori immutabili. Vavr fornisce collezioni immutabili e le funzioni e le strutture di controllo necessarie per operare su questi valori. I risultati sono belli e funzionano.