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