Google Guava может многое предложить разработчику Java, работающему с J2SE 5 , Java SE 6 или Java SE 7 . Чем старше их версия, тем полезнее может быть Guava. Хотя Java SE 7 предоставляет некоторые функции, предоставляемые Guava, языку программирования Java в качестве стандартной части языка (например, новый класс Objects ), по-прежнему существует множество функций Guava, которые недоступны даже в JDK 7. В этом посте Я сосредоточен на поддержке двунаправленных карт в Гуаве .
Наследие Гуавы находится в « древнем и не поддерживаемом » проекте Google Collections, и поддержка двунаправленной карты Гуавы происходит из этого наследия Google Collections . Документация API для интерфейса com.google.common.collect.BiMap в Guava предоставляет хорошее краткое определение двунаправленной карты:
Двунаправленная карта (или «двунаправленная карта») — это карта, которая сохраняет уникальность своих значений, а также ключей. Это ограничение позволяет бимапам поддерживать «инверсное представление», которое является еще одним бимапом, содержащим те же записи, что и этот бимап, но с обращенными ключами и значениями.
В моей карьере я столкнулся с несколькими ситуациями, когда поддержка двунаправленной карты помогает сделать более понятный и читаемый код. Я даже построил пользовательские реализации двунаправленных карт, но больше не делать , что благодаря наличию гуавы (и ранее в Google Коллекции и Apache Commons «ы BidiMap). Следующий листинг кода показывает простую ситуацию, когда двунаправленная карта полезна. Этот пример отображает нации в их столицы. Прелесть двунаправленной карты в том, что я могу искать столицу по названию ее нации или я могу искать по названию нации по названию столицы. Важной характеристикой двунаправленной карты является то, что сторона «значения» двунаправленной карты требует уникальных значений в дополнение к более типичной «ключевой» стороне двунаправленной карты, требующей уникальных значений.
TwoMonoDirectionalMaps
package dustin.examples;
import static java.lang.System.out;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Demonstrate simplistic implementation of functionality equivalent to that
* provided by bidirectional map via two monodirectional maps. This class has
* some intentional problems to illustrate the maintenance disadvantages of this
* approach. For example, there is a mismatch between the two single-direction
* maps for "London" (UK in one case and England in the other case) and the
* mapping for France/Paris was left off one of the single-direction maps.
*
* @author Dustin
*/
public class TwoMonoDirectionalMaps
{
private final static Map<String, String> nationsToCapitals;
private final static Map<String, String> capitalsToNations;
static
{
final Map<String, String> tempNationsToCapitals = new HashMap<String, String>();
tempNationsToCapitals.put("Canada", "Ottawa");
tempNationsToCapitals.put("England", "London");
tempNationsToCapitals.put("France", "Paris");
tempNationsToCapitals.put("Mexico", "Mexico City");
tempNationsToCapitals.put("Portugal", "Lisbon");
tempNationsToCapitals.put("Spain", "Madrid");
tempNationsToCapitals.put("United States", "Washington");
nationsToCapitals = Collections.unmodifiableMap(tempNationsToCapitals);
final Map<String, String> tempCapitalsToNations = new HashMap<String, String>();
tempCapitalsToNations.put("Lisbon", "Portugal");
tempCapitalsToNations.put("London", "United Kingdom");
tempCapitalsToNations.put("Madrid", "Spain");
tempCapitalsToNations.put("Mexico City", "Mexico");
tempCapitalsToNations.put("Ottawa", "Canada");
tempCapitalsToNations.put("Washington", "United States");
capitalsToNations = Collections.unmodifiableMap(tempCapitalsToNations);
}
/**
* Print the capital city of the nation whose name is provided.
*
* @param nationName Name of nation for which capital is decided.
*/
public void printCapitalOfNation(final String nationName)
{
out.println(
"The capital of " + nationName + " is "
+ (nationsToCapitals.containsKey(nationName) ? nationsToCapitals.get(nationName) : "unknown" )
+ ".");
}
/**
* Print the name of the nation whose capital name is provided.
*
* @param capitalName Name of capital city for which nation is desired.
*/
public void printNationOfCapital(final String capitalName)
{
out.println(
capitalName + " is the the capital of "
+ (capitalsToNations.containsKey(capitalName) ? capitalsToNations.get(capitalName) : "unknown" )
+ ".");
}
/**
* Main function demonstrating this use of two mono-directional maps.
*
* @param arguments Command-line arguments; none expected.
*/
public static void main(final String[] arguments)
{
final TwoMonoDirectionalMaps me = new TwoMonoDirectionalMaps();
me.printCapitalOfNation("United States");
me.printCapitalOfNation("England");
me.printCapitalOfNation("France");
me.printNationOfCapital("Washington");
me.printNationOfCapital("London");
me.printNationOfCapital("Paris");
}
}
При выполнении вышеизложенного вывод выглядит так, как показано на следующем снимке экрана. Названия столиц и стран, приведенные в этом примере, предназначены для иллюстрации одной из проблем, связанных с использованием двух однонаправленных карт: они могут быть не синхронизированы. Эта проблема может быть исправлена с помощью двунаправленной карты, как показано в следующем примере кода, в котором используется реализация ImmutableBiMap интерфейса BiMap.
GuavaBiMapDemo
package dustin.examples;
import static java.lang.System.out;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Simple demonstration of Google Guava's bidirectional map support.
*
* @author Dustin
*/
public class GuavaBiMapDemo
{
private final static BiMap<String, String> nationsToCapitals;
static
{
final Map<String, String> tempNationsToCapitals = new HashMap<String, String>();
tempNationsToCapitals.put("Canada", "Ottawa");
tempNationsToCapitals.put("England", "London");
tempNationsToCapitals.put("France", "Paris");
tempNationsToCapitals.put("Mexico", "Mexico City");
tempNationsToCapitals.put("Portugal", "Lisbon");
tempNationsToCapitals.put("Spain", "Madrid");
tempNationsToCapitals.put("United States", "Washington");
nationsToCapitals = ImmutableBiMap.copyOf(Collections.unmodifiableMap(tempNationsToCapitals));
}
/**
* Print the capital city of the nation whose name is provided.
*
* @param nationName Name of nation for which capital is decided.
*/
public void printCapitalOfNation(final String nationName)
{
out.println(
"The capital of " + nationName + " is "
+ (nationsToCapitals.containsKey(nationName) ? nationsToCapitals.get(nationName) : "unknown" )
+ ".");
}
/**
* Print the name of the nation whose capital name is provided.
*
* @param capitalName Name of capital city for which nation is desired.
*/
public void printNationOfCapital(final String capitalName)
{
out.println(
capitalName + " is the the capital of "
+ (nationsToCapitals.containsValue(capitalName) ? nationsToCapitals.inverse().get(capitalName) : "unknown" )
+ ".");
}
/**
* Main function demonstrating this use of two mono-directional maps.
*
* @param arguments Command-line arguments; none expected.
*/
public static void main(final String[] arguments)
{
final GuavaBiMapDemo me = new GuavaBiMapDemo();
me.printCapitalOfNation("United States");
me.printCapitalOfNation("England");
me.printCapitalOfNation("France");
me.printNationOfCapital("Washington");
me.printNationOfCapital("London");
me.printNationOfCapital("Paris");
}
}
When the above is executed, the output shows more consistent mappings for London and for Paris/France because there was no need to maintain two separate maps.
Guava’s bidirectional maps provide a safer and more readable approach to implementing data structures that map keys to values and values to key in such a way that one can be accessed via the other. Normal Java Maps only access use of a key to access a value directly, but both directions of access are supported by Guava’s bidirectional maps.
Guava seems to be receiving more attention these days. Google’s guava java: the easy parts was written about one year ago and is a nice introduction to the «easier» portions of Guava. Tom Jefferys‘s September 2011 post Multimaps — Google Guava also provides a nice overview of Guava’s map support with focus on Multimaps followed by separate posts focusing on BiMaps and Multisets. Recent post 5 Reasons to use Guava includes Guava’s map support as one of five reasons that Java developers should embrace Guava. Section 16.9. retrieving a key by value (working with bi-directional maps) of the Java Commons Cookbook (download) also covers Guava’s support for bidirectional maps.
From http://marxsoftware.blogspot.com/2011/10/guavas-bidirectional-maps.html
