Статьи

Используйте точные параметры метода Java

Узнайте, как выбрать правильные типы параметров метода и получить более надежный и короткий код в своих Java-приложениях.

У нас, Java-разработчиков, обычно есть плохая привычка использовать параметры методов, не думая о том, что на самом деле нужно, и просто выбирая то, к чему мы привыкли, что у нас есть или все, что приходит на ум. Рассмотрим следующий типичный пример:

01
02
03
04
05
06
07
08
09
10
11
12
13
private static String poem(Map<Integer, String> numberToWord) {
        return new StringBuilder()
            .append("There can be only ")
            .append(numberToWord.get(1))
            .append(" of you.\n")
            .append("Harts are better of when there are ")
            .append(numberToWord.get(2))
            .append(" of them together.\n")
            .append("These ")
            .append(numberToWord.get(3))
            .append(" red roses are a symbol of my love to you.\n")
            .toString();
    }

Когда мы используем метод выше, мы предоставляем карту, которая переводит из числа в строку. Мы могли бы, например, предоставить следующую карту:

1
2
3
4
Map<Integer, String> englishMap = new HashMap<>();
        englishMap.put(1, "one");
        englishMap.put(2, "two");
        englishMap.put(3, "three");

Когда мы вызываем наш метод poem с помощью englishMap, метод выдаст следующий результат:

1
2
3
There can be only one of you.
Harts are better of when there are two of them together.
These three red roses are a symbol of my love to you.

Это звучит неплохо. Теперь предположим, что ваш главный друг — компьютерный ботаник, и вы хотите оживить свое стихотворение и произвести впечатление, тогда вот путь:

1
2
3
4
Map<Integer, String> nerdMap = new HashMap<>();
        nerdMap.put(1, "1");
        nerdMap.put(2, "10");
        nerdMap.put(3, "11");

Если мы сейчас передадим наш nerdMap методу poem, он выдаст следующее стихотворение:

1
2
3
There can be only 1 of you.
Harts are better of when there are 10 of them together.
These 11 red roses are a symbol of my love to you.

Как и во всех стихах, трудно судить, какое стихотворение является более романтичным, чем другое, но у меня, конечно, есть свое личное мнение.

Проблемы

Есть несколько проблем с решением выше:

Прежде всего, мы не можем быть уверены, что метод poem не изменит предоставляемую нами карту. В конце концов, мы предоставляем карту, и ничто не мешает получателю делать с картой все возможное, даже полностью очищая карту. Этого, конечно, можно избежать, обернув карту с помощью метода Collections.unmodifiableMap () или предоставив копию существующей карты, в результате чего копия впоследствии будет отброшена.

Во-вторых, мы привязаны к использованию карты, когда нам нужно только то, что переводится из целого числа в строку. Это может создать ненужный код в некоторых случаях. Вспомните наш nerdMap, где значения в карте можно легко вычислить, используя Integer :: toBinaryString, а не отображать их вручную.

Решение

Мы должны стремиться предоставить именно то, что нужно в той или иной ситуации, а не больше. В нашем примере мы должны изменить метод poem, чтобы получить функцию, которая переходит от целого числа к строке. То, как эта функция реализована на стороне вызывающей стороны, имеет меньшее значение, это может быть карта или функция, или код или что-то еще. Вот как это должно быть сделано в первую очередь:

01
02
03
04
05
06
07
08
09
10
11
12
13
private static String poem(IntFunction<String> numberToWord) {
        return new StringBuilder()
            .append("There can be only ")
            .append(numberToWord.apply(1))
            .append(" of you.\n")
            .append("Harts are better of when there are ")
            .append(numberToWord.apply(2))
            .append(" of them together.\n")
            .append("These ")
            .append(numberToWord.apply(3))
            .append(" red roses are a symbol of my love to you.\n")
            .toString();
    }

Если мы хотим использовать метод poem с Map, мы просто вызываем его так:

1
2
// Expose only the Map::get method
    System.out.println(poem(englishMap::get));
1
 

Если мы хотим вычислить значения, которые мы сделали для стихотворения ботаника, мы можем сделать это еще проще:

1
System.out.println(poem(Integer::toBinaryString));

Черт возьми, мы можем даже написать стихотворение для значительного другого страдающего от двойственного расстройства личности, такого как это:

1
2
3
4
5
System.out.println(
        poem(
            no -> englishMap.getOrDefault(no + 1, Integer.toString(no + 1))
        )
    );

Это произведет следующее стихотворение:

1
2
3
There can be only two of you.
Harts are better of when there are three of them together.
These 4 red roses are a symbol of my love to you.

Будьте осторожны с параметрами вашего метода!