Показ дописів із міткою Java. Показати всі дописи
Показ дописів із міткою Java. Показати всі дописи

пʼятницю, 11 липня 2014 р.

WindowBuilder Error: Unhandled event loop exception

Вирішив поставити плагін WindowBuilder у Eclipse. При спробі використовувати графічний редактор зразу ж Eclipse почав видавати помилку: Unhandled event loop exception


Думав, знов щось нахомутав при встановленні. Проте завдяки посту:  "Eclipse Bug: Unhandled event loop exception No more handles", довідався що у цьому можуть бути винні деякі процеси запущені у windows. Методом проб і помилок як і у випадку описаному у моєму пості "JVM creation failed" виявилося, що знов винен електронний словник Abby Lingvo. Ну не люблять чомусь Java IDE цю програмку :)  і взагалі продукти фірми ABBY :).

Проблема вирішується або вбивством процесу  LvAgent.exe або ж у налаштуваннях лінгво забрати галочки пов'язані з роботою з клавіатурою, щоб взагалі не було реагувань на клавіші.

вівторок, 10 червня 2014 р.

Логування в Java (log4j 2)

Мабуть чи не всі програмісти виводять додаткову інформацію на консоль для зневадження програми і просто з метою стеження за її виконанням.  Проміжну інформацію про стан виконання програми, про певні критичні помилки часто корисно записувати у файл чи передати по мережі. Тоді користувач програми може надіслати розробнику звіт і розробник зможе розібратися, що ж пішло не так. Логування у будь-якому разі корисне. Логування у файл можна звичайно зробити самому. Проте навіщо винаходити велосипед, якщо на цьому поприщі вже багато чого зроблено. Існує декілька бібліотек, які спрощують логування. Зараз мова піде про log4j 2-ї версії.

Що потрібно звантажити

* Apache Log4j 2 з оф. сайту (http://logging.apache.org/log4j/2.x/download.html)
* Log4j 2 User’s Guide – посібник користувача (http://logging.apache.org/log4j/2.x/log4j-users-guide.pdf)
* SLF4J – це бібліотека для логування на якій базується log4j 2 (http://www.slf4j.org/download.html)


Підключення бібліотек


Для того щоб наші приклади працювали. Необхідно підключити відповідні *.jar файли до проекту. Не буду пояснювати як це робити.

Розархівовуємо вміст архівів звантажених з інтернету і з них я підключав наступні:

log4j2.0\log4j-api-2.0-rc1.jar
log4j2.0\log4j-core-2.0-rc1.jar
log4j2.0\log4j-slf4j-impl-2.0-rc1.jar
slf4j-1.7.7\integration\lib\slf4j-api-2.0.99.jar
slf4j-1.7.7\integration\lib\slf4j-simple-1.6.99.jar

Якщо не підключити slf4j, то буде видавати помилку виду:

 Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/ILoggerFactory
      at java.lang.ClassLoader.defineClass1(Native Method)...........



Конфігурація Log4j 2

Для того щоб логування працювало як нам потрібно необхідний відповідний файл конфігурації. Можна створити .xml файл, а можна файл properties. Приклади файлів конфігурації можна знайти в посібнику (User’s Guid). Файл повинен бути прописаний в classpath проекту. Можна просто закинути файл у корінь проекту, або у каталог src. Файл конфігурації краще назвати log4j2.xml.

У посібнику користувача можна знайти різні приклади файлу конфігурації для різних цілей: виводу лише на консоль, виводу у файл, виводу у мережевий сокет і т.д. Для виводу у файл матимемо:

<configuration>
    <appenders>
        <file append="false" filename="A1.log" name="A1">
            <patternlayout pattern="%t %-5p %c{6} - %m%n">
        </patternlayout></file>
        <console name="STDOUT" target="SYSTEM_OUT">
            <patternlayout pattern="%d %-5p [%t] %C{6} %M (%F:%L) - %m%n">
        </patternlayout></console>
    </appenders>
    <loggers>
        <logger level="debug" name="org.apache.log4j.xml">
            <appenderref ref="A1">
        </appenderref></logger>
        <root level="debug">
            <appenderref ref="STDOUT">
        </appenderref></root>
    </loggers>
</configuration>

Наступний приклад демонструє роботу з логуванням.
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HelloWorld {
 private static Logger logger = LogManager.getLogger("HelloWorld");

 public static void main(String[] args) {
  logger.info("Hello, world");
  
  Logger fileLog=LogManager.getLogger("org.apache.log4j.xml");
  fileLog.debug("Write in file!");
 }
}

В результаті, якщо був використатий файл конфігурації наведений вище, то на консолі отримаємо:
2014-06-10 15:04:31,610 INFO  [main] HelloWorld (HelloWorld.java:8) - Hello, world
2014-06-10 15:04:31,612 DEBUG [main] HelloWorld (HelloWorld.java:11) - Write in file!
А у файлі:
main DEBUG log4j.xml - Write in file!
Спочатку отримуємо наш основний «Логер», який направлений буде на консоль.

private static Logger logger = LogManager.getLogger("HelloWorld");

Якщо ми хочемо писати у файл щось, то отримуємо логер для файлу:

Logger fileLog=LogManager.getLogger("org.apache.log4j.xml");

І пишемо у файл:

fileLog.debug("Write in file!");

Те як виглядатими наш лог, що туди включатиметься в значній мірі залежить від файла конфігурації.


Можливі передачі у лог і винятків (Exception):

logger.info("Error: ", new Exception("An exception"));


Рівні логування

Не хочеться вдаватися глибоко у цю тему, але необхідно згадати основне. При логуванні розрізняють рівні логування:

1.    TRACE – повідомлення найвищого рівні

2.    DEBUG – зневаджувальні повідомлення, менш детальні ніж TRACE

3.    INFO – стандартні інформаційні повідомлення

4.    WARN – некритичні помилки

5.    ERROR – помилки, що можуть вплинути на правильність результату

6.    FATAL – фатальні помилки, які заважають роботі

За допомогою файлу конфігурації ми можемо вказати, які повідомлення включати у наш лог.  У нас у файлі конфігурації маємо level="debug" . Це означає що на консоль і у файл буде виводитися всі повідомлення рівня Debug і нижче. Повідомлення рівні trace не будуть включатися. Тобто рядок в коді logger.trace("Hello, world"); - нам нічого не виведе ні в лог, ні у файл, ні на консоль, якщо ми не підвищемо рівень логування до TRACE у файлі конфігурації.

Патерни логування

Для формування вигляду логу, використовується відповідний патерн або ж шаблон. У нас використано два патерни, один для файлу інший для консолі.

<PatternLayout pattern="%t %-5p %c{2} - %m%n" />

<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />

%d – вивести дату

%t – ім’я нитки (thread)

%-5p — виводить рівень логу (ERROR, DEBUG, INFO …), цифра 5 означає, що для виводу використовується 5 символів ,  (-), те що вирівнювання буде відбуватися по лівій стороні

%c{1} — виводить назву логера, у фігурних дужках регулюється наскільки повною видаватиметься назва

%L —номер рядка, в якій відбувася виклик запису у лог

%m — повідомлення, що було передано в лог

%n — перехід на новий рядок

Усе це детальніше подато у посібнику користувача.

середу, 11 вересня 2013 р.

JSP та кириличні запити

Почав розбиратися з JSP. Зробив найпростіший приклад і вийшла проблема з кирилицею. Коли запит приймається і формується html сторінка, вміст запиту відображається не в тому кодуванні. Хоча усюди усе на UTF-8.  При чому, що цікаво, що на комп'ютері з windows7 усе нормально, під windows XP проблема. Програмне забезпечення і там і там ставив одне і те ж Tomcat7, jdk7, Netbeans 7.3.1

Вирішується проблема частково через створення сервлет-фільтра, який запускається перед зверненням до будь якої jsp сторінки, або ж сервлета. Де додав у метод doBeforeProcessing рядок: request.setCharacterEncoding("utf-8");  Для POST запитів подіяло, але для GET не спрацьовує.

Почитав що можливо допоможе зміна деяких налаштувань в Tomcat. Інші рекомендації рекомендують погратися з локалями. Вирішив поки що в це не влазити, хоча судячи зі всього прийдеться, оскільки при зв'язці з базами даних проблема з кирилицею та різними кодуваннями прийдеться долати. В PHP якось проблем з цим по-менше :)

понеділок, 10 грудня 2012 р.

JVM creation failed

JVM creation failed - повідомлення, яке з'являється в NetBeans IDE 7.1.2 при запуску. Методом "наукового втику" виявив, що є певний конфлікт з продуктами ABBY lingvo та Adobe Reader. Закриваємо ці програми і запускаємо усе проходить. В NetBeans IDE 7.2.1 дану проблему видалили.

Можна було б забути про даний глюк. Проте виявилось, що ще один продукт Oracle страждає на ту ж слабкість. Oracle JDeveloper 11g видає схожу помилку: Unable to create istance of the Java Virtual Machine..... Вигружаю Abby lingvo і девелопер запускається. Після чого лінгво можна запускати.


понеділок, 29 жовтня 2012 р.

Використовуємо Java Database Connectivity

Представляю вирізку з Java для чайників Баррі Берда по роботі з базою даних.Розглядається з'єднання з базою даних, запис даних та подання запитів. Далі оригінальний текст.

JDBC та Java DB

Коли я вперше розпочав роботу з базами даних, моєю найбільшою проблемою було з’єднання з базою даних. Я написав весь необхідний Java код. (Насправді, я скопіював весь Java код з якоїсь книги.) Програмна частина була простою. Найважчою частиною було змусити мій код знайти базу даних в системі.

Частиною проблеми було те, що шлях в який ваш код взаємодії з базою даних залежить від виду вашої системи та виду бази даних, що встановлена в вашій системі. Книга, якою я користувався не могла описати в деталях усе, тому що деталі  відрізнялися від комп’ютера до комп’ютера. Зараз же я пишу мій власний розділ про з’єднання з базою даних. Що ж я як автор робитиму?

На моє щастя, набір розробника Java (JDK) поставляється з власною вбудованою базою даних – Java DB. Java DB базується на базі даних Apache Derby і є доволі безпечною, полегшеною і стандартизованою. Java DB виконується самостійно від решти Java JDK. Java гуру представили Java DB з випуском Java 6.

Тож Java DB робить життя легшим для мене, надаючи загальнодоступну базу даних, яку можуть застосовувати всі мої читачі. Вона вільнодоступна і не вимагає встановлення.

А що якщо ви не використовуєте Java DB? Що якщо всі ваші дані зберігаються в іншому типі бази даних; як то MySQL, PostgreSQL, SQLLite, Oracle, Microsoft Access, DB2 або в будь-якій іншій? Тоді Java має рішення для вас! Класи Java Database Connectivity (JDBC) надають загальний доступ до більшості систем управління базами даних. Просто візьміть драйвер для вашої улюбленої системи, модифікуйте два рядочки коду в прикладах даного розділу і ваш код готовий до виконання.


Створення даних

JDBC розміщується у двох пакетах: java.sql та javax.sql, які є частиною Java API. Приклади даного розділу використовують класи java.sql. Перший приклад наведений в роздруківці 16-1.

Роздруківка 16-1: Створення бази даних, таблиці та вставлення даних.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

class CreateTable {
public static void main(String args[]) {
    
    final String DRIVER =
        "org.apache.derby.jdbc.EmbeddedDriver";
    final String CONNECTION =
        "jdbc:derby:AccountDatabase;create=true";
    try {
        Class.forName(DRIVER).newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    try (Connection connection =
         DriverManager.getConnection(CONNECTION);
        Statement statement =
         connection.createStatement()) {
        statement.executeUpdate("create table ACCOUNTS"
                +"(NAME VARCHAR(32) NOT NULL PRIMARY KEY,"
                +" ADDRESS VARCHAR(32), BALANCE FLOAT) ");
        statement.executeUpdate("insert into ACCOUNTS"
                +" values ('Barry Burd', '222 Cyber Lane', 24.02)");
        statement.executeUpdate("insert into ACCOUNTS values"
                +" ('Joe Dow', '111 Luddite Street', 55.63)");
        
    } catch (SQLException e) {
        e.printStackTrace();
    }
    }
}

Щоб використовувати MySQL замість Java DB, зробіть деякі зміни в лістингу 16-1. Змініть значення DRIVER на "com.mysql.jdbc.Driver". Змініть значення CONNECTION на "jdbc:mysql://localhost/AccountDatabase;
create=true". Зробіть подібні зміни для DB2, Oracle та інших баз даних

Щоб запустити наведений код, вам необхідно мати файл, що містить відповідний драйвер бази даних, і даний файл повинен бути розміщений там, де Java зможе його знайти. В прикладах даного розділу я з’єднуюсь з базою даних Java DB, знаної як база даних Apache Derby. Драйвер знаходиться у файлі з назвою derby.jar, який зазвичай знаходиться в директорії JDK db/lib. Щоб зробити db/lib/derby.jar доступним для моєї програми, я додаю даний файл до Java classpath.

Спосіб в який додати .jar файл до classpath залежить від виду середовища розробки (IDE) яким ви користуєтесь та виду вашої операційної системи. В Eclipse, я вибираю Project->Properties->Java Build Path. Тоді я клацаю на кнопці Add External JARs і переходжу до директорії db/lib. Для інших IDEs, кроки є дещо відмінними.

Коли ви виконуєте код в роздруківці 16-1, то здається що нічого не стається. Програма запускається і зупиняється. Так і має бути. Код не має видимого виводу, тому що весь вивід направляється в базу даних. Тож, щоб побачити результат коду в роздруківці 16-1, ви повинні переглянути зміни в самій базі даних. Тож продовжуйте читати!

В попередньому абзаці, я написав що виконання роздруківки 16-1 є жахливо непримітним. Я написав що «здається нічого не сталося» і що «Код не має видимого виводу». Проте, якщо ви розглянете ближче, то зможете знайти деякі докази виконання коду роздруківки 16-1. Зокрема, ваш жорсткий диск матиме декілька додаткових файлів після виконання цього коду. Один з цих файлів, називатиметься derby.log. Він міститиме текст опису запуску і зупинки програмного забезпечення бази даних Derby.  Ви також можете знайти нову папку з назвою derbyDB, який міститиме log файли, файл service.properties та папку повну .dat файлів. (Ці .dat файли містять увесь матеріал збережений в базі даних.) Якщо ви використовуєте Eclipse, ви можете зробити дані файли і папки видимими вибравши відповідну гілку оглядача пакетів та далі вибравши File->Refresh.

Викорисовуємо SQL команди

В роздруківці16-1 суть коду лежить в трьох викликах executeUpdate. Кожен виклик executeUpdate містить рядок символів узятих в лапки. Щоб зробити код читабельним, я порізав кожен рядок на частини та розділив дані частини знаком плюс (оператором конкатенації). Плюс у Java виконує подвійну роботу. Для чисел, плюс виконує додавання. Для рядків, плюс – це знак для поєднання двох рядків докупи, утворюється один з’єднаний рядок (string).

Ви можете зробити рядок в подвійних лапках як завгодно довгим. Коли ви добираєтесь до правого краю екрану, перестаньте друкувати. Якщо ви хочете побачити цілий рядок без прокрутки, то вам необхідно розділити його на частини, як це зроблено в роздруківці 16-1. Просто розділіть частини знаком плюс.

Ви не можете розділити Java рядок просто натиснувши Enter або перемістивши на новий рядок. Коли ви розпочинаєте рядок з подвійної лапки("), то заключна подвійна лапка має бути на одному текстовому рядку коду.

Якщо ви знайомі з SQL (Structured Query Language – мова структурованих запитів), командний рядок у виклику executeUpdate зрозумілий для вас. Якщо ні, візьміть примірник SQL для Чайників, 7-ме видання, Алена Тейлора (SQL For Dummies, 7th Edition, by Allen G. Taylor.). Дані командні рядки не є частиною мови Java. В Java ці команди є лише рядками символів, які ви згодовуєте методу executeUpdate.  Дані рядки,  написані на SQL, створюють нову таблицю і додають ряд даних до таблиці. Коли ви пишете програму для бази даних на Java, ви просто пишете звичайні команди SQL і вставляєте їх у виклики методів Java.

В коді даного рядка строго дотримано технічні прийоми описані в JDBC версії 1.0. Пізніші версії класів JDBC підтримують інший спосіб запису даних (scrollable result sets), що надає вам метод insertRow, який заощаджує ваші зусилля, щодо повного написання командних рядків SQL.



З’єднання та роз’єднання

Окрім викликів методу executeUpdate, код в роздруківці 16-1 має ще деякий матеріал. Далі подається скорочений виклад  значення кожної частини коду:

  •   Class.forName: знаходить драйвер бази даних
Говорить до бази даних, що вам необхідний програмний посередник (драйвер бази даних). Драйвери можуть бути різних видів та розмірів, багато з них доволі дорогі. Роздруківка 16-1 застосовує невеликий, безкоштовний драйвер — Derby JDBC Embedded driver. Код для даного драйвера розміщується в Java класі EmbeddedDriver. Даний клас розміщений всередині пакету org.apache.derby.jdbc.

Щоб використати клас  EmbeddedDriver, ви викликаєте метод Class.forName. Хочете вірте, хочете ні проте Java API має клас під назвою Class. Клас Class містить інформацію про класи, що доступні в віртуальній машині Java (JVM). В лістингу 16-1, виклик Class.forName заглядає в клас org.apache.derby.jdbc.EmbeddedDriver. Після того як екземпляр EmbeddedDriver завантажений, ви можете приступити до з’єднання з базою даних.

  •   DriverManager.getConnection: Встановлює сесію з зазначеною базою даних
Метод getConnection проживає в Java класі з назвою DriverManager.  В роздруківці 16-1 виклик getConnection створює базу даних AccountDatabase та відкриває з’єднання з базою даних, Звичайно, що AccountDatabase можливо  вже існує перед стартом коду роздруківки 16-1. Якщо це так, то текст ;create=true у виклику getConnection не матиме ефекту.

В параметрі getConnection зверніть увагу на двокрапку. В коді не просто вказується назва бази даних AccountDatabase, крім того для класу DriverManager вказується, який протокол застосовувати для з’єднання з базою даних. Код jdbc:derby:  — теж саме, що http: у веб-адресах, тобто ми вказуємо комп’ютеру застосовувати jdbc протокол для спілкування з derby протоколом,  який передасть усе до вашої AccountDatabase.

  •     Connection.createStatement: створити інструкцію
Це виглядає дивно, проте в Java Database Connectivity, ви створюєте простий об’єкт statement. Після того як ви його створили, ви можете використовувати об’єкт багато раз з різноманітними SQL рядками, щоб посилати різні команди базі даних. Тож, перед  тим як викликати метод statement.executeUpdate, вам необхідно мати відповідний об’єкт statement.  Виклик connection.createStatement створює об’єкт statement для вас.

  •   try…catch…:  розпізнаємо винятки, що можуть виникнути в коді

Ви мабуть знаєте, що деякі виклики методів викидають контрольовані винятки. Контрольований виняток – це виняток який має бути розпізнаний у коді виклику. Тож, виклик Class.forName може викинути три типи винятків і згодом код в роздруківці 16-1 може викинути SQLException. Щоб розпізнати дані винятки, я додав інструкцію try-catch в мій код.

  •  try-with-resources:  вивільняє, які б не були, ресурси
Кожне з’єднання і кожна інструкція бази даних бере деякі системні ресурси. Коли ви закінчуєте використовувати ці ресурси, ви звільняєте їх.  Ви маєте явно вказати це викликом методу close, і ви мусите зробити це в інструкції try-catch.

Але там же є ще інструкція catch (зловити)! Коли щось іде неправильно, це не може просто так відбуватися. Це завжди трапляється через недбалість в коді. Тож, що трапиться, якщо catch викине власні винятки? І що станеться згодом, де ваш код пробує закрити усе з’єднання? Чи буде усе правильно закрито?

Щоб зробити усе заразом, Java 7 має нову інструкцію try-with-resources (try з ресурсами). Try-with-resources діє як давніша інструкція try. Проте в новій інструкції ви додаєте дужки після слова try. Всередині дужок, ви розміщуєте деякі інструкції, що створюють ресурси. (В роздруківці 16-1 інструкціями в дужками є виклики getConnection та createStatement.) Інструкції розділяються крапкою з комою.

Інструкція try-with-resources автоматично закриває і звільняє ваші ресурси вкінці виконання інструкцій. Більш того, try-with-resources, бере на себе усю брудну роботу щодо рішення усіх помилок при закритті таких ресурсів.

Видобування даних

Що доброго в базі даних, якщо ви не можете отримати дані з неї?  В даній секції, ви задаватимете запити до бази даних, що була створена в роздруківці 16-1. Код задання запитів показаний в роздруківці 16-2.

Роздруківка 16-2: Створення запитів

import static java.lang.System.out;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.NumberFormat;

class GetData {
public static void main(String args[]) {
    NumberFormat currency =
     NumberFormat.getCurrencyInstance();
    final String DRIVER =
        "org.apache.derby.jdbc.EmbeddedDriver";
    final String CONNECTION =
        "jdbc:derby:AccountDatabase";
    try {
        Class.forName(DRIVER).newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    try (Connection connection =
        DriverManager.getConnection(CONNECTION);
        Statement statement =
          connection.createStatement();
        ResultSet resultset =
         statement.executeQuery(
          "select * from ACCOUNTS")) {

            while(resultset.next()) {
            out.print(resultset.getString("NAME"));
            out.print(", ");
            out.print(resultset.getString("ADDRESS"));
            out.print(" ");
            out.println(currency.format(
            resultset.getFloat("BALANCE")));
            }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
}


Щоб використовувати MySQL замість Java DB, зробіть наступні зміни в роздруківці 16-2: змініть значення DRIVER на “com.mysql.jdbc.Driver”. Змініть значення  CONNECTION на “jdbc:mysql://localhost/ AccountDatabase;create=true”. Зробіть подібні зміни для DB2, Oracle та інших баз даних.

Результат виконання коду з роздруківки 16-2 зображено на рисунку 16-1. В коді задаються запити в базу даних і згодом поступово кожен рядок з бази даних роздруковується.

Рисунок 16-1 – Отримання даних з бази даних
________________________________
Barry Burd, 222 Cyber Lane 24,02 грн.
Joe Dow, 111 Luddite Street 55,63 грн.
________________________________

Роздруківка 16-2 починається із звичного вже виклику forName, getConnection та createStatement. Далі в коді викликається executeQuery і подається виклик з SQL командою. Для тих хто знає SQL команди, той знає, що дана особлива команда бере всі дані з таблиці ACCOUNT (таблиці створеної в роздруківці 16-1).

Сутність, що повертається з виклику executeQuery має тип java.sql.ResultSet. (Це різниця між executeUpdate та executeQuery — excuteQuery повертає множину даних,  executeUpdate ні.) Дана множина-результат виглядає  так же як і таблиця бази даних. Подібно до оригінальної таблиці, множина розділена на ряди і стовпці. Кожен ряд містить дані одного облікового запису: ім’я, адрес і об’єм балансу.

Після того як ви викликали executeQuery і отримали вашу множину-результат, ви можете проходити покроково по рядах множини-результату.  Щоб зробити це потрібно створити цикл і перевіряти на початку кожної ітерації умову resultset.next(). Кожен раз коли викликається resultset.next() робиться дві речі:

  •     відбувається перехід до наступного ряду множини-результату (наступного облікового запису), звичайно, якщо він існує
  •   вам говориться чи існує даний ряд через повертається булевого значення – true або false

Якщо resultset.next() повертає true, множина-результат має інший ряд. Комп’ютер переходить до наступного ряду і в циклі поступово вибираються дані з даного ряду. Якщо ж resultsetset.next() повертає false, множина-результат не має більше рядів. Ви стрибаєте за межі циклу і починаєте усе закривати.

Тож, якщо ряд існує, то переходимо всередину циклу роздруківки 16-2.  Ви видобуваєте дані з ряду множини-результату викликаючи методи getString та getFloat. Раніше в роздруківці 16-1 ви створили таблицю ACCOUNTS із стовпцями NAME, ADDRESS та BALANCE.  Тут же в роздруківці 16-2 ви отримуєте дані з даних стовпців викликаючи методи зразка getДеякийТип і згодовуєте оригінальні назви стовпців даним методам. Після того як ви отримали дані, ви виводити їх на екран комп’ютера.

Кожен екземпляр ResultSet має декілька непоганих методів getДеякийТип. В залежності від того який тип даних поміщений в стовпчику, ви можете викликати методи: getArray, getBigDecimal, getBlob, getInt, getObject, getTimestamp і декілька інших.


четвер, 11 жовтня 2012 р.

Робота з COM-портом на Java

Для робот з портами Java в JDK немає стандартного пакету. Тому необхідно встановити додаткову бібліотеку для роботи з послідовними та паралельними портами. Послідовний (COM-порт) доволі поширений в даний час, багато апаратного обладнання працює на ньому. Навіть в сучасному він використовується доволі часто. Сучасні прилади підключаються до USB, проте в багатьох використовується перехідник USB-COM, що дозволяють розробникам програмного забезпечення працювати з приладом через добре знайомий і легкий інтерфейс RS232 (COM).

Тож, що нам потрібно? Існує декілька java бібліотек для роботи з COM-портом , які побудовані з використанням Native-методів. Свого часу була популярна javax.Comm, її можна використовувати до цих пір, проте в даний час бібліотеку ніхто не підтримує, її розвиток не відбувається. На зміну javax.Comm прийшла інша java бібліотека – RXTX (http://rxtx.qbang.org/wiki/index.php/Main_Page). Методи в RXTX для роботи з COM-портом ідентичні до методів javax.Comm.

Встановлення

Встановлення бібліотеки можна здійснити декількома способами. Їх можна знайти в документації на сайтах підтримки RXTX.

1. Найпростіший спосіб:

• Знайти де у вас встановлене JDK, наприклад:  c:\Program Files\Java\jdk1.6.0_01\
• Скопіювати rxtxParallel.dll до c:\Program Files\Java\jdk1.6.0_01\jre\bin\
• Скопіювати rxtxSerial.dll до c:\Program Files\Java\jdk1.6.0_01\jre\bin\
 • Скопіювати RXTXcomm.jar до c:\Program Files\Java\jdk1.6.0_01\jre\lib\ext\

Якщо у вас JRE і вам просто необхідно виконати необхідну програму, яка використовує RXTX, то зробити теж саме але для відповідних каталогів JRE. Звичайно даний спосіб поганий для кінцевих користувачів вашого продукту. Оскільки не всі користувачі зможуть легко зробити необхідні маніпуляції з файлами.

2.Тому другий спосіб - це включити бібліотеку у jar файл вашого продукту. Якщо ви використовуєте NetBeans, то у проекті де знаходяться java файли необхідно створити каталог resources і помістити туди rxtxSerial.dll. .

Другий крок – це додавання власне java файлів, для цього можна завантажити джерельний код(source) бібліотеки з офіційного сайту і з папки src взяти усі .java файли і закинути в src-папку проекту по структурі каталогів gnu/io.

Детальніше можна знайти в різноманітній документації. Зокрема як підключити rxtx у Eclipse написано тут: http://rxtx.qbang.org/wiki/index.php/Using_RXTX_In_Eclipse

Для початку можете спробувати перший спосіб.



Програмування

Перейдемо власне до програмування. В інтернеті я знайшов хорошу реалізацію класу SerialPortHandler, який спрощує роботу з RXTX. Тому наведу дещо перероблений варіант далі (Оригінал: http://embeddedfreak.wordpress.com/2008/08/08/how-to-open-serial-port-using-rxtx/)

Для роботи необхідно перш за все, отримати ідентифікатор послідовного порту:

CommPortIdentifier portId =
  CommPortIdentifier.getPortIdentifier("COM4");

Далі необхідно відкрити порт, тобто вказати системі, що ви з ним працюєте:

SerialPort serialPort =(SerialPort) portId.open("Name of program", 5000);

У вищенаведеному рядочку ми відсилаємо назву програми і задаємо інтервал очікування відповіді. В даному випадку 5000 мс – 5 секунд. Якщо відповідь не приходить, то отримуємо виняток IOException.

Якщо пройшло все добре, порт знайдено в системі і вам надано ID для роботи з ним, то далі необхідно налаштувати порт для роботи з ним:

int baudRate = 9600; // 9600bps
try {
  serialPort.setSerialPortParams(
    baudRate,
    SerialPort.DATABITS_8,
    SerialPort.STOPBITS_1,
    SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException ex) {
  System.err.println(ex.getMessage());
}

Незабуваємо задати контроль потоку:

try {
  serialPort.setFlowControlMode(
        SerialPort.FLOWCONTROL_NONE);
  // OR
  // If CTS/RTS is needed
  //serialPort.setFlowControlMode(
  //      SerialPort.FLOWCONTROL_RTSCTS_IN | 
  //      SerialPort.FLOWCONTROL_RTSCTS_OUT);
} catch (UnsupportedCommOperationException ex) {
  System.err.println(ex.getMessage());
}

Для того щоб записувати і отримувати дані з порта, необхідно отримати потоки вводу-виводу.

OutputStream outStream = serialPort.getOutputStream();
InputStream inStream = serialPort.getInputStream();

Далі наведено повний текст методів для роботи з COM-портом. Наводиться без змін з оригінальної статті. Для використання необхідно вказати свій ідентифікатор порту та швидкість роботи з ним.



public class SerialPortHandler {
    private SerialPort serialPort;
    private OutputStream outStream;
    private InputStream inStream;

    public void connect(String portName) throws IOException {
        try {
            // Obtain a CommPortIdentifier object for the port you want to open
            CommPortIdentifier portId =
                    CommPortIdentifier.getPortIdentifier(portName);

            // Get the port's ownership
            serialPort =
                    (SerialPort) portId.open("Demo application", 5000);

            // Set the parameters of the connection.
            setSerialPortParameters();

            // Open the input and output streams for the connection. If they won't
            // open, close the port before throwing an exception.
            outStream = serialPort.getOutputStream();
            inStream = serialPort.getInputStream();
        } catch (NoSuchPortException e) {
            throw new IOException(e.getMessage());
        } catch (PortInUseException e) {
            throw new IOException(e.getMessage());
        } catch (IOException e) {
            serialPort.close();
            throw e;
        }
    }

    /**
     * Get the serial port input stream
     * @return The serial port input stream
     */
    public InputStream getSerialInputStream() {
        return inStream;
    }

    /**
     * Get the serial port output stream
     * @return The serial port output stream
     */
    public OutputStream getSerialOutputStream() {
        return outStream;
    }

    /**
     * Sets the serial port parameters
     */
    private void setSerialPortParameters() throws IOException {
        int baudRate = 57600; // 57600bps

        try {
            // Set serial port to 57600bps-8N1..my favourite
            serialPort.setSerialPortParams(
                    baudRate,
                    SerialPort.DATABITS_8,
                    SerialPort.STOPBITS_1,
                    SerialPort.PARITY_NONE);

            serialPort.setFlowControlMode(
                    SerialPort.FLOWCONTROL_NONE);
        } catch (UnsupportedCommOperationException ex) {
            throw new IOException("Unsupported serial port parameter");
        }
    }
}
Ряд прикладів по використанню RXTX можна знайти тут: http://rxtx.qbang.org/wiki/index.php/Examples

пʼятницю, 21 вересня 2012 р.

Узагальнення (Generics).

Вступ

 В JDK 5.0 з’явилось декілька нових розширень до мови програмування Java. Одне з таких нововведень – це узагальнення (generics).

 Ви можливо вже знайомі з подібними конструкціями з інших мов, найімовірніше з шаблонами (templates) в С++. Якщо так, то ви побачите, що є як подібності так і важливі відмінності. Якщо ви незнайомі з подібними конструкціями звідкілясь, це на краще, ви можете розпочати вивчення з нуля без помилкових уявлень.

Узагальнення дозволяють вам абстрагуватися над типами. Найбільш загальним прикладом є контейнерні типи, такі як у ієрархії Колекцій.

Ось типовий приклад даного виду:

List myIntList = new LinkedList(); // 1
myIntList.add(new Integer(0)); // 2
Integer x = (Integer) myIntList.iterator().next(); // 3


Приведення в рядку 3 є злегка надокучливим. Зазвичай, програміст знає, який тип даних поміщено у відповідний список. Проте, приведення є важливим. Компілятор може лише гарантувати, що ітератор поверне Object. Щоб забезпечити коректне присвоєння змінній типу Integer, необхідне приведення до типу.

Звичайно, приведення не тільки призводить до надмірності в коді. Це також призводить до можливостей помилок часу виконання, тож програма буде неправильною.

А що якщо програміст зможе вказати свої справжні наміри і задати список з конкретними обмеженнями щодо типів даних для розміщення у ньому? Це основна ідея узагальнень. Ось версія програмного фрагменту даного вище з використанням узагальнень:

List<Integer> 
    myIntList = new LinkedList<Integer>(); // 1'
myIntList.add(new Integer(0)); // 2'
Integer x = myIntList.iterator().next(); // 3'


Запримітьте оголошення типу для змінної myIntList. Написавши List<Integer>, зазначаємо, що це не довільний список, а цілочисельний список. Ми говоримо, що List є узагальненим інтерфейсом, що отримує параметр типу – в даному випадку, Integer. Ми також зазначаємо параметр типу, коли створюємо об’єкт списку.

Зазначте, також, що приведення в рядку 3 відкинуто. Зараз, ви мабуть думаєте, що ми перетасували безладдя в коді . Замість приведення до Integer в рядку 3, ми маємо Integer як параметр типу в рядку 1. Проте, тут є значна велика відмінність. Тепер компілятор може провірити коректність типів в програмі під час компіляції. Коли ми кажемо, що myIntList є оголошеним з типом List<Integer>, це говорить нам дещо про змінну myIntList, яка міститеми правильні дані, коли б змінна не застосовувалась і компілятор гарантуватиме це. А приведення ж нам говорить інше, що програміст думає, що це вірно в даній точці коду.

В результаті ж, особливо в великих програмах, це покращує читабельність та робастність (правильну роботу) програми.



Визначення простого узагальнення

Ось невеликий витяг з визначень інтерфейсів List та Iterator в пакеті java.util:
public interface List <E> {
    void add(E x);
    Iterator<E> iterator();
}

public interface Iterator<E> {
    E next();
    boolean hasNext();
}

Усе це повинне бути зрозуміле вам, окрім вмісту в кутових дужках. Це – оголошення формального параметру типу інтерфейсів List and Iterator.

Параметри типу можуть застосовуватись усюди в оголошенні узагальнення, особливо де ви застосовуєте звичайні типи (щоправда існують деякі важливі обмеження; дивість секцію The Fine Print)

У вступі, ви побачили виклик (invocation) узагальненого типу при оголошенні List, як то List<Integer>. При виклику (так званого параметризованного типу) всі входження формального параметра типу (E в данному випадку) заміняються актуальним аргументом типу (в даному випадку Integer).

Ви можливо уявили, що List<Integer> створює версію List де E замінюється на Integer:
public interface IntegerList {
    void add(Integer x);
    Iterator<Integer> iterator();
}

Дане уявлення корисне, проте дещо помилкове.

Воно користе, тому що параметризований тип List<Integer> справді має методи подібні до наведеного представлення.

Проте воно помилкове, тому що власне саме оголошення узагальнень ніколи не доповнюється таким чином. Не існує багатьох копій коду – ні в текстовому, ні в двійковому, ні на диску чи в пам’яті. Якщо ви С++ програміст, ви зрозумієте, що це значна відмінність від шаблонів C++.

Оголошення узагальненого типу компілюється один раз і поміщається у файл класу, як звичайний клас або оголошеня інтерфейсу.

Параметри типу є аналогами до звичайних параметрів, що використовуються в методах та конструкторах. Коли метод викликається актуальний аргумент підставляється у формальний параметр, і тіло методу виконується. Коли здійснюється оголошення узагальнення, актуальний аргумент типу підставляється у формальний параметр типу.

Зазначимо правила найменування. Ми рекомендуємо щоб ви використовували стислі назви (по можливості простий символ) для параметрів типу. Краще уникати нижнього регістру символі в таких назвах, що робить формальні параметри типу відмінними від звичайних класів та інтерфейсів. Багато контейнерних типів використовують E, для елементів, як в прикладах наведених вище. Ми розглянемо деякі інші умовності пізніше в прикладах.

Generics  - Java Tutorials (Bonus)
Частковий переклад: Volodimirg 

Оригінал повністю: http://docs.oracle.com/javase/tutorial/extra/generics/index.html

понеділок, 16 липня 2012 р.

Суміщення двох байт в Java

Постала необхідність прочитати з приладу потік байтів і їх перетворити на ряд двобайтових чисел. Готового методу в Java я не знайшов. Рішення підказав всезнаючий Інтернет:

public static short twoBytesToShort(byte b1, byte b2) {
          return (short) ((b1 << 8) | (b2 & 0xFF));
}
Інший приклад знайшов в книзі по Java. Тож це, також, можна зробити за допомогою потоку вводу даних DataInputStream:
FileInputStream fin=new FileInputStream("D://result.txt");
DataInputStream din=new DataInputStream(fin);
short s=din.readShort();
Якщо байти об'єднані в неправильній послідовності, тобто перший байт має бути другим, а другий першим в двобайтовому слові, то можна скористатись методом reverseBytes():
short k=Short.reverseBytes(s);

вівторок, 19 червня 2012 р.

Мітки Java

Мітка (JLabel) – це рядок тексту або зображення, що розміщується в компоненті. Це один з найпростіших компонентів графічного інтерфейсу. Вони дозволяють задавати вирівнювання тексту (вправо, зліва, по-центру) в середині компонента та не мають особливих подій, які б асоціювалися з ними. Наступний код демонструє різноманітні способи створення міток.
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
 
public class Labels {
    public static void main(String[] args) {
     LabelFrame frame = new LabelFrame();
     frame.setSize(150, 200);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}
 
class LabelFrame extends JFrame{
    //створюємо панель
    JPanel panel=new JPanel();
 
    LabelFrame(){
     // вирівнювання за замовчуванням (CENTER)
    JLabel label1 = new JLabel("Багато левів, ");
    // вирівнювання вліво
    JLabel label2 = new JLabel("тигрів з тигрицями", SwingConstants.LEFT); 
    // мітка без тексту, вирівнювання за замовчуванням
    JLabel label3 = new JLabel(); 
    // створюємо іконку
    Icon icon = new ImageIcon("icon.gif");
    // створюємо мітку із зображенням
    JLabel label4 = new JLabel(icon); 
    // задаємо текст для label3
    label3.setText("і ведмедів");
    // встановлюємо вирівнювання
    label3.setHorizontalAlignment(SwingConstants.RIGHT);
    //додаємо мітки в панель
    panel.add(label1);
    panel.add(label2);
    panel.add(label3);
    panel.add(label4);
    //додаємо панель у фрейм
    this.add(panel);
    }
}
Константи вирівнювання визначені в інтерфейсі SwingConstants. Щоправда вирівнювання тексту відбувається всередині компоненти Label, тому коли компонента підганяється під розмір вмісту, вирівнювання непомітне. Для зміни кольору і шрифту в класі Component існують методи setFont() та setColor(), які застосовуються не тільки для міток, але й для будь-яких компонентів. В тексті мітки можливе також застосування HTML:
JLabel label=new JLabel ("<html>"+ "S<font size=-2>MALL");

Повний варіант книги знаходиться на Вікіпідручнику

вівторок, 12 червня 2012 р.

Вступ в класи та методи

Клас, метод, ООП

Класи

Класи – це спеціального виду конструкції, які, дозволяють об’єднати ряд змінних різних типів в одне ціле. Крім власне даних, класи зазвичай включають підпрограми (в термінології java - методи) і можуть включати блоки(сукупність інструкцій між фігурними дужками {}) та інші класи(внутрішні класи). Таким чином утворюються нові типи даних.
Роз’яснення принципів побудови і роботи з класами доволі громіздка тема, тому тут розглянемо лише спрощені основи їх роботи і створення. Детальніше дивіться розділ присвячений класам. Розглянути зараз необхідно через те, що Java повністю об’єктно-орієнтована мова і з класами та пов’язаними з ними методами Ви стикатиметесь на кожному кроці. Зокрема навіть вивід даних System.out.prinln(); - здійснюється за допомогою класу System та методу println().
Для прикладу розглянемо наступну задачу: «Ви фанат збору 1 гривневих монет:). Назбирали їх чимало і хочете купити невеличкий сейф, щоб туди вмістилася ваша вся колекція і вбудувати цей сейф у стіну, щоб його з вашою колекцією не вкрали:). В інтернет-магазині вказані розміри сейфу. Постає питання, який же сейф вибрати? Оскільки сейф не один, то щоб не розраховувати вручну кожного разу об'єм сейфу, Ви захотіли написати відповідну програму.»
І так маємо:
/** 
 * CoinVoume.java
 */
public class CoinVolume {
    public static void main(String[] args) {
    double width1=10, height1=15, depth1=20;
    double width2=15, height2=20, depth2=15;
    double width3=15, height3=25, depth3=15;
 
    int    cointAmount=15000; //кількість монет - непогано зібрав :)
    double coinVolume=2*2*0.1; //приблизний об'єм монети=2*діаметр*товщину
    double safeVolume1;
    double safeVolume2;
    double safeVolume3;
    double totalCoinVol;
 
    totalCoinVol=cointAmount*coinVolume; // заг. об'єм, який займають монети
 
    safeVolume1=width1*height1*depth1; //об'єм першого сейфу
    safeVolume2=width2*height2*depth2;  //об'єм другого сейфу
    safeVolume3=width3*height3*depth3;  //об'єм третього сейфу
 
 
    System.out.println("Об'єм 1-го сейфу="+safeVolume1);
    System.out.println("Об'єм 2-го сейфу="+safeVolume2);
    System.out.println("Об'єм 3-го сейфу="+safeVolume3);
 
    System.out.println("Загальний об'єм монет="+totalCoinVol);
    }
}

Результат виконання:
Об'єм 1-го сейфу=3000.0
Об'єм 2-го сейфу=4500.0
Об'єм 3-го сейфу=5625.0
Загальний об'єм монет=6000.0 
Як бачимо з трьох не підійшов жоден, потрібен більший. Проте додавання кожного нового сейфу вимагає дописування доволі багатьох інструкції. Потрібно оголошувати три змінні для довжини, ширини та глибини сейфу, також потрібна змінна для об’єму та додавати інструкції обчислення та виводу на екран результатів. Звичайно, можна оцінювати по одному змінюючи значення змінних, але тоді прийдеться кожного разу перекомпільовувати і запускати програму. А якщо ви захочете ще раз оцінити розміри деяких сейфів, прийдеться виконувати роботу ще раз. Ось тут в пригоді і стане нам клас Safe. Зверніть увагу, що назва класу пишеться з великої букви. Рекомендовано давати назви класів з великої. Таким чином дуже просто розрізнити його від інших складових програми, наприклад назву класу від назви змінної, які прийнято називати з маленької букви.
Оголосити найпростіший клас можна так:
class Safe{
    double width;
    double height;
    double depth;
    double safeVolume;
}
Для його оголошення використовується ключове слово class та назва класу, далі іде тіло класу у фігурних дужках {}. Проте, хоч клас існує, ми не можемо так просто його використовувати. Ми повинні спочатку створити екземпляр даного класу (об’єкт). Для цього необхідно написати наступну інструкцію:
Safe mySafe1=new Safe();
де Safe – назва класу, mySafe – назва змінної, яка посилатиметься на наш об'єкт, new Safe() – створює об’єкт(при цьому відбувається виділення пам’яті під об’єкт). Таким чином ми створили перший сейф. Щоб створити другий сейф використовується аналогічна інструкція:
Safe mySafe2=new Safe(); //як бачимо змінилась лише назва змінної
Інколи класи порівнюють з формочкою для випічки печива, а саме печиво – це уже конкретний створений екземпляр (об’єкт). Форма може бути одна, а печива на її основі можна зробити безліч із різною начинкою. Так сама і з класом – це шаблон, а на його основі можемо створити безліч екземплярів даного класу.
Проте як же ми можемо звернутися до змінних об’єкту? Для цього використовується операція «.»(точка), а сама інструкція звернення в такій формі - назваОб’єкту.змінна:
mySelf1.width=10;
Перепишемо нашу програму з використанням класу Safe:
class Safe{
    double width=0;
    double height=0;
    double depth=0;
    double safeVolume=0; //додамо змінну, в якій зберігатиметься об'єм сейфу
}
public class CoinVolume {
    public static void main(String[] args) {
    //створюємо перший сейф
    Safe mySafe1=new Safe();
    //вказуємо його розміри
    mySafe1.width=10;
    mySafe1.height=15;
    mySafe1.depth=20;
    //обчислюємо об'єм сейфу
    mySafe1.safeVolume=mySafe1.width*mySafe1.height*mySafe1.depth;
 
    //аналогічно для другого сейфу
    Safe mySafe2=new Safe();
    mySafe2.width=10;
    mySafe2.height=15;
    mySafe2.depth=20;
    mySafe2.safeVolume=mySafe1.width*mySafe1.height*mySafe1.depth;
 
    //виводимо на консоль об'єми сейфів
    System.out.println("Об'єм 1-го сейфу="+mySafe1.safeVolume);
    System.out.println("Об'єм 2-го сейфу="+mySafe2.safeVolume);
    }
}
Щоб зосередитись на основному, з програми усунено обчислення об’єму монети. Компіляцію програми здійснюємо так же само як і попередню, за назвою класу в якому знаходиться метод main()— javac CoinVolume.java. Клас Safe не обов'язково може бути в одному і тому ж файлі, що і клас CoinVolume.
І так клас ми добавили, проте тепер вона виглядає складнішою ніж попередній варіант. Ситуацію виправити може використання методів.

Методи

Методи в java – це аналог підпрограм, функцій, процедур в інших мовах програмування. За допомогою методів ми виносимо текст повторюваного коду програми окремо в тіло методу, після чого можна викликати даний метод з будь-якого місця програми, безліч разів.
Спрощене оголошення та визначення методу, який ми зараз будемо використовувати, має вигляд:
тип_повернення  назва_методу(параметри){

//тіло методу;
інструкція1;
інструкція2;
…..
інструкціяN;
}
Тип_повернення – результат виконання методу, наприклад він може повертати об’єм сейфу, тоді тип_повернення буде double. Якщо метод нічого не повертає, то вказується слово ключове слово void.
Виклик методу здійснює наступна інструкція: назва_методу(параметри). Взагалі в термінології мов програмування для виклику методу використовуються аргументи, а в самому методі – це уже параметри, оскільки передаються лише значення змінних, а не самі змінні. Аргументи та параметри повинні бути одного і того ж типу. Якщо ми передаємо цілочисельне значення, то і параметр повинен бути цілочисельним і т.п. Тобто в методі створюються нові змінні. В деяких мовах, наприклад в С++, як аргумент можна передати посилання на певну змінну, таким чином її можна буде модифікувати в функції через вказівник на дану змінну. В Java в метод передаються лише значення змінних, тому розрізнення аргументів і параметрів менш суттєве і ми там і там використовуватимемо термін «параметр». Об'єкти ж в методи передаються по посиланню. Тобто, при передачі в якості аргументу об'єкта, буде передане посилання на об'єкт, а не створений новий об'єкт.
Повернемось до нашої програми. Повторюваними є присвоювання значень змінним, обчислювання та вивід об’ємів. Тому корисно буде створити два методи safeValue (double width, double height, double depth) та safeVolume (). Перший для присвоєння змінним значень, а другий для обчислення об'єму.
Модифікована програма матиме вигляд:
class Safe{
    double width=10; // поля класу можуть бути ініціалізовані з самого початку
    double height=10;
    double depth=10;
    double safeVolume=0;
 
    // метод присвоєння значень змінним
    void safeValue(double aWidth, double aHeight, double aDepth){
        width=aWidth;
        height=aHeight;
        width=aWidth;
    }
 
    // метод для обчислення об'єму сейфа
    double safeVolume(){
        return width*height*width;
    }
}
public class CoinVolume {
public static void main(String[] args) {
    double width1=10, height1=20, depth1=40;
    Safe mySafe1=new Safe(); //створюємо перший сейф
    Safe mySafe2=new Safe(); //створюємо другий сейф
 
    //задаємо розміри сейфу
    //викликаємо метод safeValue() класу Safe, що ініціалізує поля об'єкту
    mySafe1.safeValue(width1,height1,depth1);
    mySafe2.safeValue(10.0, 15.0, 15.5); //можна і так
 
    //виводимо на екран об'єми сейфів
    //для чого викликаємо метод safeVolume(), який повертає обчислений об'єм кожного сейфу
    System.out.println("Об'єм 1-го сейфу="+mySafe1.safeVolume());
    System.out.println("Об'єм 2-го сейфу="+mySafe2.safeVolume());
    }
}
Як бачимо код програми спростився. Тепер набагато легше модифікувати програму, додаючи нові сейфи. Крім того можна наприклад вивід повідомлення з інформацією про об’єм розмістити метод safeVolume() або в окремий метод, наприклад, printVolume().
Слід зауважити, щодо назв змінних-параметрів. Так для висоти, широти та глибини в методі safeValue() вибрані назви aWidth, aHeight, aDepth. Вони могли б мати назви і просто width, height, depth, але тоді б вони перекрили б доступ до однойменних змінних класу. В такому випадку, щоб звернутися до змінних класу з методу необхідно вживати ключове слово this. Наприклад: this.height=height - тут ми присвоюємо змінній класу this.height одержаний методом параметр height.

Конструктори

Замість методу safeValue(), який в нас заповнює змінні об’єкту значеннями ми можемо створити метод, який буде мати назву таку ж як і клас, тобто Safe(aWidth, aHeight, aDepth). Це дасть нам можливість ще скоротити програму, оскільки при створенні об’єкту ми зможемо зразу ж задавати розміри сейфу.
Safe mySafe1=new Safe(10.0, 15.0, 20.0)
Такі методи носять назву “конструктор класу”. Коли ми писали просто new Safe(); то віртуальна машина використовувала конструктор по замовчуванню без параметрів, який практично нічого корисного для нас не робив. Тепер же ми можемо використовувати новий створений нами конструктор.
Таким чином, новий варіант програми:
class Safe {
    final double width;
    final double height;
    final double depth;
 
    // конструктор
    Safe(double pWidth, double pHeight, double pDepth) {
        width = pWidth;
        height = pHeight;
        depth = pDepth;
    }
 
    // обчислюємо об'єм сейфу
    double getVolume() {
        return width * height * width;
    }
 
}
 
public class CoinsVolume {
    public static void main(String[] args) {
        double width1 = 10, height1 = 20, depth1 = 40;
        Safe safe1 = new Safe(width1, height1, depth1); // створюємо 1-й сейф
        Safe safe2 = new Safe(10.0, 15.0, 20.0); // створюємо 2-й сейф
        Safe safe3 = new Safe(10.3, 15.4, 20.5); // створюємо 3-й сейф
        Safe safe4 = new Safe(20.0, 30.0, 20.0); // створюємо 4-й сейф
 
        printSafeVolume(safe1, 1); // виводимо об'єм 1-го сейфу
        printSafeVolume(safe2, 2);
        printSafeVolume(safe3, 3);
        printSafeVolume(safe4, 4);
    }
 
    // вивід об'єму сейфу
    // safe - сейф
    // number - номер сейфу
    static void printSafeVolume(Safe safe, int number) {
        System.out.println("Об'єм " + number + "-го сейфу=" + safe.getVolume());
    }
 
}
Результат виконання:
Об'єм 1-го сейфу=2000.0
Об'єм 2-го сейфу=1500.0
Об'єм 3-го сейфу=1633.786
Об'єм 4-го сейфу=12000.0 
В наведеному прикладі, щоб обчислити об’єм нового сейфу, нам потрібно додати лише два рядочки тексту (дві інструкції). Щоправда навіть це можна автоматизувати за допомогою використання іншого типу даних – масивів, які будуть розглядатися пізніше. Можна також додати клас Coin, в якому був би метод для обчислення сукупного об’єму різноманітних монет. Ви можете спробувати зробити таку програму зараз. Це буде корисним для засвоєння викладеного матеріалу.
Тема класів та методів значно комплексніша, тому основне, що Ви повинні винести з даного розділу -це розуміння того, як використовуються методи класів. Java надає великий набір уже готових класів та методів, які значно спрощують роботу програміста.

Повний варіант книги знаходиться на Вікіпідручнику

четвер, 29 грудня 2011 р.

Cтворюємо графіки з допомогою JFreeChart

Декілька років назад довелося малювати графік в Java аплеті. Як виявилося не така вже й проста задача, особливо коли кількість даних постійно змінюється і розміри аплета теж. Тоді ж натрапив на безкоштовну бібліотеку JFreeChart, яка дозволяє малювати діаграми різного типу: графіки, стовпцеві діаграми, кругові і т.д. Зараз таких бібліотек доволі багато як безплатних так і платних. Платні переважно надають доволі непогану візуалізацію з ефектами об’ємності і т.п. JFreeChart дещо гірше промальовує графіку, але порівняно з іншими безкоштовними – це одна із найкращих, яка має багато засобів для модифікації вигляду графіку, виводу міток і написів над точками, масштабування осей та графіків тощо. Щоправда дещо заплутана документація. Існує також платний посібник розробника, який дещо детальніше описує процес створення. Багато прикладів можна знайти в Інтернеті і роз’яснень до них. Можна навіть скачати посібник до старіших версій бібліотеки.
Для використання JFreeChart необхідно скачати два jar файли JCommon та JFreChart з офіційного сайту. В інструкції по встановленню описано як можна підключити бібліотеки для використання разом з NetBeans та Eclipse. Також можна запустити демонстраційну програму, яка демонструє приклади готових графіків. Їхній код можна отримати разом з посібником. Багато прикладів програм можна знайти тут:  http://www.java2s.com/Code/Java/Chart/CatalogChart.htm
Алгоритм створення графіку простий:
1)    Створити набір даних (dataset)
2)    Створити об’єкт діаграми, який відповідатиме за вивід діаграми
3)    Додати графік на якусь графічну компоненту

Розглянемо як можна намалювати звичайний лінійний графік.  Їх можна створити засновуючись на двох типах даних, які базуються на інтерфейсах CategoryDataset та XYDataset.
Перший вид графіків передбачає, що на одній з осей будуть знаходитись цифрові значення, а на іншій текстові значення (категорії).
JFreeChart, Chart on Java
Другий тип передбачає, що і по X та по Y знаходяться числові значення. Саме такий ми будемо будувати.
Існують також можливість створення часових діаграм, на яких одна з осей представляє собою час. Дані графіки базують на XYDataset .
Вибір типу діаграми визначає які класи будуть застосовуватись при її створенні і відповідно, які методи будуть  доступні для роботи з даною діаграмою.
Далі наведений приклад програми, що малює два графіки на одній області.
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class FirstXYChart {
public static void main(String[] args) {

 JFrame frame = new JFrame(); //створюємо каркас вікна
 frame.setTitle("Графік");    //заголовок вікна
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

 //створюємо 1 ряд даних
 XYSeries series = new XYSeries("Ряд1 1");
 //додаємо точки на графіку
   series.add(1, 11);
   series.add(2, 12);
   series.add(3, 13);
   series.add(4, 14);
   series.add(5, 15);
   series.add(6, 16);
   series.add(7, 17);
   series.add(8, 58);
   series.add(9, 19);
   series.add(10, 11);

//створюємо 2 ряд даних
XYSeries series2 = new XYSeries("Ряд1 2");
   series2.add(2, 1);
   series2.add(2, 3);
   series2.add(4, 3);
   series2.add(4, 5);
   series2.add(6, 7);
   series2.add(6, 8);
   series2.add(9, 7);
   series2.add(8, 28);
   series2.add(13, 9);
   series2.add(12, 12);

// зразу ж додаємо ряд в набір даних
XYSeriesCollection data = new XYSeriesCollection(series);
data.addSeries(series2); // додаємо другий ряд в набір
//створюємо діаграму
final JFreeChart chart = ChartFactory.createXYLineChart(
  "XY Series Example",
  "X",
  "Y",
  data,
  PlotOrientation.VERTICAL,
  true,
  true,
  false
);

 //створюємо панель для графіка
 final ChartPanel chartPanel = new ChartPanel(chart);
 //встановлюємо розмір графіка
 chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
 //додаємо панель на створений нами фрейм
 frame.setContentPane(chartPanel);
 //підганяємо розміри фрейму
 frame.pack();
 //робимо усе видимим
 frame.setVisible(true);
 }
}
Результат:
JFreeChart, Chart on Java, Plot
Практично схожим чином можна створювати і інші типи діаграм.
Модифікація діаграм
В JFreeChart також передбачені широкі можливості по зміні зовнішнього вигляду діаграми.
Наприклад, змінюємо фон:
XYPlot plot=chart.getXYPlot();         // одержати область побудови діаграми
plot.setBackgroundPaint(Color.CYAN);   // встановлюємо колір

Крім задання кольору, можна поставити як фон певне зображення.
Якщо хочемо змінити колір кривих:
XYItemRenderer renderer=plot.getRenderer();  //отримати візуалізатор(рендерер)
renderer.setSeriesPaint(0, Color.darkGray);  // задаємо колір першого графіка
renderer.setSeriesPaint(1, Color.GREEN);     // задаємо колір другого графіка

Можна також задавати мітки на графіки, вигляд точок і т.п. З усім можна розібратись по документації та наявних в інтернеті прикладах.

Читання каталогу на Java

Читати папку java, каталог javaПрийшлось вирішувати наступну задачу. Необхідно було за допомогою програми на java збити дані з файлів в каталозі в один. Крім власне читання з файлів і запису, виникла необхідність прочитати вміст каталогу(папки)  і одержати список файлів.

Читання вмісту каталогу (Java)

Для роботи з файлами і каталогами (папками) слугує клас File. Каталог по суті представляє той же File-об'єкт, який містить список інших файлів і каталогів. Перевірка такого об’єкта в java виконується за допомогою методу isDirectory().
  

import java.io.File; //імпортуємо відповідний клас

**
* @author volodimirg
*/
public class AllInFileTest {
 public static void main(String[] args) {
  String dirname="D:\\install\\tmp"; // наша робочий каталог
  File ourFile=new File(dirname); // створюємо File-об'єкт

  if (ourFile.isDirectory()){
  System.out.println("Каталог: "+dirname);
  String files[]=ourFile.list(); //одержуємо і заносимо список файлів в масив
  for (int i=0;i<files.length;i++){
   File f =new File (dirname+"/"+files[i]); //беремо для перевірки кожен File-об'єкт в каталозі
  if (f.isDirectory()){
    System.out.println(files[i]+" - це каталог");
  }else{
  System.out.println(files[i]+" - це файл");
  }
 }
 }
 }
}

Каталог: D:\\install\\tmp
1-49і.csv - це файл
1-2і.csv - це файл
1-3і.csv - це файл
1-5і.csv - це файл
1-7і.csv - це файл
1-9і.csv - це файл
1-11і.csv - це файл
1-13і.csv - це файл
1-15і.csv - це файл
1-17і.csv - це файл
1-19і.csv - це файл
1-21і.csv - це файл
1-23і.csv - це файл
1-25і.csv - це файл
1-27і.csv - це файл
1-29і.csv - це файл
1-31і.csv - це файл
1-33і.csv - це файл
1-35і.BAK - це файл
1-47і.csv - це файл
1-45і.csv - це файл
1-43і.csv - це файл
1-41і.csv - це файл
1-39і.csv - це файл
1-37і.csv - це файл
1-51і.csv - це файл
1stTree Lypa40rЖовтня.xlsx - це файл
1-1і.csv - це файл
Other - це каталог
My - це каталог
Проте для виконання поставленої задачі необхідно перебирати файли у посортованому вигляді.

Сортування списку файлів в Java

Порившись в інтернеті можна знайти поради використовувати класи з колекцій пакету java.util і зокрема Comparator для сортування файлів у списку. Хоч це не складний спосіб, та й лінь згадувати і розбиратись, тим більше, що знайшов простіший спосіб. У тому ж пакеті міститься клас Array, який надає ряд зручних методів для роботи з масивами. Зокрема і метод для сортування масиву sort().
Таким чином наша програма потребує лише додавання двох рядків:
import java.util.*; //підключаємо відповідний клас
Arrays.sort(files); //сортуємо масив, результат повертається у тому ж масиві

Повний текст програми наступний.
import java.io.File; //імпортуємо клас File
import java.util.Arrays; // імпортуємо клас Arrays
/**
* @author volodimirg
*/
public class AllInFileTest {
public static void main(String[] args) {
 String dirname=" D:\\install\\tmp "; // наш робочий каталог
 File ourFile=new File(dirname); // створюємо File-об'єкт

 if (ourFile.isDirectory()){
   System.out.println("Каталог: "+dirname);
   String files[]=ourFile.list(); //одержуємо і заносимо список файлів в масив
   Arrays.sort(files); // сортуємо масив, результат у тому ж масиві
   for (int i=0;i<files.length;i++){
     File f =new File (dirname+"/"+files[i]); //беремо для перевірки кожен File-об'єкт в каталозі
     if (f.isDirectory()){
       System.out.println(files[i]+" - це каталог");
     }else{
     System.out.println(files[i]+" - це файл");
  }
 }
}
}
}