Страницы

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

пятница, 12 апреля 2019 г.

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

Проблема заключается в необходимости задания значения 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)


Ответ

Ответ-вопросник и очередной наброс на медальку.
Итак, у вас было что-то вот такое:
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 и где-то сделайте проверку.
Предложенный вариант с массивом - это либо то самое создание объектов и выделение памяти, с которым вы сражаетесь, либо потеря подключений и обработка одного подключения несколько раз, смотря где вы этот массив объявите.

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

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