|
|
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
Вообщем ребят изучаю java ну и написал небольшую утилитку для добавления отчетов (fastreport) на сервер Oracle используя для этого базу данных. Мне самому сложно понять какие ошибки я допустил при написании (ну или все это одна большая ошибка) нужен взгляд со стороны более опытных людей. Програмулину выложил на гитхаб https://github.com/GaraZ/ReportsLoader ну и прикрепил к теме (без jdbc библиотеки) Всем зарание спасибо за участие )) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 14:51:32 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
GaraZ, правильно писать "в общем" ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 16:10:45 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
GaraZ, правильно писать "в общем" ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 16:13:45 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
J.Serge, ну і так добре ) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 16:14:32 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
J.Serge, я так понимаю вы дальше первого предложения читать не стали? )) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 16:24:46 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
Для junior девелопера - норм. В целом - много мелких косяков. Странное соглашение об именновании переменных. Многое можно было сделать проще с использованием сторонних библиотек. Crypt.KEY_DATA - отличное место чтобы хранить ключь. Так нельзя писать. Это заготовка для будущих ошибок. Код: java 1. 2. Можно так Код: java 1. и так Код: java 1. 2. 3. TreeMap<String,HashMap<String,String>> - очень странная структура, чтобы хранить конфиг. Лучше было сделать объектами. Для объявления переменных использовать лучше интерфейсы коллекций: Map<String,Map<String,String>> А не конкретные реализации. Кроме случаев, где тип нужен явно, например при сериализации. Методы setProfiles/getProfiles - вынос мозга. Понятно что такой кривой DOM API в Java, лучше было взять что-то другое для работы с XML. JavaDoc оформление странное. Коментарии к классам и методам пишутся иначе. Методы возвращающие 0\1 похожи на смесь логики и представления. А если отчету нужно будет Y/N? try-with-resource используется в IO, но не используется в JDBC. Почему? Не используется Connection Pool. Даже без него DriverManager.getConnection не стоило копипастить во все методы. Buffered(Input|Output)Stream - где-то используется, а где-то нет. Написан свой метод копирование in->out, но не везде используется. new String(" ") - что за финт ушами? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 16:36:40 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
Blazkowicz, огромное спасибо за ответ ) BlazkowiczДля junior девелопера - норм. В целом - много мелких косяков. Странное соглашение об именновании переменных. Многое можно было сделать проще с использованием сторонних библиотек. Сделать проще цели не было ) BlazkowiczCrypt.KEY_DATA - отличное место чтобы хранить ключь. Не совсем понял. Мысль была в том чтобы хранить там последовательность байт для генерации ключа. Что бы с одной стороны при каждом запуске генерился постоянный ключ, а с другой скрыть его от пользователя вообще BlazkowiczТак нельзя писать. Это заготовка для будущих ошибок. Код: java 1. 2. Можно так Код: java 1. и так Код: java 1. 2. 3. С этим полностью согласен. Возможно я просто гдето провтыкал. BlazkowiczTreeMap<String,HashMap<String,String>> - очень странная структура, чтобы хранить конфиг. Лучше было сделать объектами. Для объявления переменных использовать лучше интерфейсы коллекций: Map<String,Map<String,String>> А не конкретные реализации. Кроме случаев, где тип нужен явно, например при сериализации. Я сначала так и сделал, но потом переписал. Чесно говоря просто не придал этому значение. BlazkowiczМетоды setProfiles/getProfiles - вынос мозга. Понятно что такой кривой DOM API в Java, лучше было взять что-то другое для работы с XML. Этого не понял. В чем ошибка? Очень криво написал? BlazkowiczJavaDoc оформление странное. Коментарии к классам и методам пишутся иначе. Это не странное оформление. Его просто нет. Я просто подописывал короткие коментарии Как я понял JavaDoc нужны для public методов. Внутренние методы тожно желательно оформлять в JavaDoc? BlazkowiczМетоды возвращающие 0\1 похожи на смесь логики и представления. А если отчету нужно будет Y/N? Тоже не совсем понял. Отображение в отчете - это проблема (логика) отчета. Blazkowicztry-with-resource используется в IO, но не используется в JDBC. Почему? Если вы о классе ReportApi то он выполнялся на сервере Oracle. Версия jvm на сервере не поддерживает эту конструкцию. BlazkowiczНе используется Connection Pool. Даже без него DriverManager.getConnection не стоило копипастить во все методы. Сначала я открывал новое соединение на каждый чих. Потом переписал под одно соединение. А в классе на сервере переписать забыл. Провтыкал вообщем. BlazkowiczBuffered(Input|Output)Stream - где-то используется, а где-то нет. Это плохо? BlazkowiczНаписан свой метод копирование in->out, но не везде используется. Каюсь. Blazkowicznew String(" ") - что за финт ушами? А это отступы для каждой вложенной папки. Просто для более удобного отображения. Потом я переписал под jtree. а этот кусок кода не убрал. Вот такот финт и получился. Хух... ответил )) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 17:27:48 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
GaraZСделать проще цели не было ) :) GaraZНе совсем понял. Мысль была в том чтобы хранить там последовательность байт для генерации ключа. Что бы с одной стороны при каждом запуске генерился постоянный ключ, а с другой скрыть его от пользователя вообще Открыл класс, увидел ключ. Какой в нем вообще смысл? GaraZBlazkowiczМетоды setProfiles/getProfiles - вынос мозга. Понятно что такой кривой DOM API в Java, лучше было взять что-то другое для работы с XML. Этого не понял. В чем ошибка? Очень криво написал? Огромные методы делают ничтожную работу. Просто не удачный API для работы с конфиг файлами. GaraZЭто не странное оформление. Его просто нет. Я просто подописывал короткие коментарии Как я понял JavaDoc нужны для public методов. Внутренние методы тожно желательно оформлять в JavaDoc? Коментарии для класса и для методов, лучше оформлять в виде JavaDoc стандартных коментариев. Смысл писать эти коментарии в таком виде, чтобы их никто не смог прочитать? GaraZТоже не совсем понял. Отображение в отчете - это проблема (логика) отчета. Почему 0\1 лучше чем true/false? GaraZЕсли вы о классе ReportApi то он выполнялся на сервере Oracle. Версия jvm на сервере не поддерживает эту конструкцию. Ну, хз. С ходу так сразу не понятно, что разные классы одного пакета используются в разных версиях JVM. GaraZ BlazkowiczBuffered(Input|Output)Stream - где-то используется, а где-то нет. Это плохо? Да. Там, например, в одном месте File*Stream не обернут и обрабатывается побайтово. Будет подтормаживать не слабо. GaraZ А это отступы для каждой вложенной папки. Просто для более удобного отображения. Потом я переписал под jtree. а этот кусок кода не убрал. Вот такот финт и получился. почему new String() ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 17:38:54 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
Blazkowicz, Blazkowicz Открыл класс, увидел ключ. Какой в нем вообще смысл? ну да в принцыпе смысла нет. Просто мне нужно было его где то хранить. И я решил хранить в классе. Решение совсем не комерческое я согласен BlazkowiczПочему 0\1 лучше чем true/false? У меня были проблемы при передачи boolean значений из jvm Oracle в pl/sql BlazkowiczНу, хз. С ходу так сразу не понятно, что разные классы одного пакета используются в разных версиях JVM. Ну да я этого нигде не указал. Каюсь. BlazkowiczДа. Там, например, в одном месте File*Stream не обернут и обрабатывается побайтово. Будет подтормаживать не слабо. Хм... особо не думал над производительностью ввиду того что прога мелкая. Но спасибо теперь погляжу Blazkowiczпочему new String() ? Пробел это отспуп который должен ставится перед каждой вложенной папкой. Ну тупо конечно. Я согласен. Можно было " " написать хотябы ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 18:21:04 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
GaraZУ меня были проблемы при передачи boolean значений из jvm Oracle в pl/sql Об этом нужно было явно указать в коментариях. Стоило сделать реализацию методов с boolean. А потом какой-нибудь отдельной, общей для всех методов, операцией конвертировать boolean->int специально для общения с Oracle. GaraZХм... особо не думал над производительностью ввиду того что прога мелкая. Но спасибо теперь погляжу Для чтения\записи файла там разница довольно существенная выходит. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 18:34:30 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
BlazkowiczОб этом нужно было явно указать в коментариях. Стоило сделать реализацию методов с boolean. А потом какой-нибудь отдельной, общей для всех методов, операцией конвертировать boolean->int специально для общения с Oracle. Да вы правы так наверное было бы логичнее. Еще раз спасибо за замечания. Все поправлю Ну и конечно буду ждать может кто еще чего напишет ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2013, 18:51:20 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
GaraZ, В Config.crypt поток читается не правильно. in.read может считать один байт даже до конца файла. Так что вы завершите операцию раньше, чем надо. Config.crypter занимается перекладыванием байтов в потоки и обратно. Он вместе с crypt может быть переписан в один doFinal. Config.encrypt/Config.decrypt в случае исключений возвращают пустое значение. Здесь нужно какой-нибудь RuntimeException или Error (например, AssertionError) бросать. А так вы молча теряете данные. В Config.setProfiles смущают String.valueOf(...). Это чтобы null обработать? В этом случае вы строку "null" и значение null запишете одинаково. Config.getProfiles. Проверка на fileExists - первый шаг к уязвимости DoS. Файл может быть удален между проверкой и последующим чтением. В подобных операциях стоит сразу открывать файл и затем отдельно обрабатывать FileNotFoundException. ReportApi.getDir как-то странно рекурсию использует и игнорирует возвращаемое значение. Его стоит переписать нерекурсивно (для вашего случая) или исправить реализацию. А еще посмотрите API у File. В частности, методы list* и конструкторы. Reports.getReportList совершенно неожиданно изменяет внутреннее состояние класса. Ну и для большого приложения в каждом из сервисов стоит сделать свои исключения, а подробности реализации вроде SQLException оборачивать в них. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.11.2013, 10:10:37 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
maxkar, Спасибо за замечания ) maxkarВ Config.crypt поток читается не правильно. in.read может считать один байт даже до конца файла. Так что вы завершите операцию раньше, чем надо. С этим замечение не согласен. Конечно in.read может считать до конца, но метод cipher.update вызывается для полноразмерных блоков данных, а метод cipher.doFinal для неполных блоков (которые сам дописывает). Поправте если я не прав. maxkarConfig.crypter занимается перекладыванием байтов в потоки и обратно. Он вместе с crypt может быть переписан в один doFinal. Не совсем понял. Crypt.crypter занимается тем что шифрует/дешифрует массив байт в зависимости от значения aMode(ENCRYPT_MODE/DECRYPT_MODE). doFinal метод Cipher, зачем мне его переопределять? maxkarConfig.encrypt/Config.decrypt в случае исключений возвращают пустое значение. Здесь нужно какой-нибудь RuntimeException или Error (например, AssertionError) бросать. А так вы молча теряете данные. Так и задумывалось если возникает ошибка при шифровании/дешефровании (в данном случае пароля), то выводится пустое значение и пользователю необходимо ввести его вручную. Если это шифрование то вслучае ошибки значение просто не сохраняется. И при следущем вызове пользователь опять же вынужден ввести его вручную maxkarВ Config.setProfiles смущают String.valueOf(...). Это чтобы null обработать? В этом случае вы строку "null" и значение null запишете одинаково. К null это не имеет отношение. Этим кодом я просто гарантирую что в запишется именно тип String. Ну возможно это лишнее конечно. maxkarConfig.getProfiles. Проверка на fileExists - первый шаг к уязвимости DoS. Файл может быть удален между проверкой и последующим чтением. В подобных операциях стоит сразу открывать файл и затем отдельно обрабатывать FileNotFoundException. Наверное вы правы. Я нечего не знаю про DoS уязвимость. Нужно почитать maxkarReportApi.getDir как-то странно рекурсию использует и игнорирует возвращаемое значение. Его стоит переписать нерекурсивно (для вашего случая) или исправить реализацию. А еще посмотрите API у File. В частности, методы list* и конструкторы. Полностью согласен. Сначала хотел чтобы отображались также и вложенные директории. Потом передумал. В итоге получилось не то и не то. Буду переписывать maxkarReports.getReportList совершенно неожиданно изменяет внутреннее состояние класса. Не совсем понял. Можно поподробнее? Почему это совершенно неожиданно? Нужно было написать отдельный метод в котором бы заполнялось значение gRootDir? maxkarНу и для большого приложения в каждом из сервисов стоит сделать свои исключения, а подробности реализации вроде SQLException оборачивать в них. Не сосем понял о чем это вы. Можете подробней пояснить Еще раз спс )) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.11.2013, 11:38:53 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
GaraZmaxkarВ Config.crypt поток читается не правильно. in.read может считать один байт даже до конца файла. Так что вы завершите операцию раньше, чем надо. С этим замечение не согласен. Конечно in.read может считать до конца, но метод cipher.update вызывается для полноразмерных блоков данных, а метод cipher.doFinal для неполных блоков (которые сам дописывает). Поправте если я не прав. Здесь сразу два момента. Во-первых, даже блочные шифры не требуют кормить ему данные размером с блок. "Блочность" шифра - это некоторые характеристики внутри алгоритма, они не связаны с тем, как правильно вызывать этот алгоритм. И ни один из методов update не выбрасывает исключения "недостаточно входных данных". Если вдруг данных будет недостаточно, шифр запомнит введенные данные и при следующем вызове их тоже использует. Т.е. вы их получите обратно, когда скормите достаточно данных. Косвенно это подтверждается и в документации по Cipher.getOutputSize ("This call takes into account any unprocessed (buffered) data from a previous update call, padding, and AEAD tagging."). Т.е. данные могут буферизоваться. Отсюда же следует, что на самом деле getOutputSize желательно вызывать на каждой итерации и при необходимости создавать новый массив (мало ли что там забуферизовалось). Второй момент. Даже если предположить, что шифру данные нужно давать порциями в blockSize, читаете вы их все равно неверно. Даже при blockSize=5 и 10 байтах в потоке InputStream.read может считать только один байт. В этом случае ваш код пойдет делать doFinal, а это слишком рано. Нужно реализовывать код, который в любом случае пытается вычитать массив "по-максимуму". GaraZmaxkarConfig.crypter занимается перекладыванием байтов в потоки и обратно. Он вместе с crypt может быть переписан в один doFinal. Не совсем понял. Crypt.crypter занимается тем что шифрует/дешифрует массив байт в зависимости от значения aMode(ENCRYPT_MODE/DECRYPT_MODE). doFinal метод Cipher, зачем мне его переопределять? Я про взаимодействие crypter и crypt. Вот у вас в crypter байты заворачиваются в поток и вызывается crypt. И все это происходит после создания шифра. Вместо вызова crypt можно вызывать cypher.doFinal(aBytes), что сразу дает результат и избавляет от необходимости перекладывать байты в потоки или собирать их из потока. GaraZТак и задумывалось если возникает ошибка при шифровании/дешефровании (в данном случае пароля), то выводится пустое значение и пользователю необходимо ввести его вручную. Я на месте пользователя буду совсем не рад, если из-за каких-то ошибок программа потеряет мои данные. Причем ошибки даже не мои. И все это происходит без предупреждения. Т.е. в правильном варианте хорошо бы сказать пользователю "шифрование не поддерживается, пароли не будут сохранены" и пусть уже он решает, стоит ли пользоваться приложением или нет. Или просто не запускать приложение, если алгоритмы недоступны. Вот какие-то ошибки расшифровки можно игнорировать. Например, пользователь вручную изменил шифрованный пароль в конфиге. Тогда можно и сбросить данные. А в случае независящих от пользователя обстоятельств это не очень хорошо. GaraZmaxkarВ Config.setProfiles смущают String.valueOf(...). Это чтобы null обработать? В этом случае вы строку "null" и значение null запишете одинаково. К null это не имеет отношение. Этим кодом я просто гарантирую что в запишется именно тип String. Ну возможно это лишнее конечно. Т.е. вы предполагаете, что в вашей Map там все-таки хранится не String? Ну так в этом случае очень желательно, чтобы приложение падало в случае ошибок (оно и упадет с ClassCastException если не вызывать String.valueOf) а затем разбираться, откуда у вас там в map могли попасть не те типы. Иначе вы потом концов ошибки не найдете (ошибка в одном месте, а падает совсем в другом). GaraZmaxkarReports.getReportList совершенно неожиданно изменяет внутреннее состояние класса. Не совсем понял. Можно поподробнее? Почему это совершенно неожиданно? Нужно было написать отдельный метод в котором бы заполнялось значение gRootDir? Потому что из названия метода следует, что он только отчеты загружает. А на самом деле он еще что-то меняет. Пользователь класса же не просил изменять rootDir. В идеальном случае метод либо не меняет состояния, но возвращает значение, либо изменяет состояние и ничего не возвращает (void method). На практике так не всегда получается (см. тот же Cipher). Но от get изменение внутреннего состояния совсем не ожидается. Один из вариантов - да, выделить отдельный метод. Между прочим, этот метод у вас уже есть - initRootDir. Второй - инициализировать состояние только один раз (в конструкторе). Такой подход может быть не всегда применим. Третий - возвращать данные в объекте (например, там будут поля rootDir и reportList), а внутри класса состояние вообще не хранить (тем более, оно самим классом нигде не используется). GaraZmaxkarНу и для большого приложения в каждом из сервисов стоит сделать свои исключения, а подробности реализации вроде SQLException оборачивать в них. Не сосем понял о чем это вы. Можете подробней пояснить Ну вот возьмем тот же Config. getProfiles/setProfiles выбрасывают всякие ошибки вроде SAXException и IOException. Т.е. любой пользователь привязан к деталям реализации. Допустим, потом вам XML надоест и вы решите использовать JSON. В этом случае добавятся еще исключение JSONException. При этом пользователь метода ничего в случае этих ошибок сделать не может. Он контролирует только набор данных. Вот IllegalArgumentException он может как-то обработать, а SAXException - нет. Для "больших" приложений удобно заводить исключения в терминах "контракта" сервиса, а не его реализации. Вот у вас есть конфиг, который загружает/сохраняет профили. Поэтому при невозможности загрузить/сохранить профиль логичным будет что-нибудь вроде ProfileInaccessibleException. Это явно говорит пользователю метода "профиль недоступен". Исходное исключение (то же IOException) можно передавать как cause в конструктор ProfileInaccessibleException, так что все необходимые детали будут доступны, их можно будет сохранить в лог и т.д. Если вдруг вы измените формат на json, декларированное исключение у методов не изменится, изменится только реализация метода. В дальнейшем вы можете развивать иерархию ошибок. Допустим, пользователи могут менять "профиль" вручную. В этом случае ситуации "при изменении испортили формат" и "у пользователя испортился жесткий диск" будут приниципиально разными. Можно будет ввести двух наследников ProfileInaccessibleException: ProfileUnreadableException и MailformedProfileException. Причем старый код тоже будет корректно работать. Т.е. свою иерархию исключений в некоторых пределах можно и под стоящие задачи подстраивать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.11.2013, 10:45:20 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
maxkar, maxkarЗдесь сразу два момента. Во-первых, даже блочные шифры не требуют кормить ему данные размером с блок. "Блочность" шифра - это некоторые характеристики внутри алгоритма, они не связаны с тем, как правильно вызывать этот алгоритм. И ни один из методов update не выбрасывает исключения "недостаточно входных данных". Если вдруг данных будет недостаточно, шифр запомнит введенные данные и при следующем вызове их тоже использует. Т.е. вы их получите обратно, когда скормите достаточно данных. Косвенно это подтверждается и в документации по Cipher.getOutputSize ("This call takes into account any unprocessed (buffered) data from a previous update call, padding, and AEAD tagging."). Т.е. данные могут буферизоваться. Отсюда же следует, что на самом деле getOutputSize желательно вызывать на каждой итерации и при необходимости создавать новый массив (мало ли что там забуферизовалось). По поводу размера блока согласен. Изменил размер блока на произвольный и проверил - ничего не поменялось. Насчет getOutputSize ну да какбы может и не лишним было бы maxkarВторой момент. Даже если предположить, что шифру данные нужно давать порциями в blockSize, читаете вы их все равно неверно. Даже при blockSize=5 и 10 байтах в потоке InputStream.read может считать только один байт. В этом случае ваш код пойдет делать doFinal, а это слишком рано. Нужно реализовывать код, который в любом случае пытается вычитать массив "по-максимуму". Тут не согласен. Все прекрасно работает int read(byte[] b) Читает данные в байтовый массив и возвращает фактическое число прочитанных байтов или число -1, если обнаружен конец потока. Максимальноее количество байтов, которое может прочитать метод read(), определяется полем b.length maxkarЯ про взаимодействие crypter и crypt. Вот у вас в crypter байты заворачиваются в поток и вызывается crypt. И все это происходит после создания шифра. Вместо вызова crypt можно вызывать cypher.doFinal(aBytes), что сразу дает результат и избавляет от необходимости перекладывать байты в потоки или собирать их из потока. Попробывал. Работает и так. Выходит что вы правы "Блочность" шифра - это некоторые характеристики внутри алгоритма, они не связаны с тем, как правильно вызывать этот алгоритм. ))) Алгоритм я взял из книги Хорстманна. Теперь не понятно зачем он разбивал на блоки. пс. Возможно в старой версии java так и нужно было делать maxkarЯ на месте пользователя буду совсем не рад, если из-за каких-то ошибок программа потеряет мои данные. Причем ошибки даже не мои. И все это происходит без предупреждения. Т.е. в правильном варианте хорошо бы сказать пользователю "шифрование не поддерживается, пароли не будут сохранены" и пусть уже он решает, стоит ли пользоваться приложением или нет. Или просто не запускать приложение, если алгоритмы недоступны. Вот какие-то ошибки расшифровки можно игнорировать. Например, пользователь вручную изменил шифрованный пароль в конфиге. Тогда можно и сбросить данные. А в случае независящих от пользователя обстоятельств это не очень хорошо. maxkarНасчет предупреждения в принципе согласен возможно стоит и добавить )) Т.е. вы предполагаете, что в вашей Map там все-таки хранится не String? Ну так в этом случае очень желательно, чтобы приложение падало в случае ошибок (оно и упадет с ClassCastException если не вызывать String.valueOf) а затем разбираться, откуда у вас там в map могли попасть не те типы. Иначе вы потом концов ошибки не найдете (ошибка в одном месте, а падает совсем в другом). ок. согласен. перепишу. maxkarОдин из вариантов - да, выделить отдельный метод. Между прочим, этот метод у вас уже есть - initRootDir. Второй - инициализировать состояние только один раз (в конструкторе). Такой подход может быть не всегда применим. Третий - возвращать данные в объекте (например, там будут поля rootDir и reportList), а внутри класса состояние вообще не хранить (тем более, оно самим классом нигде не используется). Мне кажется что здесь подойдет второй вариант ))) maxkarНу вот возьмем тот же Config. ... Т.е. свою иерархию исключений в некоторых пределах можно и под стоящие задачи подстраивать Ну это ж маленькое приложение, которое к тому же не будет дальше развиваться. Меня в принципе данный функционал вполне устраивает. Писать свою иерархию интересно но мне кажется здесь не уместно. Игра не стоит свеч )) Спасибо за замечания )) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.11.2013, 12:48:19 |
|
||
|
Покритикуйте код
|
|||
|---|---|---|---|
|
#18+
GaraZmaxkar, maxkarВторой момент. Даже если предположить, что шифру данные нужно давать порциями в blockSize, читаете вы их все равно неверно. Даже при blockSize=5 и 10 байтах в потоке InputStream.read может считать только один байт. В этом случае ваш код пойдет делать doFinal, а это слишком рано. Нужно реализовывать код, который в любом случае пытается вычитать массив "по-максимуму". Тут не согласен. Все прекрасно работает int read(byte[] b) Читает данные в байтовый массив и возвращает фактическое число прочитанных байтов или число -1, если обнаружен конец потока. Максимальноее количество байтов, которое может прочитать метод read(), определяется полем b.length Оно работает только потому, что у вас ByteArrayInputStream. Этот Stream заполняет буфер по-максимуму всегда (когда есть данные). Для других реализаций InputStream подобное поведение не гарантировано. Т.е. отрицательное число - точно конец файла. Любое положительное число ничего кроме "прочитанны данные" не обозначает. Даже если read вернул число меньшее, чем b.length, это не обозначает, что был прочитан последний блок ввода. И в контракте этого не написано. А в строке 56 вы как раз ориентируетесь на "прочитался ли буфер полностью". Чтобы получить ошибку, нужно другие потоки использовать. Можно попробовать файловые. А можно написать свой наследник FilterInputStream, который на любой read читает только один байт (это контракта не нарушит). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2013, 10:12:30 |
|
||
|
|

start [/forum/topic.php?fid=59&msg=38468792&tid=2128162]: |
0ms |
get settings: |
7ms |
get forum list: |
17ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
187ms |
get topic data: |
7ms |
get forum data: |
2ms |
get page messages: |
47ms |
get tp. blocked users: |
1ms |
| others: | 213ms |
| total: | 487ms |

| 0 / 0 |
