Почему две равные строки не совпадают?

Я хочу сравнить ответ от сервера с нить, но при тестировании двух строк получаю ложный результат. Почему?

Я нашел это, но не помогло: Как сравнить строки в Java?

Я пробовал два способа:

BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF8"));
String code;
if (Objects.equals((code = in.readLine()), "S")) { //Input string: "S"
    //code
}

BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF8"));
String code;
if ((code = in.readLine()).equals("S")) { //Input string: "S"
    //code
}

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

Полный код

На стороне сервера - C# (Windows)

class ManagePhoneClients
    {
        public void managePhoneClients(object obj)
        {
            Boolean socketalive = true;
            TcpClient tcpClient = (TcpClient)obj;
            StreamReader sr = new StreamReader(tcpClient.GetStream(), Encoding.UTF8);
            StreamWriter sw = new StreamWriter(tcpClient.GetStream(), Encoding.UTF8);
            Boolean isPhoneClientConnected = false;
            String user;
            String answer;
            String tl;
            List<string> LC = new List<string>();
            Boolean qss = false;
            Program program = new Program();
            Int32 points = 0;

            ConsoleMethods.writeLine("Thread started for the phone client.", "Info", ConsoleColor.Cyan);

            sw.WriteLine("S");
            sw.Flush();

            while (socketalive == true)
            {
                try
                {
                    if (Program.isMainClientConnected != true || Program.isPowerPointConnected != true)
                    {
                        ConsoleMethods.writeLine("Connection refused because the necessary clients are not connected!", "Error", ConsoleColor.Red);
                        sw.WriteLine("NS");
                        sw.Flush();
                        tcpClient.Close();
                        socketalive = false;
                    }
                    else
                    {
                        sw.WriteLine("LC");
                        sw.Flush();
                    }
                    if (isPhoneClientConnected != true & sr.Peek() != -1)
                    {
                        String rLC = sr.ReadLine();
                        LC.AddRange(rLC.Split('|'));
                        if (LC[1].ToString() == Program.passPhoneClient)
                        {
                            user = LC[0];
                            Program.userNames.Add(user);
                            ConsoleMethods.writeLine("Phone connected from: " + tcpClient.Client.RemoteEndPoint, "Info", ConsoleColor.Cyan);
                            sw.WriteLine("S");
                            sw.Flush();
                            Program.utnr = rLC;
                            isPhoneClientConnected = true;
                        }
                        else
                        {
                            sw.WriteLine("NS");
                            sw.Flush();
                            socketalive = false;
                            ConsoleMethods.writeLine("Phone client disconnected because the password was invalid!", "Error", ConsoleColor.Red);
                        }

                    }
                    switch (sr.ReadLine())
                    {
                        case "CLIENT-EXCEPTION":
                            ConsoleMethods.writeLine("Exception in phone client from: " + tcpClient.Client.RemoteEndPoint + "\n" + sr.ReadLine(), "Client-Error", ConsoleColor.DarkRed);
                            break;
                        case "RECEIVED_POINTS":
                            int point = int.Parse(sr.ReadLine());
                            points += point;
                            ConsoleMethods.writeLine("Phone client succesfully completed a task from: " + tcpClient.Client.RemoteEndPoint + " Point: " + point, "Client-Received Points", ConsoleColor.DarkRed);
                            ConsoleMethods.writeLine("Phone client collected points from: " + tcpClient.Client.RemoteEndPoint + " Points: " + points, "Client-Collected Points", ConsoleColor.DarkRed);
                            break;
                    }

                }
                catch (Exception e)
                {
                    tcpClient.Close();
                    socketalive = false;
                    ConsoleMethods.writeLine(e.Message + e.StackTrace + e.StackTrace, "Error", ConsoleColor.Red);
                }
            }
        }
    }

(Это еще не закончено!)

Клиентская сторона - Java (Android)

   public void login(View v) {
        final Context context = this;
        new Thread(new Runnable() {
            public void run() {
                try {
                    final Socket socket = new Socket("192.168.0.104", 90);
                    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF8"));
                    PrintWriter out = new PrintWriter(socket.getOutputStream());
                    out.print("P" + "\r\n");
                    out.flush();
                    String code;
                    code = in.readLine();
                    if (code.equals("S")) {
                        if (Objects.equals((code = in.readLine()), "LC")) {
                            out.print(((EditText)findViewById(R.id.username)).getText().toString() + "|" + ((EditText)findViewById(R.id.password)).getText().toString() + "\r\n");
                            out.flush();
                            if (Objects.equals((code = in.readLine()), "S")) {
                                new ServerContact(context).Listener(socket);
                                startActivity(new Intent(Login.this, Waiting.class));
                            } else {
                                throw new Exception("Login failed because the server refused the login request. Server responded with status code: '" + code + "'.");
                            }
                        } else {
                            throw new Exception("Login failed because the server refused the login request. Server responded with status code: '" + code + "'.");
                        }
                    } else {
                        throw new Exception("Login failed because the server refused the login request. Server responded with status code: '" + code + "'.");
                    }
                } catch (Exception e) {
                    new ExceptionWriter(e);
                }
            }
        }).start();
    }

(Это еще не закончено!)

Что ж, результаты показывают, что строка, которую вы получаете от readLine, не"S". Поэтому лучше всего использовать отладчик, встроенный в вашу среду IDE, на примере переменной code и посмотреть, каково реальное содержимое.

T.J. Crowder 07.04.2018 20:22

Возможно, вы получаете непечатаемые символы. Используйте отладчик для проверки содержимого code. (Тривиально выведите его длину).

Andy Turner 07.04.2018 20:22

Как узнать, что code - это "S"? Может, в нем есть какие-то символы нулевой ширины? Преобразуйте строку в массив символов и выведите целочисленное значение каждого символа.

Sweeper 07.04.2018 20:23

@Sweeper: Или ... использовать отладчик? Когда вы можете включить свет, вам не нужно спотыкаться в темноте с фонариком System.out.println. :-)

T.J. Crowder 07.04.2018 20:24

@ T.J.Crowder Я не вписывал это в вопрос, но в случае ложного теста выдает исключение, содержащее значение code.

Noel Nemeth 07.04.2018 20:34

Ну и какова стоимость code? Также будьте осторожны, readLine() может вернуть null.

markspace 07.04.2018 20:35

На стороне Windows: вам передается объект TcpClient, который вы затем оборачиваете? Таким образом, кто-то мог уже написать мусор, который вы видите на стороне Android, даже если вы сами не писали это в этом методе (см. Комментарии к моему ответу ниже).

markspace 07.04.2018 22:04

Думаю, мне удалось решить проблему. Когда я заменил Ecoding.UTF8 на new UTF8Encoding(false), клиент успешно завершил все испытания.

Noel Nemeth 07.04.2018 22:19

Так что тогда это была спецификация. Извини, что не узнал раньше.

markspace 07.04.2018 22:43

Кроме того, вы можете добавить свой ответ и отметить его правильным. Это нормальная процедура в подобных случаях.

markspace 07.04.2018 22:44
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
10
200
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

У меня работает (используя ваш первый случай). Я думаю, мы все пришли к выводу, что code на самом деле не равен "S", извините за это.

public class EqualsTest {

   public static void main( String[] args ) throws IOException {
      MyStream socket = new MyStream( new ByteArrayInputStream( "S\n".getBytes() ));

      BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream(), "UTF8" ) );
      String code;
      if ( Objects.equals( (code = in.readLine()), "S" ) ) { 
         System.out.println( "true" );
      } else {
         System.out.println( "false" );
      }
   }

   static class MyStream {
      private final InputStream ins;

      public MyStream( InputStream ins ) {
         this.ins = ins;
      }

      public InputStream getInputStream() {
         return ins;
      }

   }
}

Выход:

run:
true
BUILD SUCCESSFUL (total time: 0 seconds)

Добавлю несколько идей по тестированию code для отладки:

     // how to debug
     System.err.println( "code = "+code+" length = "+code.length() );
     System.err.println( "code bytes = "+Arrays.toString( code.getBytes() ) );

Это интересно ... На самом деле "S" не совпадает с серверной "S". CODE = [-17, -69, -65, 83]S = [83]

Noel Nemeth 07.04.2018 21:00

Я вижу букву «S» в конце вашего ввода (83), но у вас явно есть какой-то другой мусор. Я думаю, возможно, вы не декодируете UTF-8, это может быть какое-то другое декодирование. Возможно, в вашем вводе также есть спецификация, хотя я дважды не проверял ее значения, чтобы быть уверенным.

markspace 07.04.2018 21:01

Возможно ли, что проблема в том, что сервер находится на C#, а клиент работает на java (Android)? Обе стороны имеют кодировку UTF-8.

Noel Nemeth 07.04.2018 21:12

Все UTF-8 должны быть одинаковыми. Если вы работаете на машине с Windows, я думаю, что более вероятно, что входной поток - это cp-1252 и содержит спецификацию, хотя я признаю, что для меня это не похоже на спецификацию.

markspace 07.04.2018 21:17

@NoelNemeth Или, конечно, код C# мог быть ошибочным / сломанным / делать неправильные вещи. Попытайтесь получить точную спецификацию того, что точно делает эта часть кода, от того, кто ее написал. Если у вас есть источник, добавьте его в свой вопрос выше.

markspace 07.04.2018 21:20

Я добавил как серверный, так и клиентский полный код.

Noel Nemeth 07.04.2018 21:52

@NoelNemeth Дополнительные байты (-17, -69, -65) - это байтовая кодировка спецификации UTF-8 (0xef, 0xbb, 0xbf). Вам необходимо указать серверу CS не отправлять в UTF-8 спецификацию.

Thomas Kläger 08.04.2018 10:35
Ответ принят как подходящий

Мне удалось это решить. На стороне сервера я должен отключить спецификацию.

Нет спецификации:

StreamWriter sw = new StreamWriter(tcpClient.GetStream(), new UTF8Encoding(false));

Со спецификацией:

StreamWriter sw = new StreamWriter(tcpClient.GetStream(), Encoding.UTF8);

Вы должны отметить этот ответ как правильный, если это решение.

markspace 08.04.2018 21:46

@markspace Я знаю, но мне нужно подождать 48 часов после публикации ответа.

Noel Nemeth 09.04.2018 15:46

Ах, тогда моя ошибка. Извини за это.

markspace 09.04.2018 20:04

Другие вопросы по теме