Как стать автором
Обновить

Комментарии 28

String value = switch (expression) {

    case 0 -> "abc";

    case 1 -> {

      String s = "def";

      yield s;

    }

    case 2, 3 -> "ghi";

    default -> "klm";

}

```Если expression == 1, то в локальную переменную s присвоится значение "abc", а далее оно будет присвоено в value``` - тут опечатка (возвращается значение abc) или я что-то не так понял (возвращается def)

да, все верно, опечатка, конечно же вернется "def"

Как по мне, единственно верной эволюцией switch в java было бы полное его выпиливание из языка. Очевидно, такого никогда не произойдёт, потому что, как минимум, обратная совместимость и все такое, но как по мне лучше бы switch вообще никак не трогали и не пытались улучшить. Его использование в коде - это очевиднейший bad smell, и чем он менее удобен, тем больше бы количество программистов от него отказывались самостоятельно в пользу более качественных решений

Если есть аргументы в его защиту - прошу, будет интересно обсудить

но у вас нет аргументов против, кроме "это очевиднейший bad smell". почему он "очевиднейший", кому "очевиднейший", почему это вообще "bad smell" - не понятно.
но давайте попробуем так: switch в коде - это очевиднейший good taste.
оппонируйте!

и еще мне хочется развить вашу мысль: предлагаю убрать "else if" в частности и "else" вообще, так как, во-первых, без них можно обойтись, а во-вторых, это "очевиднейший bad smell"(тм)

Нарушает open/close principle, скорее всего следом нарушается single responsibility, усложняет тестирование, в долгосрочной перспективе усложняет сопровождение и рефакторинг

Решает ли switch какие-то определённые задачи? Да, разумеется. Есть ли ситуации, когда его использование уместно? Может быть, готов допустить, что да. Обычно же его использование только ухудшает код, не привнося никаких бонусов

пока вижу лишь голословные утверждения.
нет, не нарушает.
нет, не усложняет.

все, что вы описали - это вопросы дизайна структуры классов, которые не имеют отношения к оператору языка.

можно ли использовать оператор не корректно и нарушить общепринятые принципы дизайна?
да, можно.
вот только, при чем тут сам оператор языка?

Использование switch в процедурных языках, вероятно, имело смысл. Собственно, само его существование - это наследие процедурного стиля. В ООП парадигме switch скорее всего означает, что программист просто не понимает ООП, у него плохая иерархия классов, и он не умеет в полиморфизм. На эту тему есть огромное количество статей в интернете, рекомендую к прочтению. Может, хоть тогда станет понятно, почему это считается за bad smell, и какие есть способы его избегать

Да, в общем и целом, это все проблемы дизайна классов, а не оператора. Просто так получается на практике, что этот оператор либо сам по себе является призраком уже плохого дизайна, либо, если мы с самого начала где-то начали его использовать, он приведёт к плохому дизайну

Мне неинтересно вести диалог, в котором ответом на мои аргументы являются фразы в стиле "нет, не так". Как и неинтересно объяснять вещи, которые уже многократно разжеваны всем, кому не лень

Будут конкретные аргументы в защиту switch, которые сделают его использование осмысленным, а не признаком того, что программист не умеет в полиморфизм - продолжим диалог

Ну, в этой ситуации вы оба не привели никаких примеров или доводов. Я вижу ничем не обоснованные факты и такие же ответы "да/нет". Это не имеет никакого смысла)

Есть бесспорный аргумент в пользу использования switch: он быстрее if-else. Ваших аргументов я не понимаю, т.к. switch - аналог if-else. В частности, какое отношение switch имеет к ООП. В общем, вероятно, вы друг друга просто не понимаете)

Лично я считаю, что использование проверок типов может использоваться только в крайнем случае. Например, если существует готовая библиотека, в которой не реализован функционал для какого-то класса. Конечно, есть наследование, но что, если класс final? В этом случае без этого не обойтись. Это единственная связь с ООП, которую я пока что увидел, прочитав комментари. Но то же можно сделать и с использованием if-else

Вы считаете, что использование этого оператора приводит к плохому дизайну в коде. Эти выводы были сделаны на основании статей, но, очень часто, статьи рассматривают лишь одну сторону медали, на которую натолкнулся автор. Если есть реально интересные статьи, где рассматривается switch как причина плохого дизайна кода, и при этом учитывается его высокая эффективность - буду благодарен, если скинете. Возможно, перестану писать плохой код :)

Это выводы, сделанные не из статей, а из некоторого количества практического опыта. Я раньше тоже не понимал, чем плох switch. Да чего уж там, я когда-то и goto пользовал, и настаивал, что ничего плохого в нем нет, если использовать его аккуратно. А потом (с опытом, опять же) лучше начал понимать ООП, и пришёл к тому, о чем говорил выше - желание использовать некоторые конструкции само по себе выдаёт то, что что-то с кодом не в порядке

Заменять switch на череду if-else - это, разумеется, нифига не решение, и я вовсе не предлагаю делать так. Если уж на то пошло, то switch можно заменить на Map или любую другую коллекцию

В таком случае жуть вида:

switch (condition) {

case_1: action_1(); break;

case_2: action_2(); break;

...

case_n: action_n(); break;

}

Заменяется на гораздо более элегантное:

Action action = actionsMap.get(condition);

if (action != null) { action.perform(); }

Если в будущем добавится новый case, то он автоматом подтянется в этот Map (подразумеваем использование Spring или какого-то иного DI), код получается короче, появляется разделение обязанностей (у нас теперь не один класс, который и выбор нужной логики делает, и саму логику исполняет, а много маленьких, каждый из которых занимается чем-то своим), проще для понимания, его легче тестировать и сопровождать

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

хотите я покажу использование break (label) в коде JDK? )
или использование switch тоже в коде JDK?

давайте еще раз попробую свою мысль озвучить: switch - это оператор языка.
он не имеет никакого отношения к дизайну структуры классов.
он присутствует во многих объектно-ориентированных языках.
он есть в C#, Go, Kotlin, Rust и много где еще.
вы беретесь утверждать, что понимаете ООП лучше, чем дизайнеры C#, Go, Kotlin или Rust, которые изначально создавались как ООП языки?

я не понимаю аргументов в стиле "switch нарушает open/close принцип".
это нонсенс!
оператор языка не может нарушать правила дизайна структуры классов!

я готов поверить, что вы встречались с кодом, где оператор switch использовался не правильно.
но и кухонные ножи, знаете ли, бывает используют не по назначению.
разве это повод запрещать кухонные ножи?

еще давайте я покажу это

https://github.com/spring-projects/spring-framework/blob/1af64802174c0122b59a2178f17f8f1d2b4cbcd4/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java#L143

что есть ни что иное, как switch с паттерн-матчингом (если бы исходники спринга кто-нибудь решился переписать на яву версии больше 17) и чем вы наверняка пользуетесь в своих проектах на спринге
а вы мне скажите, что авторы спринга "не умеют в полиморфизм" и не знают про solid

В том же самом спринге в свое время было огромное количество недоработок, которые исправлялись просто за минуты (рекомендую видео Евгения Борисова: что-то было в java puzzlers, что-то в spring потрошитель/построитель на эту тему), но они жили в спринге годами. Может, и до сих пор живут. Технологию пишут люди, а люди совершают ошибки

ясно. Россен не умеет в полиморфизм и не знает про DI.

тогда давайте посмотрим в исходник метода lengthOfMonth класса LocalDate, который выглядит так

public int lengthOfMonth() {
        switch (month) {
            case 2:
                return (isLeapYear() ? 29 : 28);
            case 4:
            case 6:
            case 9:
            case 11:
                return 30;
            default:
                return 31;
        }
    }


авторы JDK тоже не умеют в полиморфизм?

или может тут тоже надо создать на хипе дополнительный Map, дополнительный массив, дополнительные списки под каждую ячейку массива, в те списки положить дополнительные объекты типа Node, в которые положить врапперы над int? И все это ради... ничего?

кажется, что дизайнеры JDK хорошо понимали, что делают, использовав тут switch на закрытом множестве )

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

И, пожалуйста, перестань уже апеллировать к авторитетам. То, что кто-то где-то что-то делает, не означает, что следует делать так же

так.. оказывается не все случаи в мире покрываются спрингом и не везде у нас есть DI. это уже прогресс.

хотелось бы напомнить, что JDK - это открытая платформа и любой может сделать ее лучше. рекомендую предложить свой PR и вписать свое имя в историю развития JDK!

хотя, мне трудно сходу представить, как можно улучшить код, который скомпилируется в несколько ассемблерных инструкций.
но буду искренне рад увидеть твои улучшения в JDK 25

я и не говорил ни разу, что все на свете покрывается спрингом и DI. Есть и другие способы избегать switch, кроме как использовать коллекции с autowired

из JDK switch не выпилят, даже если весь мир вдруг резко признает его ущербность, потому что "обратная совместимость", так что не вижу смысла даже обсуждать это

и, опять же, если ты ставишь максимальную производительность приоритетом, то тебе, быть может, вообще не java нужна. И как минимум мы обсуждаем разные вещи. Мне пофигу незначительная потеря производительности, мне важнее, чтобы код было легко читаем, тестируем и поддерживаем в будущем. switch с этим не справляется, почему - я приводил выше

не приводил. ни одного разумного аргумента.
код со switch прекрасно тестируется и поддерживается.
"поддерживаемость" и "тестируемость" определяются не операторами языка, а самим кодом.

утверждать, что switch влияет на тестируемость - это то же самое, что утверждать, что использование if влияет на тестируемость.

Жду от тебя пример кода на java, как ты тестируешь количество возможных вариантов в switch

Давайте я ещё раз попробую донести свою: switch - это наследие процедурного языка, при ООП подходе его легко избежать и тем самым повысить качество кода

Твой аргумент (давай на "ты"?) сейчас - это буквально когнитивная ошибка "апелляция к авторитету". Типа вон те чуваки написали язык, уж им-то лучше знать, как писать код. А вот и не лучше. Люди совершают ошибки

Насчет нарушения open/close. Окей, вот тебе пример: надо добавить новый case. В моем коде с Map выше я просто добавлю новую имплементацию Action, повешу на неё какой-нибудь @Component,и она автоматически подхватится в коде. Мне не придётся изменять уже существующий код для добавления нового функционала. В switch придётся ещё и существующий код редактировать. А если таких мест не одно, а несколько, и программист банально упустит какой-нибудь из нескольких switch-ей? Привет, бага в продакшане

Ещё раз. switch вполне решает свои задачи. Тем не менее, вообще ничего не стоит избавиться от него ради лучшего код стайла (кроме чуть худшей производительности) и своего же собственного лучшего будущего, где тебя не разбудят в 5 утра звонком, что продакшн лежит (и хорошо если просто лежит, а не работает неправильно и клиент каждую секунду теряет деньги)

Давай так. Можешь привести хоть один пример кода, где я не смогу переписать switch на что-то более нормальное?

Давай так. Можешь привести хоть один пример кода, где я не смогу переписать switch на что-то более нормальное?


давай так. я могу переписать код, использующий оператор '%' так, чтобы этот оператор не использовался.
Могу переписать так, чтобы вычитание не использовалось.

Это повод убирать эти операторы из языка?

оператор языка не может что-то нарушать или как-то влиять на мифический "code style".
оператор switсh, или if-else не может нарушать open-close точно так же, как оператор "+" не может нарушать принцип подстановки Лисков.

можно ли нарушить open-close используя оператор switch? можно конечно! а еще его можно нарушить используя if-else.
а еще можно вообще не используя операторы ветвления его нарушить.

похоже ты не чувствуешь разницы между дизайном языка и дизайном структуры классов, написанных на этом языке.

Я привел даже конкретный пример кода, как и объяснил, каким образом использование switch нарушает open/close. Ты опять не приводишь никаких конкретных аргументов против моих или в защиту switch, а просто отвечаешь в стиле "нет, не так". У меня вообще создаётся впечатление, что ты споришь не с моим мнением, а лично я тебе не нравлюсь

нет, просто я искренне никак не могу понять твои аргументы. Пока я вижу аргумент в стиле "в этом частном случае можно написать код без использования switch, поэтому оператор надо убрать из языка вообще".

это даже близко не аргумент.
это просто частный случай реализации паттерна "стратегия", который можно делать на switch, но более "канонично" сделать через наследование или с помощью DI.

этот частный случай никакого отношения не имеет к наличию оператора в языке.

и нет, switch - это не "процедурное наследие". это утверждение в корне не верно.
рекомендую почитать то, как дизайнили тот же котлин и почему там есть оператор when.
причем, можно даже напрямую к главному дизайнеру обратиться с этим вопросом. даже на русском. вот просто написать в любой соцсети вопрос: "Андрей, скажи, зачем ты запихнул процедурное наследие в виде when в новенький мультипарадигменный язык?!"
он даже, наверняка, аргументированно ответит.
но, все же, рекомендую сначала почитать.

у нас тут статья про java и обсуждение конкретного оператора конкретно в java. Мне неинтересно, что там происходит в kotlin, c#, go или каких-то других языках, или какими аргументами руководствовались те или иные люди, создавая эти языки. Конкретно в java я ни разу не видел ситуаций, где использовался бы switch, которые нельзя было бы переписать в более качественный код стайл

Диалог начался с того, что я высказал свое мнение, что switch ущербен, и привел примеры, почему я так считаю. Ты из раза в раз мне говоришь про другие языки, где этот оператор или его аналоги используются, и ссылаешься на каких-то людей, которые его используют. Я и так знаю, что этот оператор используется, но это ни разу не опровергает мои аргументы, почему он плох, и даже хотя бы тот один пример кода, что я привел, как его можно избежать

приведи хотя бы один пример, когда switch будет уместен, когда я не смогу переписать его на что-то более адекватное, и я пересмотрю свое мнение. До тех пор же считаю продолжение диалога нецелесообразным

Мне неинтересно, что там происходит в kotlin, c#, go или каких-то других языках, или какими аргументами руководствовались те или иные люди, создавая эти языки.

очень зря. именно поэтому и появляются странные мысли об "ущербности" операторов. а если бы интересовался, как дизайнятся языки и какими доводами руководствуются их создатели, то таких странных мыслей бы не возникало.

приведи хотя бы один пример, когда switch будет уместен

приводил уже выше.

никаких аргументов, почему оператор switch плох ты не привел.
один жалкий частный случай "некрасивого" использования switch не является аргументом против наличия оператора в языке.

switch - не процедурное наследие. Процедурное наследие - goto. Вот этот оператор реально может похерить code style) после него и появилось структурное программирование, в основе которого лежит утверждение: любую программу можно написать с помощью линейных переходов, условий и циклов. switch работает немного иначе, нежели goto с метками. И мне казалось, что switch появился позже, но тут могу ошибаться.

switch действительно можно избежать, но главный вопрос - целесообразность. Если это увеличит количество кода в разы, ещё и убавляя производительность (например, заменив его на какой-то класс), то сколько методов open/close не придерживайся, а код будет куда менее читабельным и его будет труднее редачить. Так что предлагаю сделать вывод: большие конструкции в switch действительно не стоит пихать, потому что это смотрится дико. Но для простых задач switch прекрасно подходит

Я вроде осознал главную мысль спора. WieRuindl считает, что switch - лишняя обёртка над вызовом соответствующего метода. Но это далеко не во всех случаях так. Например, есть метод получения количества дней в месяце, представленный GreyN. Этот код невозможно улучшить, switch идеально вписывается сюда. Так что предлагаю закончить дискуссию и принять, что бывают случаи, когда switch упрощает жизнь, но использовать его где попало - нельзя

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории