La class <a target=newWin href=http://java.sun.com/j2se/1.4.1/docs/api/java/util/BitSet.html>java.util.BitSet</a>
permet de positionner facilement des bits dans un tableau à vrai ou faux et de faire
ensuite des opérations booléennes directement sur l’objet BitSet.
Autre avantage, ce tableau est un vecteur dont nous n’avons pas à gérer la taille,
l’allocation est masquée et permet de s’affranchir de tableaux statiques.
L’interêt d’utiliser la class java.util.BitSet
?
La class BitSet a des fonctions simples, rapides et puissante. Les opérateurs booléens sont
des opérations Java qui sont appelées pour modifier le BitSet.
Si nous prenons un exemple concret, cela va plus vous parler.
Dans une application vous devez lire une Map et positionner des drapeaux si un champ
de la Map existe. On ne vérifie pas si pour une clé donnée il existe une valeur, les valeurs
vides étant acceptées dans mon exemple. D’autre part afin d’éviter de parcourir
à chaque fois la Map, nous voulons garder un BitSet qui va représenter
les champs renseignés dans la Map.
Pour créer un BitSet c’est simple:
BitSet bitSet=new BitSet();
bit.set(2); // 100
bit.set(5); // 100100
bit.set(0); // 100101
Pour voir si au moins un des bytes est positionné à true, la fonction intersects(BitSet ensemble)
est très pratique:
BitSet first = new BitSet();
first.set(2); // 100
System.out.println("first=" + first);
BitSet second = new BitSet();
second.set(4); // 10000
second.set(3); // 11000
System.out.println("second=" + second);
BitSet third = new BitSet();
third.set(0, 3); // positionne de 0 à 2 --> 111
System.out.println(first.intersects(second));
System.out.println(first.intersects(third));
System.out.println(second.intersects(third));
System.out.println("third="+third);
L’execution de ce petit exemple nous donne:
first={2}
second={3, 4}
false
true
false
third={0, 1, 2}
Reprenons l’exemple de parsing d’une Map. J’ai écris un petit programme d’exemple qui parcours
une java.util.Map et en suivant le pattern Visitor va positionner des bits à true dans un object
java.util.BitSet
.
La fonction retourne donc un BitSet qui est en quelques sortes un cliché des champs qui existent
dans la Map spécifiée. Ensuite il devient facile de faire des opérations booléennes sur ce BitSet.
Voici l’exemple complet:
/* testBitSet
* Created by : nicmarti
* Date: 04-Dec-2003 - Time: 16:10:05
*/
import java.util.*;
import java.util.logging.Logger;
/** testBitSet is a sample for BitSet.
* @version 04-Dec-2003 16:10:05
* @author Nicolas Martignole
*/
public class testBitSet {
public static final String TO = "TO";
public static final String SUBJECT = "SUBJECT";
public static final String BODY = "BODY";
public static final String FROM_ADDRESS = "FROM_ADDRESS";
public static final String FROM_NAME = "FROM_NAME";
public static final String DEVICE_CHARSET = "DEVICE_CHARSET";
public static final int HAS_TO=1;
public static final int HAS_SUBJECT = 2;
public static final int HAS_BODY = 3;
public static final int HAS_FROM_ADDRESS = 4;
public static final int HAS_FROM_NAME = 5;
public static final int HAS_DEVICE_CHARSET = 6;
/** Check the Map for field, return a BitSet that is a snapshoot
* of the current Map configuration.
*/
private static BitSet parseHeaders(Map msg) {
BitSet mask = new BitSet();
for (Iterator i = msg.keySet().iterator(); i.hasNext();) {
String curs = i.next().toString();
if (curs.toUpperCase().equals(TO)) {
mask.set(HAS_TO);
}
if (curs.toUpperCase().equals(SUBJECT)) {
mask.set(HAS_SUBJECT);
}
if (curs.toUpperCase().equals(BODY)) {
mask.set(HAS_BODY);
}
if (curs.toUpperCase().equals(FROM_ADDRESS)) {
mask.set(HAS_FROM_ADDRESS);
}
if (curs.toUpperCase().equals(FROM_NAME)) {
mask.set(HAS_FROM_NAME);
}
if (curs.toUpperCase().equals(DEVICE_CHARSET)) {
mask.set(HAS_DEVICE_CHARSET);
}
}
return mask;
}
public static void main(String[] args) {
testBitSet tested=new testBitSet();
Map myMap=new HashMap();
myMap.put(TO,"customer1@test.dotcom");
myMap.put(FROM_NAME, "Mister Test");
myMap.put(FROM_ADDRESS, "mistert@test.dotcom");
myMap.put(SUBJECT, "A subject");
Map myMap2 = new HashMap();
myMap2.put(TO, "customer@emailcom");
myMap2.put(FROM_NAME,"From de test");
myMap2.put(FROM_ADDRESS, "mistert@test.dotcom");
myMap2.put(SUBJECT, "From de test");
myMap2.put(BODY, "A body for testing");
myMap2.put(DEVICE_CHARSET, "TEST Charset");
BitSet littleMail =tested.parseHeaders(myMap);
BitSet hugeMail = tested.parseHeaders(myMap2);
BitSet allTrue=new BitSet(6);
allTrue.set(1,7);
// We want a header without Body and DeviceChareset sets
BitSet withoutCharsetAndBody=new BitSet();
withoutCharsetAndBody.set(HAS_BODY);
withoutCharsetAndBody.set(HAS_DEVICE_CHARSET);
// 100100
withoutCharsetAndBody.xor(littleMail); // will output 111111
System.out.println("withCharsetAndBody="+ withoutCharsetAndBody.toString());
if(withoutCharsetAndBody.equals(allTrue)){
System.out.println("The specified header has no BODY and DEVICE_CHARSET");
}
// We would like to check that all headers are set
BitSet allHeader = new BitSet(); //000000
allHeader.xor(hugeMail);
System.out.println("allHeader=" + allHeader.toString());
if(allHeader.equals(allTrue)){
System.out.println("Great ! no missing header fields");
}
}
}