#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[] на один элемент и в пишите в него.
Комментариев нет:
Отправить комментарий