Страницы

Поиск по вопросам

суббота, 8 февраля 2020 г.

Java. Задание занчения (final) переменной в try-блоке и ее дальнейшее использование и видимость

#java #переменные #инициализация #try_catch


Проблема заключается в необходимости задания значения final переменной (connectionSocket2)
в try-блоке. В дальнейшей части кода (в части run()) этого не видно и возникает как
бы ошибка, что та переменная не определена:

        final Socket connectionSocket;
        try { connectionSocket = welcomeSocket.accept(); }



  The local variable connectionSocket2 may not have been initialized


убрать final не могу, так как (в части run()) дает ошибку 


  Cannot refer to the non-final local variable connectionSocket defined
  in an enclosing scope


            Socket connectionSocket2=null;
            try { connectionSocket2 = welcomeSocket.accept();
            } catch (IOException e2) { e2.printStackTrace(); }
            final Socket connectionSocket=connectionSocket2; try{connectionSocket2.close();}catch(IOException
e1){e1.printStackTrace();}

            service.submit(new Runnable() {
                public void run() {
                    while (true) {
                        BufferedReader inFromClient=null;
                        DataOutputStream outToClient=null;
                        try{
                           inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
                           outToClient = new DataOutputStream(connectionSocket.getOutputStream());
                           outToClient.writeBytes(inFromClient.readLine());
                        } catch(IOException ioe) {} }}});


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

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

Как правильно, профессионально быть в этой ситуации? Модно ли как-то сказать компилятору,
что переменная на самом деле уже определена в try блоке и ему нечего "волноваться"?
(типа динамическая переменная, как в .Net)
    


Ответы

Ответ 1



Ответ-вопросник и очередной наброс на медальку. Итак, у вас было что-то вот такое: public class ICanIntoSockets { public static void main( String[] args ) throws IOException { ServerSocket welcomeSocket = new ServerSocket(10000); ExecutorService service = Executors.newCachedThreadPool(); doWork( welcomeSocket, service ); } public static void doWork( ServerSocket welcomeSocket, ExecutorService service ) { try { while (true) { final Socket connectionSocket = welcomeSocket.accept(); service.execute( () -> { try ( Socket socket = connectionSocket; BufferedReader inFromClient = new BufferedReader( new InputStreamReader(socket.getInputStream())); DataOutputStream outToClient = new DataOutputStream( socket.getOutputStream())) { outToClient.writeBytes(inFromClient.readLine()); } catch (IOException ioe) { ioe.printStackTrace(); } }); } } catch ( IOException ex ) { ex.printStackTrace(); } } } но try - плохо, и торморзит на тысячах подключений (тесты где?), поэтому вы решили от него избавиться. Ява - убогий язык, в ней зачем-то придумали Checked Exceptions и напихали во все места в стандартной библиотеке, поэтому совсем без try - никак: public static void doWork( ServerSocket welcomeSocket, ExecutorService service ) { while (true) { final Socket connectionSocket; try { connectionSocket = welcomeSocket.accept(); } catch (IOException ex) { ex.printStackTrace(); } service.execute(() -> { try ( Socket socket = connectionSocket; // The local variable connectionSocket may not have been initialized BufferedReader inFromClient = new BufferedReader( new InputStreamReader(socket.getInputStream())); DataOutputStream outToClient = new DataOutputStream(socket.getOutputStream())) { outToClient.writeBytes(inFromClient.readLine()); } catch (IOException ioe) { ioe.printStackTrace(); } }); } } Зло загнано в угол в одной строчке кода! Но компилятор почему-то считает, что переменная connectionSocket может быть не инициализирована. Почему? Потому что есть путь выполнения программы, при которой она действительно не инициализируется: когда welcomeSocket.accept() выбрасывает исключение. Метод не возвращает значение - значение переменной не присваивается. Что же делать? Не надо продолжать выполнение итерации, ваш код все равно не сможет работать дальше без клиентского сокета. Сделайте внутри catch-блока return, break, continue (в надежде, что следующий accept не выбросит исключение, что вряд ли). Если код непременно должен продолжаться дальше - присвойте connectionSocket null и где-то сделайте проверку. Предложенный вариант с массивом - это либо то самое создание объектов и выделение памяти, с которым вы сражаетесь, либо потеря подключений и обработка одного подключения несколько раз, смотря где вы этот массив объявите.

Ответ 2



Можно обёртку сделать: public class MySocket{ private Socket mSocket; public MySocket(){ } public void setSocket(Socket socket){ mSocket = socket; } public Socket getSocket(){ return mSocket; } } И создать его экземпляр: final MySocket connectionSocket = new MySocket(); И дальше: try{ connectionSocket.setSocket(welcomeSocket.accept()); } catch (IOException e2) { e2.printStackTrace(); } И внутри Runnable обращаться к connectionSocket.getSocket().

Ответ 3



создайте final Socket[] на один элемент и в пишите в него.

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

Отправить комментарий