Melhor coleção para serializar

4 respostas
gcobr

Amigos

Suponham que vocês queiram serializar uma implementação qualquer de Collection. Qual das implementações padrão (ArrayList, HashSet, etc.) vocês escolheriam para ocupar menos espaço/banda de rede?

4 Respostas

T

Acho mais fácil fazer um teste. Pela lógica seria um ArrayList, mas a lógica não é uma conselheira totalmente confiável quando se trata de desempenho.

T

Fiz o teste com Java 5.0. Realmente, a intuição é muito má conselheira.

a) Você pode até usar qualquer uma das coleções indistintamente, exceto a Vector, que tem um grande overhead (não sei por quê.)
b) Por incrível que pareça, a melhor para mim foi a TreeSet.

import java.util.*;
import java.io.*;


class Funcionario implements Serializable, Comparable<Funcionario> {
    private String nome;
    private double salario;
    public Funcionario (final String pNome, final double pSalario) {
         nome = pNome; salario = pSalario; 
    }
    public int compareTo (Funcionario f) {
        return nome.compareTo (f.nome);
    }
    public int hashCode () {
        return nome.hashCode() * 37 + Double.valueOf(salario).hashCode();
    }
    public boolean equals (Object obj) {
        if (obj.getClass() == Funcionario.class) {
            Funcionario f = (Funcionario) obj;
            return (f.nome.equals (nome) && Math.abs (f.salario - salario) &lt 1E-2);
        } else return false;
    }
}

class Projeto implements Serializable, Comparable<Projeto> {
    private String nome;
    private Funcionario chefe;
    private Funcionario[] subordinados;
    public Projeto (final String pNome, final Funcionario pChefe, final Funcionario[] pSubordinados) {
         nome = pNome; chefe = pChefe; subordinados = pSubordinados;
    }
    public int compareTo (Projeto p) {
        return nome.compareTo (p.nome);
    }
    public int hashCode () {
        int ret = nome.hashCode() * 37 + chefe.hashCode();;
        for (Funcionario subordinado : subordinados) {
            ret = ret * 37 + subordinado.hashCode();
        }
        return ret;
    }
    public boolean equals (Object obj) {
        if (obj.getClass() == Projeto.class) {
            Projeto p = (Projeto) obj;
            boolean ret = p.nome.equals (nome) 
                && p.chefe.equals (chefe);
            if (p.subordinados != null && subordinados != null && p.subordinados.length == subordinados.length) {
                for (int i = 0; i &lt subordinados.length; ++i) {
                    ret &= p.subordinados[i].equals (subordinados[i]);
                }
            } else if (p.subordinados != subordinados) {
                ret = false;
            }
            return ret;
        } else return false;
    }
}

class TesteTamanhoCollection {
    
    public static int tamCollection (Collection&lt?&gt col) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream (baos);
        oos.writeObject (col);
        oos.close();
        return baos.toByteArray().length;
    }
    
    public static void main(String[] args) throws IOException {
        Collection<Projeto> treeSet = new TreeSet<Projeto>();
        Collection<Projeto> hashSet = new HashSet<Projeto>();
        Collection<Projeto> linkedList = new LinkedList<Projeto>();
        Collection<Projeto> linkedHashSet = new LinkedHashSet<Projeto>();
        Collection<Projeto> arrayList = new ArrayList<Projeto>();
        Collection<Projeto> vector = new Vector<Projeto>();
        System.out.println ("Imprimindo as coleções vazias");
        System.out.println ("treeSet =       " + tamCollection (treeSet));       // 46
        System.out.println ("hashSet =       " + tamCollection (hashSet));       // 53
        System.out.println ("linkedList =    " + tamCollection (linkedList));    // 48
        System.out.println ("linkedHashSet = " + tamCollection (linkedHashSet)); // 91
        System.out.println ("arrayList =     " + tamCollection (arrayList));     // 58
        System.out.println ("vector =        " + tamCollection (vector));        // 167
        //== Acrescentando três projetos
        Projeto p1 = new Projeto ("javac", new Funcionario ("Peter Ahe", 7000.00), new Funcionario [] {new Funcionario ("Gilad Bracha", 8000.00)});
        Projeto p2 = new Projeto ("netbeans", new Funcionario ("Tim Boudreau", 9000.00), new Funcionario [] {new Funcionario ("Roman Strobl", 8500.00), new Funcionario ("Geertjan Wielenga", 8200.00)});
        Projeto p3 = new Projeto ("sun", new Funcionario ("Jonathan Schwartz", 100000.00), new Funcionario [] {new Funcionario ("Rich Burridge", 50000.00)});
        treeSet.add (p1); treeSet.add (p2); treeSet.add (p3);
        hashSet.add (p1); hashSet.add (p2); hashSet.add (p3);
        linkedList.add (p1); linkedList.add (p2); linkedList.add (p3);
        linkedHashSet.add (p1); linkedHashSet.add (p2); linkedHashSet.add (p3);
        arrayList.add (p1); arrayList.add (p2); arrayList.add (p3);
        vector.add (p1); vector.add (p2); vector.add (p3);
        System.out.println ("Imprimindo as coleções com elementos");
        System.out.println ("treeSet =       " + tamCollection (treeSet));       // 501
        System.out.println ("hashSet =       " + tamCollection (hashSet));       // 508
        System.out.println ("linkedList =    " + tamCollection (linkedList));    // 503
        System.out.println ("linkedHashSet = " + tamCollection (linkedHashSet)); // 546
        System.out.println ("arrayList =     " + tamCollection (arrayList));     // 513
        System.out.println ("vector =        " + tamCollection (vector));        // 619
    }
}
A

[edit] escrevi uma besteira tão grande que até apaguei… falta de atenção… [/edit]

T

armando:

a) Você pode até usar qualquer uma das coleções indistintamente, exceto a Vector, que tem um grande overhead (não sei por quê.)

Só pra constar… isso acontece porque a Vector é desenvolvida para ser thread-safe, então todos os seus métodos são synchronized… é isso que gera esse overhead…]

Abraço,

Armando

Aham, Vector tem um pouco de overhead na serialização, mas não devido à sincronização.
Comparando o fonte de java.util.Vector e java.util.ArrayList, você pode ver que o primeiro usa o suporte-padrão a serialização e o segundo sobrepõe as rotinas writeObject e readObject. Como Vector aloca um array de pelo menos 10 objetos, e ArrayList sobrepõe as rotinas writeObject e readObject de modo que sempre copia a quantidade exata de objetos, aparece a tal diferença. Vou retestar com 10 objetos para ver o que ocorre.

Criado 6 de setembro de 2006
Ultima resposta 6 de set. de 2006
Respostas 4
Participantes 3