Возвращает внутри ifs запутывает Java

#java #if-statement #return

#java #if-statement #Возврат

Вопрос:

У меня есть эти два метода, и Java не может найти «возврат» в getNumEmails(). Все они находятся в одном классе, который имеет только статические методы

 private static int posSymbol=0;
private static int cont=0;
private static String text=null;


private static int getPosSymbol(){
     posSymbol=text.indexOf('@',posSymbol);//if there is no symbol, returns -1
     return posSymbol;
}

//Main calls this method
public static int getNumEmails(String completeText){
     text=completeText;

     while(posSymbol!=(-1)){

         posSymbol=getPosSymbol();

         if(posSymbol!=(-1)){
              cont  ;
              posSymbol  ;
         }//close if
         else{
              return cont; //It seems that it doesn't reach the return always
         }//close else
         }//close while
}//close method
  

Я знаю, что решение простое: удалить «else» и поставить return cont; через некоторое время. Но я хочу знать, почему Java считает, что getNumEmails() может завершиться, ничего не возвращая.

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

1. Он, безусловно, завершится без возврата, если значение getPosSymbol() равно -2 или никогда не было -1…

2. Что заставляет вас думать, что он всегда будет что-то возвращать? else Предложение может никогда не выполняться.

3. @Kendrick. верно, но компилятор не собирается углубляться в этот уровень проверки. Это просто просмотр else .

4. @Arkonor — Итак, вы знаете, с этим кодом есть серьезные потенциальные проблемы. Самый неприятный из которых — если вы попытаетесь использовать этот многопоточный. Самым неприятным из которых является то, что его нельзя запустить дважды (в некоторых случаях). Кроме того, не ставьте комментарии в закрытых скобках; большинство современных IDE будут выделять пары открытых / закрытых скобок, ваши методы не должны быть достаточно длинными, чтобы они были необходимы, и они рискуют рассинхронизироваться.

5. @Kendrick. getPosSymbol не может возвращать -2 или бесконечные значения, потому что. a) indexOf() возвращает -1 или возможное значение, если находит совпадение для символа. б) Я сомневаюсь, что строка, которую он получает, не может иметь конца (возможно, захват текста, который транслируется в потоковом режиме или что-то странное, но в моем случае источником текста является ввод с клавиатуры)

Ответ №1:

Я полагаю, это связано с жалобами компилятора This method must return a result of type int .

Хотя компиляторы иногда могут определить, достигнет ли функция оператора return, это не всегда так. Математически невозможно статически определить динамическое поведение программы.
В информатике это называется «проблемой остановки»; в общем случае невозможно определить, завершится или не завершится программа.
Таким образом, даже если вы можете определить, что метод всегда будет достигать одного из ваших return операторов, компилятор может быть не в состоянии этого сделать.

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

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

2. Теперь, когда я думаю об этом. Если бы программа была более сложной, у меня могло бы возникнуть много проблем, чтобы найти другой способ ее решения. В этом случае мне просто нужно поставить «return» после «while», но в другой программе это невозможно

3. Кстати, как я могу использовать ключ возврата, не добавляя комментарий по ошибке XD

4. Как указывали другие, в данном конкретном случае на самом деле существует путь выполнения, где return никогда не встречается. Технически говоря, компилятор может найти return , он не может определить все пути выполнения. В более сложных алгоритмах… ну, решение этих проблем — это просто еще одна часть программирования, не так ли?

5. Но вы не можете избежать ввода в «while», поссимвол устанавливается равным нулю до того, как это «while» встречается. Я также пытался установить его равным нулю непосредственно перед while, и все же это вызывало у меня проблемы

Ответ №2:

Он может найти возврат в предложении else . Проблема в том, что вам нужно иметь возврат для всех путей выполнения, даже для того, когда posSymbol равно -1, поскольку, когда posSymbol равно -1, вы никогда не входите в цикл while.

Следовательно, вам нужен возврат после оператора while.

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

1. Но getPosSymbol(), который находится внутри цикла while, может возвращать значение -1 после проверки условия while.

2. Но это не то, как вы пишете код. Оператор while имеет область действия, которая никогда не будет выполнена, если не будет выполнено условие в предложении while . Поскольку оператор return находится в области while, он не будет выполнен по этой причине.

3. Я могу заверить вас, что я пытался установить posSymbol=0 непосредственно перед While, и все равно это не сработало

4. Дело не в этом. Компилятор не может сделать вывод, что он никогда не покинет цикл while в любом последовательном цикле, поэтому ему все равно нужен оператор return после этой области. Компилятор не выполняет никакого анализа, чтобы проверить, всегда ли условие переменной истинно или всегда ложно, он знает, что, учитывая, что у вас есть while, в любых следующих за ним операторах должен быть оператор return, потому что в объявлении вашего метода указано, что значение должно быть возвращено.

Ответ №3:

Просто добавьте a return 0; после «//close while».

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

1. Может случиться так, что метод возвращает 2 разных значения до его завершения. Это может привести к сбою всей программы. Извините, но это не решает мою проблему.

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

3. Разрыв существует только для блока, такого как циклы for / while или условия переключения / обращения.

Ответ №4:

Не ответ, но вот гораздо более безопасная версия метода без статических переменных.

 //Main calls this method 
public static int getNumEmails(String completeText)
{
    int posSymbol=0, count=0;
    while(posSymbol!=(-1))
    {           
        posSymbol=completeText.indexOf('@',posSymbol); //if there is no symbol, returns -1
        if(posSymbol!=(-1))
        {
              count;
              posSymbol;
        }//close if
    }//close while
    return count;
}//close method 
  

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

1. Это то, что я сделал в конце. Я понял, что else также означает, что программа завершается. Поэтому я могу поместить возврат через некоторое время, чтобы быть уверенным, что программа всегда встречает возврат.

2. @Kendrik — Согласен, это намного безопаснее. Однако, как насчет того, чтобы поместить indexOf() вызов внутри проверки условий для while цикла?

Ответ №5:

Компилятор Java не может статически (во время компиляции) проверить, что while цикл вообще выполняется ( posSymbol может быть -1 при первом вызове). Отсюда и ошибка.

В общем, не стоит сохранять состояние цикла в переменных-членах. Что, если более одного потока выполняет ваш метод (например, на веб-сервере)? В долгосрочной перспективе легче отслеживать ошибки, если ваш код не изменяет глобальное состояние:

 public static int getNumEmails(String completeText) {
    int count = 0;
    Matcher m = Pattern.compile("@").matcher(completeText);
    while (m.find()) {
        count  ;
    }
    return count;
}
  

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

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

2. Этот код пытается определить, сколько @ s есть в completeText , используя регулярное выражение. Вы можете посмотреть его здесь: download.oracle.com/javase/7/docs/api/java/util/regex /.