Класс пары знаком тем из нас, кто использовал C ++ в течение длительного времени. Несмотря на разговоры о добавлении его в Java в качестве стандартной части SDK, это довольно спорная тема . Несколько человек официально запросили его, и даже были зарегистрированы ошибки ( 4947273 , 4983155 и 6229146 ), чтобы получить его на Java. В сообщении, задающем вопрос, хотим ли мы java.util.Pair? , Алекс Миллер делает хорошую работу покрытия обе стороны вопроса.
Для Java уже есть реализации Pair или подобного Пару эквивалента. Кроме того, неизвестное количество пользовательских единиц в локальных кодовых баз, есть общедоступные примеры , такие как те , которые предусмотрены должности класса пара Java , примеры , приведенные в потоке StackOverflow , иероглиф «s Generic Pair , и ( не удивительно ) Java кортежей » с Пара . Android SDK также имеет Pair класс. Тот , что удивило меня больше всего , является существование JavaFX 2.0 «s javafx.util.Pair класса.
Имя пакета и класса, наиболее часто предлагаемых для SDK-версии класса Pair, было java.util.Pair, а версия JavaFX аналогична имени пакета: javafx.util.Pair. Запуск javap для этого класса в JavaFX SDK приводит к следующему выводу.
Compiled from "Pair.java" public class javafx.util.Pair<K, V> { public K getKey(); public V getValue(); public javafx.util.Pair(K, V); public java.lang.String toString(); public int hashCode(); public boolean equals(java.lang.Object); }
Как показано в приведенном выше выводе javap, это относительно простой класс с базовым параметризованным конструктором, методами «get» для частей ключа и значения пары и «общими» методами toString (), equals (Object) и hashCode ( ). В следующем листинге кода показано использование параметризованного конструктора для предоставления ключа и значения каждому экземпляру Pair, для которого создается экземпляр.
/** * Provide a collection of famous pairs. * * @return Collection of famous pairs. */ private static Collection<Pair<String,String>> createFamousPairs() { final Collection<Pair<String,String>> pairs = new ArrayList<Pair<String,String>>(); pairs.add(new Pair("Yin", "Yang")); pairs.add(new Pair("Action", "Reaction")); pairs.add(new Pair("Salt", "Pepper")); pairs.add(new Pair("Starsky", "Hutch")); pairs.add(new Pair("Fox", "Mulder")); pairs.add(new Pair("Batman", "Robin")); pairs.add(new Pair("Fred Astaire", "Ginger Rogers")); pairs.add(new Pair("Flotsam", "Jetsam")); pairs.add(new Pair("Brutus", "Nero")); pairs.add(new Pair("Tom", "Jerry")); pairs.add(new Pair("Jekyll", "Hyde")); pairs.add(new Pair("Holmes", "Watson")); pairs.add(new Pair("Mario", "Luigi")); pairs.add(new Pair("Pinky", "The Brain")); pairs.add(new Pair("Wallace", "Gromit")); return pairs; }
Доступ к ключу и значению каждой пары также прост, как показано в следующем примере кода.
/** * Write provided collection of pairs to standard output. * * @param title Title for output written to standard output. * @param pairsToPrint Pairs to be written to standard output. */ private static void writeCollectionOfPairs( final String title, final Collection<Pair<String,String>> pairsToPrint) { out.println(title + ":"); for (final Pair<String,String> pair : pairsToPrint) { out.println("\t" + pair.getKey() + " and " + pair.getValue()); } }
Приведенный выше пример является относительно надуманным, но можно утверждать, что он наиболее эффективно использует пару, поскольку в этом конкретном примере это действительно представляемая концепция «пары». Одна из самых больших жалоб на добавление Pair в SDK или его использование в целом заключается в том, что он не назван достаточно конкретно, чтобы покрыть бизнес-цели существования объекта. Я действительно думал об использовании класса JavaFX Pair, когда писал свой пример Christmas Tree для поста JavaFX 2.0 Christmas Tree (JavaFX 2.0 Shapes) . В итоге я решил отказаться от этого и использовал более подходящее имя вложенного класса Coordinate. Тем не менее, я мог бы легко использовать пару в этом примере. Следующий листинг кода содержит тот самый пример с удаленным вложенным классом Coordinate и заменой ссылок на него на Pair.
package dustin.examples; import javafx.application.Application; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.effect.Glow; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; import javafx.scene.shape.*; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.stage.Stage; import javafx.util.Pair; /** * Simple example of using JavaFX 2.0's Path to create a simple Christmas tree. * * @author Dustin */ public class ChristmasTreePathWithPair extends Application { /** Number of branches on Christmas tree. */ private final static int NUMBER_BRANCHES = 4; /** X-coordinate of very top of Christmas tree. */ private final static int TOP_CENTER_X = 400; /** Y-coordinate of very top of Christmas tree. */ private final static int TOP_CENTER_Y = 25; /** Horizontal distance to end of each branch. */ private final static int DELTA_X = 125; /** Vertical distance to end of each branch. */ private final static int DELTA_Y = 100; /** Length of each branch as measured on bottom of branch. */ private final static int BRANCH_LENGTH = 75; /** Width of tree stump. */ private final static int STUMP_WIDTH = 100; /** Height of tree stump. */ private final static int STUMP_HEIGHT = 150; /** X-coordinate of top left corner of tree stump. */ private final static int LEFT_STUMP_X = TOP_CENTER_X - STUMP_WIDTH/2; /** Y-coordinate of top left corner of tree stump. */ private final static int LEFT_STUMP_Y = TOP_CENTER_Y + DELTA_Y * NUMBER_BRANCHES; /** Width of Christmas tree bottom. */ private final static int TREE_BOTTOM_WIDTH = (DELTA_X-BRANCH_LENGTH) * NUMBER_BRANCHES * 2; /** * Draw left side of the Christmas tree from top to bottom. * * @param path Path for left side of Christmas tree to be added to. * @param startingX X portion of the starting coordinate. * @param startingY Y portion of the starting coordinate. * @return Coordinate with x and y values. */ private Pair<Integer, Integer> drawLeftSide( final Path path, final int startingX, final int startingY) { int coordX = startingX - DELTA_X; int coordY = startingY + DELTA_Y; final LineTo topLeft = new LineTo(coordX, coordY); path.getElements().add(topLeft); coordX += BRANCH_LENGTH; final LineTo topLeftHorizontal = new LineTo(coordX, coordY); path.getElements().add(topLeftHorizontal); coordX -= DELTA_X; coordY += DELTA_Y; final LineTo secondLeft = new LineTo(coordX, coordY); path.getElements().add(secondLeft); coordX += BRANCH_LENGTH; final LineTo secondLeftHorizontal = new LineTo(coordX, coordY); path.getElements().add(secondLeftHorizontal); coordX -= DELTA_X; coordY += DELTA_Y; final LineTo thirdLeft = new LineTo(coordX, coordY); path.getElements().add(thirdLeft); coordX += BRANCH_LENGTH; final LineTo thirdLeftHorizontal = new LineTo(coordX, coordY); path.getElements().add(thirdLeftHorizontal); coordX -= DELTA_X; coordY += DELTA_Y; final LineTo fourthLeft = new LineTo(coordX, coordY); path.getElements().add(fourthLeft); coordX += BRANCH_LENGTH; final LineTo fourthLeftHorizontal = new LineTo(coordX, coordY); path.getElements().add(fourthLeftHorizontal); return new Pair(coordX, coordY); } /** * Draw right side of the Christmas tree from bottom to top. * * @param path Path for right side of Christmas tree to be added to. * @param startingX X portion of the starting coordinate. * @param startingY Y portion of the starting coordinate. * @return Coordinate with x and y values. */ private Pair<Integer, Integer> drawRightSide( final Path path, final int startingX, final int startingY) { int coordX = startingX + BRANCH_LENGTH; int coordY = startingY; final LineTo bottomHorizontal = new LineTo(coordX, coordY); path.getElements().add(bottomHorizontal); coordX -= DELTA_X; coordY -= DELTA_Y; final LineTo bottomBranch = new LineTo(coordX, coordY); path.getElements().add(bottomBranch); coordX += BRANCH_LENGTH; final LineTo secondHorizontal = new LineTo(coordX, coordY); path.getElements().add(secondHorizontal); coordX -= DELTA_X; coordY -= DELTA_Y; final LineTo secondBottomBranch = new LineTo(coordX, coordY); path.getElements().add(secondBottomBranch); coordX += BRANCH_LENGTH; final LineTo thirdHorizontal = new LineTo(coordX, coordY); path.getElements().add(thirdHorizontal); coordX -= DELTA_X; coordY -= DELTA_Y; final LineTo thirdBottomBranch = new LineTo(coordX, coordY); path.getElements().add(thirdBottomBranch); coordX += BRANCH_LENGTH; final LineTo fourthHorizontal = new LineTo(coordX, coordY); path.getElements().add(fourthHorizontal); coordX -= DELTA_X; coordY -= DELTA_Y; final LineTo fourthBottomBranch = new LineTo(coordX, coordY); path.getElements().add(fourthBottomBranch); return new Pair(coordX, coordY); } /** * Draw stump of tree. * * @return Path representing Christmas tree stump. */ private Path buildStumpPath() { final Path path = new Path(); int coordX = LEFT_STUMP_X; int coordY = LEFT_STUMP_Y; final MoveTo startingPoint = new MoveTo(coordX, coordY); path.getElements().add(startingPoint); coordY += STUMP_HEIGHT; final LineTo leftStumpSide = new LineTo(coordX, coordY); path.getElements().add(leftStumpSide); coordX += STUMP_WIDTH; final LineTo stumpBottom = new LineTo(coordX, coordY); path.getElements().add(stumpBottom); coordY -= STUMP_HEIGHT; final LineTo rightStumpSide = new LineTo(coordX, coordY); path.getElements().add(rightStumpSide); coordX -= STUMP_WIDTH; final LineTo topStump = new LineTo(coordX, coordY); path.getElements().add(topStump); path.setFill(Color.BROWN); return path; } /** * Build the exterior path of a Christmas Tree. * * @return Path representing the exterior of a simple Christmas tree drawing. */ private Path buildChristmasTreePath() { int coordX = TOP_CENTER_X; int coordY = TOP_CENTER_Y; final Path path = new Path(); final MoveTo startingPoint = new MoveTo(coordX, coordY); path.getElements().add(startingPoint); final Pair<Integer, Integer> bottomLeft = drawLeftSide(path, coordX, coordY); coordX = bottomLeft.getKey() + TREE_BOTTOM_WIDTH; coordY = bottomLeft.getValue(); final LineTo treeBottom = new LineTo(coordX, coordY); path.getElements().add(treeBottom); drawRightSide(path, coordX, coordY); path.setFill(Color.GREEN); return path; } /** * Create a bulb based on provided parameters and associate a MouseEvent to * it such that clicking on a bulb will increase its size and enable the glow * effect. * * @param centerX X-coordinate of center of bulb. * @param centerY Y-coordinate of center of bulb. * @param radius Radius of bulb. * @param paint Paint/color instance to be used for bulb. * @return Christmas tree bulb with interactive support. */ private Circle createInteractiveBulb( final int centerX, final int centerY, final int radius, final Paint paint) { final Circle bulb = new Circle(centerX, centerY, radius, paint); bulb.setOnMouseClicked( new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent mouseEvent) { bulb.setEffect(new Glow(1.0)); bulb.setRadius(bulb.getRadius() + 5); } }); return bulb; } /** * Add colored circles (bulbs) to the provided Group. * * @param group Group to which 'bulbs' are to be added. */ private void addBulbs(final Group group) { final Circle bulbOne = createInteractiveBulb(350,100,10, Color.RED); group.getChildren().add(bulbOne); final Circle bulbTwo = createInteractiveBulb(285,210,10, Color.YELLOW); group.getChildren().add(bulbTwo); final Circle bulbThree = createInteractiveBulb(325,300,10, Color.WHITE); group.getChildren().add(bulbThree); final Circle bulbFour = createInteractiveBulb(475,290,10, Color.BLUE); group.getChildren().add(bulbFour); final Circle bulbFive = createInteractiveBulb(380,150,10, Color.CADETBLUE); group.getChildren().add(bulbFive); final Circle bulbSix = createInteractiveBulb(550,390,10, Color.VIOLET); group.getChildren().add(bulbSix); final Circle bulbSeven = createInteractiveBulb(375,400,10, Color.GOLD); group.getChildren().add(bulbSeven); final Circle bulbEight = createInteractiveBulb(445,195,10, Color.SILVER); group.getChildren().add(bulbEight); final Circle bulbNine = createInteractiveBulb(220,385,10, Color.DARKSALMON); group.getChildren().add(bulbNine); } /** * Add text portions to Christmas Tree group. * * @param group Group for text to be added to. */ private void addText(final Group group) { final Text text1 = new Text(25, 125, "Merry\nChristmas!"); text1.setFill(Color.RED); text1.setFont(Font.font(java.awt.Font.SERIF, 50)); group.getChildren().add(text1); final Text text2 = new Text(600, 150, "2011"); text2.setFill(Color.DARKGREEN); text2.setFont(Font.font(java.awt.Font.SERIF, 75)); group.getChildren().add(text2); } /** * Starting method of JavaFX application. * * @param stage Primary stage. * @throws Exception Thrown for exceptional circumstances. */ @Override public void start(final Stage stage) throws Exception { stage.setTitle("JavaFX 2.0: Christmas Tree 2011 (Pair)"); final Group rootGroup = new Group(); final Scene scene = new Scene(rootGroup, 800, 600, Color.WHITE); stage.setScene(scene); rootGroup.getChildren().add(buildChristmasTreePath()); rootGroup.getChildren().add(buildStumpPath()); addBulbs(rootGroup); addText(rootGroup); stage.show(); } /** * Main function that kicks off this JavaFX demonstrative application. * * @param arguments Command-line arguments; none expected. */ public static void main(final String[] arguments) { Application.launch(arguments); } }
Удаление вложенного класса Coordinate уменьшает общие строки кода для приложения, но аргумент против этого заключается в том, что Pair не так удобочитаема или специфична, как Coordinate. Этот пример иллюстрирует то, что я обычно делаю: создаю простые пользовательские классы вместо использования универсальной пары.
Что может быть наиболее интересным для меня в том, что в JavaFX есть класс Pair, так это то, что, если учесть, что JavaFX, вероятно, будет стандартизирован и станет частью Java SE . Этот класс Pair вполне может оказаться в Java SDK как есть. Другими вариантами может быть включение стандартного класса java.util.Pair в качестве замены для версии JavaFX, чтобы иметь оба в SDK (имеющих более одного в самом SDK), или не добавлять новый и удалять JavaFX. версия. Есть разветвления по обслуживанию существующих приложений в любом случае. Несколько человек отметили, что использование «пары» — это запах кода или «грязное» использование, а не пользовательский объект, связывающий два атрибута. Скорее всего, использование подразумеваемого класса, специфичного для JavaFX, только сделает вещи еще более грязными (javafx.util.Pair ) в коде, который не имеет ничего общего с JavaFX или даже с презентацией или пользовательским интерфейсом.
От http://marxsoftware.blogspot.com/2012/01/pair-class-coming-to-java-via-javafx.html