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