Использование транзакций в программах на Java

Задача
Вы хотите выполнить транзакцию в сценарии JDBC.

Решение
Используйте стандартный механизм поддержки транзакций JDBC.

Обсуждение
Для выполнения транзакции в Java используйте ваш объект Connection для отключения режима автофиксации. После запуска запросов используйте метод commit()объекта для фиксации транзакции или rollback() для ее отката. Обычно предложения транзакции выполняются в блоке try, в конце которого стоит commit(). Для обработки ошибок вызовите rollback() в соответствующем обработчике исключений:

try
{
conn.setAutoCommit (false);
Statement s = conn.createStatement ();
// передать деньги от одного человека другому
s.executeUpdate ("UPDATE money SET amt = amt - 6 WHERE name = 'Eve'");
s.executeUpdate ("UPDATE money SET amt = amt + 6 WHERE name = 'Ida'");
s.close ();
conn.commit ();
conn.setAutoCommit (true);
}
catch (SQLException e)
{
System.err.println ("Transaction failed, rolling back.");
Cookbook.printErrorMessage (e);
// пустой обработчик исключений, если откат не удался
try
{
conn.rollback ();
conn.setAutoCommit (true);
}
catch (Exception e2) { }
}

Добавлено: 23 Июля 2018 20:50:49 Добавил: Андрей Ковальчук

Многозадачность в JavaMe при HTTP соединении

Введение
Разрабатывая простые приложения для JavaMe мы обычно не нуждаемся в использовании многозадачности. Но как только от мидлета требуется производить такие действия, как связь с серверами по HTTP протоколу или SMS, показывать анимацию или ожидать совершения какого-либо события, то без многозадачности не обойтись. В статье мы сфокусируемся на решении следующей, реально возникшей практической, задачи. Мобильное приложение должно отправить информацию на сервер по протоколу HTTP, получить ответ, а во время ожидания показывать анимированную картинку. Далее предполагается, что читатель знаком с JavaMe, ее ограничениями и возможностями. Далее подразумевается MIDP 2.0. В первой части статьи мы попробуем ответить на вопрос, а так ли уж необходима многозадачность при работе с сетевым соединением. Далее мы рассмотрим два способа установления соединения в отдельном потоке. В третей части мы рассмотрим, как разные потоки могут взаимодействовать друг с другом. В заключении, будет не большой рассказ о том, как все перечисленное можно использовать при разработке реального приложения.

HTTP - зачем многозадачность?
Действительно, почему просто не поставить вызов соединения в код выполнения какой либо команды. Например так:

public class Simple extends MIDlet implements CommandListener{ 
 ...
 ...

 private void connectWOThread(){
 String urlString = input.getString();
 HttpConnection conn = null;
 try {
 conn = (HttpConnection)Connector.open("http://"+urlString);
 int resp = conn.getResponseCode(); 
 output.setString(new Integer(resp).toString());
 } catch (IOException e) {
 e.printStackTrace();
 }finally{
 if(conn !=null){
 try {
 conn.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
 }
 
 public void commandAction(Command command, Displayable arg1) {
 if(command.equals(connectD)){
 connectWOThread();
 }
 }

}

На первый взгляд ничего неправильного в приведенном выше коде нет. Однако, на большинстве реальных устройств, а также на некоторых эмуляторах этот код выполнятся не будет, возникает блокировка или дедлок. Рассмотрим, как выполняется этот код на некоторых платформах и причины, по которым возникает дедлок. Во первых, код выполняется в системном потоке или потоке событий. Система блокирует поток, вызвавший запрос на установление соединения до того момента, когда соединение будет фактически установлено, в нашем случае блокируется системный поток. В этот момент система безопасности "песочницы", а как известно все мидлеты, если они не подписаны, выполняются в "песочнице", может потребовать от пользователя разрешения на выполнение операции соединения. Запрос на разрешение должен выполнить системный поток, который в свою очередь ожидает завершения установления соединения. Получаем дедлок. Поэтому, настоятельно рекомендуется все действия, связанные с сетевыми запросами выносить в отдельный поток.

Два способа решения проблемы.
Простейшая многозадачная реализация приведенного выше кода может выглядеть так:
public class Simple extends MIDlet implements CommandListener{
 ...
 ...
 private void connectWThread(){
 String urlString = input.getString();
 HttpConnection conn = null;
 try {
 conn = (HttpConnection)Connector.open("http://"+urlString); 
 int resp = conn.getResponseCode(); 
 output.setString(new Integer(resp).toString());
 } catch (IOException e) {
 e.printStackTrace();
 }finally{
 if(conn !=null){
 try {
 conn.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
 }
 
 public void commandAction(Command command, Displayable arg1) {
 if(command.equals(connectSimple)){
 SimpleConnector sc = new SimpleConnector();
 new Thread(sc).start();
 }
 }
 
 private class SimpleConnector implements Runnable{
 public void run() {
 connectWThread();
 }
 
 }
}

Мы немного модифицировали наш код. Мы вынесли операцию установления соединения в отдельный поток. Приведенный выше код уже работает, он не приводит к дедлоку, если мы выполняем команду connectSimple. Таким образом, мы можем устанавливать сетевое соединение с внешними ресурсами внутри нашей программы. Теперь надо вспомнить, что мы говорим о приложении работающем на мобильном устройстве. MIDP 2.0 гарантирует нам только то, что приложение может запускать одновременно как минимум 10 потоков, а также открывать как минимум одно сетевое соединение. Таким образом, если логика приложения позволяет производить несколько соединений одновременно, например, отсылать на сервер некоторые данные, получать от сервера картинку, то на некоторых платформах мы сделать этого не сможем. Помимо этого, создание нового потока довольно ресурсоемкая операция.

Если мы хотим, чтобы наша программа работала на как можно большем количестве устройств, то наиболее простым решением будет следующее: Запустить параллельный поток, отвечающий только за установку сетевых соединений. В тот момент, когда нам нужно это соединение, мы просто активируем этот поток, он выполняет необходимые действия и "засыпает".

Пример измененного кода:
... protected void startApp() throws MIDletStateChangeException { connecto = new ConnectionThread(); new Thread(connecto).start(); Display.getDisplay(this).setCurrent(mainForm); } private void connectWOThread(){ String urlString = input.getString(); HttpConnection conn = null; try { conn = (HttpConnection)Connector.open("http://"+urlString); int resp = conn.getResponseCode(); output.setString(new Integer(resp).toString()); } catch (IOException e) { e.printStackTrace(); }finally{ if(conn !=null){ try { conn.close(); } catch (IOException e) { e.printStackTrace(); } } } } public void commandAction(Command command, Displayable arg1) { if(command.equals(connectSimple)){ connecto.conn(); } } private class ConnectionThread implements Runnable { private Object mut = new Object(); private boolean shouldRun = true; public void run() { while(shouldRun){ synchronized (mut) { try{ mut.wait(); }catch(InterruptedException e){} } if(!input.getString().equals("")){ connectWOThread(); input.setString(""); } } } public void conn(){ synchronized (mut){ mut.notify(); } } } ...

Как видно из кода, в момент старта или активации приложения запускается новый поток, который тут-же ставится на ожидание mut.wait(). Активация потока и постановка его в ожидание реализована с помощью монитора. Монитором может выступать любой объект, кроме примитивных типов и строк, в некоторых реализациях. Активация потока происходит путем вызова метода mut.notify(). Так как этот вызов находится в блоке synchronized, то это значит, что монитор заблокирован для всех остальных потоков, которые хотят к нему обратится. У нас запущен только один поток, поэтому он и будет активирован. Активированный поток должен тут-же заблокировать монитор для себя, что достигается путем synchronized блока.

Что же получилось в результате? При запуске или активации приложения создается новый спящий поток, который активируется при выборе пользователем определенной команды. Это позволяет экономно расходовать ресурсы, в отличие от бесконечного цикла. После выполнения этот поток становится спящим. Естественно в методе pauseApp() необходимо остановить выполнение дополнительного потока.

Взаимодействие потоков.
Теперь рассмотрим как можно реализовать анимированную заставку на момент установления соединения. Для чего это надо? Если приложение предполагает интенсивный обмен данными с сервером, то хорошо бы в момент соединения выводить картинку. Так как в данной статье мы рассматриваем потоки, то можно сделать картинку анимированной. Вначале несколько замечаний. В спецификации сказано, что MIDP контейнер обязан уметь работать с графическими файлами в формате PNG. При этом форматы GIF и JPG не упоминаются. Тем не менее, довольно большое количество телефонов поддерживают эти форматы, но есть модели(некоторые из которых очень популярны, например смартфоны фирмы HTC), которые эти форматы не поддерживают. Поэтому у нас все картинки будут только в PNG.

Анимационная заставка должна работать следующим образом. Когда пользователь нажимает на команду соединения с сервером всплывает анимированая картинка. Когда обмен данных с сервером завершается картинка убирается. Все очень просто. Исходя из соображений приведенных ранее, для заставки мы создадим один поток и будем просто вызывать его в тот момент, когда нам это будет надо.
...
 ...
 protected void startApp() throws MIDletStateChangeException {
 connecto = new ConnectionThread();
 new Thread(connecto).start();
 animationT = new AnimThread();
 new Thread(animationT).start();
 Display.getDisplay(this).setCurrent(mainForm);
 }

 ...
 ...
 
 public void commandAction(Command command, Displayable arg1) {
 if(command.equals(connectSimple)){
 connecto.conn();
 }
 }
 
 
 private class ConnectionThread implements Runnable {
 private Object mut = new Object();
 private boolean shouldRun = true;
 
 public void run() {
 while(shouldRun){
 
 synchronized (mut) {
 try{
 mut.wait();
 }catch(InterruptedException e){}
 } 
 if(!input.getString().equals("")){
 animationT.show();
 connectWOThread();
 input.setString("");
 animationT.hide();
 } 
 }
 }
 
 public void conn(){
 synchronized (mut){
 mut.notify();
 }
 }
 }
 
 private class AnimThread extends Canvas implements Runnable{
 private final String path = "/test/multithreading/start.png";
 private final int w = 55; //sprite pixels width
 private final int h = 68; //sprite pixels height
 private final int delay = 100; //milliseconds
 private final long minShows = 5000;
 
 private Sprite anim = null;
 
 
 private Object mut = new Object();
 private boolean shouldRun = true;
 private Boolean show = new Boolean(false);
 
 public AnimThread(){
 InputStream is = AnimThread.class.getResourceAsStream(path);
 Image im;
 try {
 im = Image.createImage(is);
 anim = new Sprite(im,w,h);
 //adjusting position of animation 
 int w1 = this.getWidth();
 int h1 = this.getHeight();
 anim.setPosition((w1-anim.getWidth())/2, (h1 - anim.getHeight())/2);
 
 } catch (IOException e) {
 e.printStackTrace();
 }
 
 }
 
 public void run() {
 while(shouldRun){ 
 synchronized (mut) {
 try{
 mut.wait();
 }catch(InterruptedException e){}
 } 
 
 if(anim != null){
 long star_time = System.currentTimeMillis();
 boolean finished = false;
 synchronized (show) {
 finished = false;
 }
 int counter = 0;
 repaint();
 while(!finished){ 
 paintSingleFrame(counter++);
 counter = counter<anim.getFrameSequenceLength()?counter:0;
 if(!shouldRun){
 break;
 }
 synchronized (show) {
 if((star_time+minShows)<System.currentTimeMillis()&&!show.booleanValue()){
 finished = true;
 disp.setCurrent(mainForm);
 }
 } 
 }
 }
 }
 }
 
 
 
 private void paintSingleFrame(int frameIndex){
 anim.setFrame(frameIndex);
 repaint(anim.getX(),anim.getY(),anim.getWidth(), anim.getHeight()); 
 
 try {
 Thread.sleep(delay);
 } catch (InterruptedException e) {}
 }
 
 
 protected void paint(Graphics g) {
 g.setColor(255,255,255);
 g.fillRect(g.getClipX(), g.getClipY(), g.getClipWidth(), g.getClipHeight());
 if(anim!=null){
 anim.paint(g);
 }
 }
 
 public void show(){
 synchronized (mut){
 show = new Boolean(true);
 disp.setCurrent(this);
 mut.notify();
 }
 }
 
 public void hide(){
 synchronized (show){
 show = new Boolean(false); 
 }
 }
 
 }

}

Как можно увидеть из приведенного выше кода наш мидлет стал более сложным. Одновременно у нас запускаются два потока. Один из них как и раньше отвечает за сетевые соединения. Другой поток отвечает за показ анимированной заставки.

Поток, отвечающий за показ анимации, становится в режим ожидания сразу после своего запуска. За это отвечает объект mut. Поток активируется точно таким же способом, как и поток connecto. Некоторая сложность кода обусловлена тем, что анимация будет демонстрироваться как минимум minShows миллисекунд.

Применение
Описанный выше способ реализации мидлета, устанавливающего сетевые соединения, применялся при разработке мобильного приложения к системе DomEconom. Эта система предназначена для помощи при ведении учета семейных финансов. В ней реализована довольно интересная технология распределенного хранения данных, что позволяет вносить данные о доходах и расходах разными членами семьи с разных компьютеров, например с домашнего и с рабочего. Система сама синхронизирует данные. Более того все данные хранятся в зашифрованном виде, а пароль известен только пользователю. Таким образом никто не зная пароля не может прочитать конфиденциальную информацию. Для облегчения ввода данных о расходах был разработан мидлет. Он работает следующим образом. Пользователь заполняет форму, в которой указывает сумму, счет, категорию, валюту и т.д. и отправляет эти данные на сервер. В процессе отправки мидлет шифрует данные, показывает пользователю анимированную заставку. Система полностью бесплатна. Посмотреть ее можно по адресу: www.domeconom.ru

Добавлено: 25 Мая 2018 09:32:04 Добавил: Андрей Ковальчук

Тщательная перетасовка колоды карт. Пример Java приложения.

В данной статье я бы хотел показать один из вариантов алгоритма, выполняющего перетасовку колоды игральных карт, и, безусловно, обсудить его достоинства и недостатки.

Если вы захотите написать программу для игры в карты, то неизбежно столкнетесь с необходимостью перетасовки колоды карт. Обычно, эта операция выполняется перед каждой сдачей карт, то есть, возможно, десятки раз за игру (в зависимости от правил конкретной игры). Поэтому качество выполнения данной операции может существенно сказаться на результатах игры.

На первый взгляд, в решении этой задачи нет ничего сложного. Нужно просто поменять местами карты в колоде так, чтобы они располагались случайным образом. Но что означает «случайным образом»? Ответ простой: «Во взаимном расположении карт не должно быть никаких закономерностей». Но ведь компьютер выполняет только то, что написано в программе. Команды из серии: «Возьми то, не знаю что», тут не проходят. Поэтому в первую очередь нам нужен источник случайных чисел.

И вот тут возникает проблема. На сегодняшний день не существует источника по-настоящему случайных чисел. Но зато есть огромное количество алгоритмов, которые позволяют получать, так называемые, псевдослучайные числа. Практически каждый язык программирования имеет встроенные функции для генерирования псевдослучайных последовательностей чисел. Разница между случайными и псевдослучайными числами в том, что последние получены с использованием какого-то алгоритма. А это означает наличие некоторой закономерности в появлении таких чисел.

Я не буду анализировать особенности этих алгоритмов, это тема не статьи, а книги (скорее нескольких). Те, кому интересно, могут посмотреть литературу по вычислительной математике или теории чисел.

В этой статье я расскажу о возможностях, которые нам предоставляет стандартная библиотека языка Java. Есть два варианта. Первый – использовать метод random() класса java.lang.Math.. Второй – воспользоваться одним из методов класса java.util.Random.

Мы будем использовать второй вариант, т.к. он обеспечивает более широкую функциональность.

В первую очередь, я хочу показать, что этот класс генерирует псевдослучайные числа. Напишем простенькую программку:

import java.util.Random;public class Main {
public Main() {
    }
public static void main(String[] args) {
        //создаем новый генератор псевдослучайных чисел, и задаем
        //начальное значение для алгоритма генерации чисел
        Random generator = new Random(20);
        //выводим десять случайных чисел
        for(int i = 0; i < 10; i++) {
            if(i == 9) {
                System.out.println(generator.nextInt(100));
            }
            else {
                System.out.print(generator.nextInt(100) + "; ");
            }
        }
    }
}

Тут все предельно просто. Программа генерирует 10 случайных чисел, и выводит их в одну строку. Если мы запустим программу 3 раза подряд, то получим три строки с числами:
53; 36; 1; 61; 5; 95; 33; 55; 93; 88
53; 36; 1; 61; 5; 95; 33; 55; 93; 88
53; 36; 1; 61; 5; 95; 33; 55; 93; 88
Как видите, все строки одинаковые. Это происходит из-за того, что аргументом в конструкторе класса Random у нас является одно и то же число (20). Кстати, если использовать конструктор без аргументов, то начальное значение будет выбрано по специальному алгоритму, и генерируемые числа будут разными.

Но я не зря использовал именно этот конструктор. Дело в том, что в качестве начального значения для генератора случайных чисел можно использовать текущее значение системного времени. Действительно, нельзя точно предугадать в какой момент времени пользователь запустит программу, миллисекундой раньше, миллисекундой позже…

Создать генератор случайных чисел, с системным временем в качестве базового числа, можно так:
Random generator = new Random(new Date().getTime());

Или, если у вас уже есть объект типа Random:
generator.setSeed(new Date().getTime());

Итак, с созданием случайных чисел разобрались. Переходим непосредственно к алгоритму перетасовки карт.
Прежде всего, просмотрите его исходный код, а затем я объясню, как это все работает.
public static void reshuffle(int[] pack) {
    if(pack != null) {
        int length = pack.length;
        //создаем генератор случайных чисел, в качестве начального
        //значения передаем системное время
        Random generator = new Random(new Date().getTime());
        //тосуем колоду карт
        //перебираем все карты колоды
        for(int i = 0; i < length; i++) {
            //генерируем случайное число, в диапазоне от нуля до
            //конца колоды
            int newPos = generator.nextInt(length);
            //меняем местами текущую карту с картой, которая находится
            //в pack[newPos]
            int curCard = pack[i];
            pack[i] = pack[newPos];
            pack[newPos] = curCard;
            //для увеличения эффекта "случайности" возникновения чисел,
            //в течении перетасовки колоды, четыре раза устанавливаем
            //новое начальное значение генератора случайных чисел
            if(i%(length/4) == 0) {
                //генерируем случайный интервал времени (мс)
                int pause = generator.nextInt(20);
                try {
                    //останавливаем работу программы на полученный
                    //интервал времени (максимально возможная задержка
                    //восемдесят миллисекунд)
                    Thread.currentThread().sleep(pause);
                }
                catch (InterruptedException ex) {}
                //уставливаем новое начальное значение генератора
                generator.setSeed(new Date().getTime());
            }
        }
    }
}

За основу я взял давно известный алгоритм, но для увеличения степени “случайности” возникновения чисел, ввел несколько изменений.

Допустим, у нас есть колода из 36 карт. Для её хранения мы используем массив из 36 элементов, каждый из которых может принимать значения от 0 до 35.

Перетасовка выполняется следующим образом. Мы последовательно перебираем все ячейки массива с картами. Для каждой ячейки мы генерируем случайное число (newPos) в диапазоне от 0 до 35. Это число является новым положением карты в массиве. Т.е. мы меняем местами текущую карту с картой, которая лежит в ячейке с индексом newPos.

Теперь обратите внимание на строки начиная с if(i%(length/4) == 0) {. Этот блок кода будет выполняться четыре раза в течение работы метода. Принцип работы следующий. В первую очередь мы получаем случайное число в диапазоне от 0 до 20. Почему выбран именно этот диапазон, я объясню чуть позже. Это число задает время, на которое программа приостанавливает свою работу.

Остановка программы выполняем с помощью метода sleep(). После этого, мы опять устанавливаем текущее время в качестве нового базового значения для генератора случайных чисел.

Теперь разберемся, что все это нам дает. В первую очередь увеличивается время выполнения перетасовки. Это, конечно, не очень хорошо, но давайте подумаем. Максимально возможная задержка составляет 80 мс. Данный алгоритм предназначен для использования в карточных играх, в которых, при перетасовке карт, игроку обычно показывают какую-нибудь анимацию (это увеличивает реалистичность игры). Длительность такой анимации обычно около секунды или больше (игрок должен хоть что-то рассмотреть:-)). Т.е., за время этой анимации, можно будет раз десять перетасовать колоду.

А теперь посмотрим на сильные стороны этого алгоритма. Мы четыре раза устанавливаем новое базовое число. Предсказать значение этого числа практически невозможно, и не только потому, что длительность паузы мы выбираем случайным образом. Любая современная операционная система вносит дополнительный эффект случайности в работу алгоритма. Дело в том, что в системе выполняется одновременно несколько десятков процессов (программ). Но один процессор (не многоядерный) может выполнять одновременно только одну программу. Поэтому для создания эффекта многозадачности используется специальная программа – планировщик, которая переключает процессы. Сначала выполняется несколько команд из одной программы, потом – несколько из другой, и так далее. Порядок переключения программ зависит от многих причин. Это и приоритеты процессов, и тактовая частота процессора, и версия операционной системы, и многое другое.

Таким образом, существует высокая вероятность того, что выполнение нашего метода перетасовки будет прервано планировщиком (и не один раз). Системное время, естественно, не зависит от порядка работы нашей программы, и значения, которые возвращает метод getTime() предсказать практически невозможно. А именно этого мы и добиваемся.

Для тестирования работы алгоритма я написал небольшую программу. В неё входят 3 файла с исходными кодами. Reshuffler.java – имеет один статический метод, который и выполняет перетасовку карт. CardsPack.java – этот файл, содержит класс, который используется для создания колоды карт. Он содержит два метода: getPackOfCards() – возвращает массив с номерами карт;
toString() – возвращает строку с названиями карт в колоде.
Оба эти метода находятся в пакете cards.tools.
Main.java – содержит класс с функцией main, которая выполняет следующие операции:

создает новую колоду;
выводит её содержимое;
перетасовывает колоду;
и опять выводит её содержимое.

Как видите, у нас все получилось.

Добавлено: 17 Апреля 2018 18:29:15 Добавил: Андрей Ковальчук

Создание приложения для поиска файлов на Java

Сегодня любая операционная система имеет встроенные средства для поиска файлов. Во многих случаях что-то подобное хотелось бы использовать в своих программах. В этой статье я покажу, как создать небольшой Java класс, который можно будет использовать в любой программе для поиска файлов.

Создание класса для поиска файлов
Сегодня любая операционная система имеет встроенные средства для поиска файлов. Во многих случаях что-то подобное хотелось бы использовать в своих программах. В этой статье я покажу, как создать небольшой Java класс, который можно будет использовать в любой программе для поиска файлов.

В первую очередь, давайте определимся, что именно должен делать наш класс. Для большинства случаев, я думаю, будет достаточно таких возможностей:

поиск заданных файлов и папок в начальной папке и всех её вложенных папках;
общая статистика поиска (количество найденных файлов и папок, общий размер файлов);
использование регулярных выражений в качестве шаблонов для имен найденных файлов и папок (выборочный поиск);
поиск отдельно файлов, и отдельно папок.
Теперь посмотрим, какие стандартные библиотеки из JDK (java development kit) нам понадобятся. В состав пакета java.io входит класс File, предназначенный для работы с файлами и папками. Он имеет методы для определения содержимого папки. Так что, нам остаётся добавить просмотр вложенных папок и поддержку регулярных выражений.

Несколько слов о том, что такое регулярные выражения. Это текстовые строки, составленные по определённым правилам, которые можно использовать в качестве шаблонов. Библиотека Java содержит пакет java.util.regex, предназначенный для работы с регулярными выражениями. Подробнее почитать о правилах составления и возможностях регулярных выражений можно в статье: Анализ данных с помощью регулярных выражений или быстрый способ проверки введённых данных.

Таким образом, наш класс, назовём его FileFinder, должен иметь такой набор методов.

Для поиска файлов и папок:
public List findAll(String startPath)
public List findAll(String startPath, String mask)

Для поиска только файлов:
public List findFiles(String startPath)
public List findFiles(String startPath, String mask)
Для поиска только папок:
public List findDirectories(String startPath)
public List findDirectories(String startPath, String mask)
Каждый найденный объект (файл или папка) включается в список результатов только в том случае, если он соответствует регулярному выражению, заданному в параметре mask. Все методы возвращают результат в виде списка объектов типа File.

С помощью методов:
public long getDirectorySize()
public long getFilesNumber()
public long getDirectoriesNumber()
определяем количество найденных файлов и папок, и размер файлов.

Теперь, рассмотрим самую интересную часть. Поиск файлов. Он выполняется с помощью двух методов. Первый,
private List find(String startPath, String mask, int objectType)

выполняет начальную подготовку к поиску: сброс счётчиков, проверку допустимости параметров, компиляцию регулярного выражения и т.п.. Второй метод,
private void search(File topDirectory, List res, int objectType)

вызывается только из метода find(...), он и выполняет поиск. В качестве параметров, методу search(...) передаются: имя папки, указатель на список для хранения найденных объектов, и тип нужного объекта (файлы, папки, всё подряд). С помощью метода listFiles() класса File определяем список файлов и папок в текущей папке (параметр topDirectory), а затем, для каждой найденной папки снова вызываем метод search(...), но в параметре topDirectory передаём найденную папку. Такой способ вызова методов называется рекурсией. Т.е. метод search(...) будет вызывать сам себя до тех пор, пока не пройдёт все вложенные папки. Каждый найденный объект (папка или файл) проверяется на соответствие регулярному выражению (если оно задано) с помощью метода accept(), и, если проверка прошла успешно, добавляется в список результатов.

Теперь посмотрим на весь класс целиком.

package searchtools;
 
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
/**
 * Этот класс предназначен для поиска файлов
 *
 * @author Стаценко Владимир
 * http://www.vova-prog.narod.ru
 */
public class FileFinder {
 
    //классы для работы с регулярными выражениями
    private Pattern p = null;
    private Matcher m = null;
 
    //общий размер найденных файлов
    private long totalLength = 0;
    //общее количество найденных файлов
    private long filesNumber = 0;
    //общее количество просмотренных директорий
    private long directoriesNumber = 0;
 
    //константы для определения объектов, которые нужно найти
    private final int FILES = 0;
    private final int DIRECTORIES = 1;
    private final int ALL = 2;
 
    /** Создает новые экземпляры FileFinder */
    public FileFinder() {
    }
 
    /**
     * Этот метод выполняет поиск всех объектов (файлов и директорий),
     * начиная с заданной директории (startPath)
     * @param startPath Начальная директория поиска
     * @return Список (List) найденных объектов
     * @throws java.lang.Exception если возникли ошибки в процессе поиска
     */
    public List findAll(String startPath) throws Exception {
        return find(startPath, "", ALL);
    }
 
    /**
     * Этот метод выполняет поиск объектов (файлов и директорий),
     * которые соответствуют заданному регулярному выражению (mask),
     * начиная с заданной директории (startPath)
     * @param startPath Начальная директория поиска
     * @param mask регулярное выражение, которому должны соответствовать
     * имена найденный объектов
     * @throws java.lang.Exception если возникли ошибки в процессе поиска
     * @return Список (List) найденных объектов
     */
    public List findAll(String startPath, String mask)
            throws Exception {
        return find(startPath, mask, ALL);
    }
 
    /**
     * Этот метод выполняет поиск всех файлов,
     * начиная с заданной директории (startPath)
     * @param startPath Начальная директория поиска
     * @return Список (List) найденных объектов
     * @throws java.lang.Exception если возникли ошибки в процессе поиска
     */
    public List findFiles(String startPath)
            throws Exception {
        return find(startPath, "", FILES);
    }
 
    /**
     * Этот метод выполняет поиск файлов,
     * которые соответствуют заданному регулярному выражению (mask),
     * начиная с заданной директории (startPath)
     * @param startPath Начальная директория поиска
     * @param mask регулярное выражение, которому должны соответствовать
     * имена найденный объектов
     * @throws java.lang.Exception если возникли ошибки в процессе поиска
     * @return Список (List) найденных объектов
     */
    public List findFiles(String startPath, String mask)
            throws Exception {
        return find(startPath, mask, FILES);
    }
 
    /**
     * Этот метод выполняет поиск всех директорий (папок),
     * начиная с заданной директории (startPath)
     * @param startPath Начальная директория поиска
     * @return Список (List) найденных объектов
     * @throws java.lang.Exception если возникли ошибки в процессе поиска
     */
    public List findDirectories(String startPath)
            throws Exception {
        return find(startPath, "", DIRECTORIES);
    }
 
    /**
     * Этот метод выполняет поиск директорий (папок),
     * которые соответствуют заданному регулярному выражению (mask),
     * начиная с заданной директории (startPath)
     * @param startPath Начальная директория поиска
     * @param mask регулярное выражение, которому должны соответствовать
     * имена найденный объектов
     * @throws java.lang.Exception если возникли ошибки в процессе поиска
     * @return Список (List) найденных объектов
     */
    public List findDirectories(String startPath, String mask)
            throws Exception {
        return find(startPath, mask, DIRECTORIES);
    }
 
    /**
     * Возвращает суммарный размер найденных файлов
     * @return размер найденных файлов (байт)
     */
    public long getDirectorySize() {
        return totalLength;
    }
 
    /**
     * Возвращает общее количество найденных файлов
     * @return количество найденных файлов
     */
    public long getFilesNumber() {
        return filesNumber;
    }
 
    /**
     * Возвращает общее количество найденных директорий (папок)
     * @return количество найденных директорий (папок)
     */
    public long getDirectoriesNumber() {
        return directoriesNumber;
    }
 
    /*
    Проверяет, соответствует ли имя файла заданному
    регулярному выражению. Возвращает true, если найденный
    объект соответствует регулярному выражению, false - в
    противном случае.
    */
    private boolean accept(String name) {
        //если регулярное выражение не задано...
        if(p == null) {
            //...значит объект подходит
            return true;
        }
        //создаем Matcher
        m = p.matcher(name);
        //выполняем проверку
        if(m.matches()) {
            return true;
        }
        else {
            return false;
        }
    }
 
    /*
    Этот метод выполняет начальные установки поиска.
    Затем вызывает метод search для выполнения поиска.
    */
    private List find(String startPath, String mask, int objectType)
            throws Exception {
        //проверка параметров
        if(startPath == null || mask == null) {
            throw new Exception("Ошибка: не заданы параметры поиска");
        }
        File topDirectory = new File(startPath);
        if(!topDirectory.exists()) {
            throw new Exception("Ошибка: указанный путь не существует");
        }
        //если задано регулярное выражение, создаем Pattern
        if(!mask.equals("")) {
            p = Pattern.compile(mask,
                    Pattern.CASE_INSENSITIVE | Pattern.UNIcomment_CASE);
        }
        //обнуляем все счетчики
        filesNumber = 0;
        directoriesNumber = 0;
        totalLength = 0;
        //создаем список результатов
        ArrayList res = new ArrayList(100);
 
        //выполняем поиск
        search(topDirectory, res, objectType);
 
        //присваиваем null шаблону, т.к. при следующем вызове find...
        //регулярное выражение может быть не задано
        p = null;
        //возвращаем результат
        return res;
    }
 
    /*
    Этот метод выполняет поиск объектов заданного типа.
    Если, в процессе поиска, встречает вложенную директорию
    (папку), то рекурсивно вызывает сам себя.
    Результаты поиска сохраняются в параметре res.
    Текущая директория - topDirectory.
    Тип объекта (файл или директория) - objectType.
    */
    private void search(File topDirectory, List res, int objectType) {
        //получаем список всех объектов в текущей директории
        File[] list = topDirectory.listFiles();
        //просматриваем все объекты по-очереди
        for(int i = 0; i < list.length; i++) {
            //если это директория (папка)...
            if(list[i].isDirectory()) {
                //...выполняем проверку на соответствие типу объекта
                // и регулярному выражению...
                if(objectType != FILES && accept(list[i].getName())) {
                    //...добавляем текущий объект в список результатов,
                    //и обновляем значения счетчиков
                    directoriesNumber++;
                    res.add(list[i]);
                }
                //выполняем поиск во вложенных директориях
                search(list[i], res, objectType);
            }
            //если это файл
            else {
                //...выполняем проверку на соответствие типу объекта
                // и регулярному выражению...
                if(objectType != DIRECTORIES && accept(list[i].getName())) {
                    //...добавляем текущий объект в список результатов,
                    //и обновляем значения счетчиков
                    filesNumber++;
                    totalLength += list[i].length();
                    res.add(list[i]);
                }
            }
        }
    }
}

Как видите, ничего сложного. Большая часть – это комментарии.

Добавлено: 17 Апреля 2018 17:23:10 Добавил: Андрей Ковальчук

Программирование на Java. Сортировка списка файлов.

Вступление
Прежде всего, нам нужно определиться, что мы будем сортировать, и как. Наш класс для поиска файлов имеет несколько методов find(...), которые возвращают список файлов (объект типа List) с объектами типа File. Таким образом, мы можем получить любую информацию о найденных файлах (имя, размер, размещение и т.д.).

Теперь решим, каким образом нам нужно отсортировать результаты поиска. Наиболее часто требуется сортировка по имени, типу, размеру и дате создания файла.

В этой статье мы напишем методы, необходимые для сортировки по имени файла (это одна из наиболее сложных сортировок). Итак, нам нужно, отсортировать все найденные файлы и папки в следующем порядке:

первыми идут файлы с минимальной глубиной вложения (т.е. те, которые находятся ближе к начальной папке поиска);
файлы, которые находятся внутри одной папки, должны быть отсортированы в алфавитном порядке (нужно обеспечить правильную обработку не латинских символов).
Результаты сортировки должны быть возвращены в виде списка (List) с объектами типа File, т.е. мы меняем только порядок следования элементов и ничего более.

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

Теперь, когда задача ясна, посмотрим, как мы можем её решить. В первую очередь, нам нужен какой-нибудь алгоритм сортировки. С этим проблем нет. На сегодняшний день, разработано множество таких алгоритмов. Парочку этих алгоритмов можно найти практически в любом учебнике по программированию. Так что, если хотите, берите книжку…, или можно воспользоваться стандартной библиотекой Java, конкретнее, методом sort(List list, Comparator c) класса Collections из пакета java.util.

Этот метод выполняет сортировку списка объектов, который передается ему в первом параметре (list). Тут у вас может возникнуть вполне закономерный вопрос: «А как именно он будет сортировать файлы». Ответ простой: «Так, как мы ему расскажем»:-). Дело в том, что любой алгоритм сортировки принимает решения о порядке следования объектов на основании результатов их сравнения, т.е. при сортировке мы всегда должны иметь возможность получить результат сравнения двух любых объектов. Например, если бы мы сортировали список с объектами стандартного типа, например, int, то метод sort упорядочил бы их в порядке возрастания без дополнительных усилий с нашей стороны.

Но о том, как мы хотим отсортировать наш список, методу sort ничего не известно. Поэтому мы должны написать метод, который выполняет сравнение двух объектов из нашего списка. Этот метод (int compare(Object o1, Object o2)) определён в интерфейсе Comparator. Он должен возвращать «1», если первый аргумент (o1) больше второго (o2), «0» — если аргументы равны, и «-1» — если второй объект больше. Как вы, наверное, уже поняли, указатель на класс, который содержит наш метод сравнения (compare(...)) передаётся методу sort во втором параметре. Метод sort будет сортировать наши объекты в порядке возрастания, сравнивая их при помощи нашего метода compare(...). Изменяя метод compare(...) мы можем задать любой порядок сортировки.

Теперь посмотрим как будет выглядеть наш класс сортировки файлов (FileSorter)

package searchtools;
 
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.File;
 
/**
 * Этот класс предназначен для сортировки списка файлов
 *
 * @author Стаценко Владимир
 * http://www.vova-prog.narod.ru
 */
public class FileSorter implements Comparator {
 
    Pattern p = null;
    Collator collator = null;
 
    /** Создает новые экземпляры FileSorter */
    public FileSorter() {
        .
        .
        .
    }
 
    /* Этот метод выполняет сравнение имен двух файлов.
     * Возвращает:
     *     1 если первый параметр (о1) больше второго (о2),
     *    -1 если первый параметр (о1) меньше второго (о2),
     *     0 если они равны.
     * Имя первого файла считается больше второго имени, если
     * первый файл находится ближе к корню дерева папок.
     * Если файлы находятся в одной папке, то больше то имя,
     * которое идет первым по алфавиту.
     */
    public int compare(Object o1, Object o2) {
        .
        .
        .
    }
 
    public List sort(List fileList) {
        ArrayList res = new ArrayList(fileList.size());
        res.addAll(fileList);
        Collections.sort(res, this);
        return res;
    }
}

Как видите, наш класс реализует интерфейс Comparator, и, соответственно, методу sort мы передаём указатель this.

Для того, чтобы наш класс заработал, нам осталось написать метод compare.

Тут все просто. В первую очередь, проверяем равенство объектов (если имена файлов одинаковы, то и файлы равны). Если файлы разные, определяем их глубину вложения. Как вы помните, сначала должны идти файлы с меньшей глубиной вложения. Наконец, если файлы находятся на одной глубине, сравниваем сами имена файлов.

Для определения глубины вложения файлов нам нужно узнать количество символов-разделителей в полном имени файла. Обратите внимание, определять символ-разделитель нужно с помощью переменной File.separator, т.к. он зависит от операционной системы.

Для подсчёта символов-разделителей можно использовать цикл, но есть и более удобный метод, основанный на использовании регулярных выражений (почитать о них вы можете в статье «Анализ данных с помощью регулярных выражений или быстрый способ проверки введенных данных» или в Java Tutorial).

Для поддержки различных кодировок очень удобно использовать классы Collator и Locale из пакета java.util. Метод compare класса Collator позволяет выполнить сортировку строк в соответствии с алфавитом языка, который установлен в настройках системы.

Теперь посмотрим на весь класс целиком.
/*
 * FileSorter.java
 *
*/
 
package searchtools;
 
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.File;
 
/**
 * Этот класс предназначен для сортировки списка файлов
 *
 * @author Стаценко Владимир
 * http://www.vova-prog.narod.ru
 */
public class FileSorter implements Comparator {
 
    //класс для работы с регулярными выражениями
    Pattern p = null;
    //класс для работы со строками на разных языках
    Collator collator = null;
 
    /** Создает новые экземпляры FileSorter */
    public FileSorter() {
        //определяем системный символ разделитель и создаем
        //шаблон на его основе
        String separator = File.separator;
        if(separator.equals("\\")) {
            separator = "\\";
        }
        //создаем шаблон на основе символа-разделителя
        p = Pattern.compile(separator,
                Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
        //получаем системные настройки (язык и страну)
        String country = System.getProperty("user.country");
        String language = System.getProperty("user.language");
        //создаем экземпляр класса для сравнения строк на
        //основе региональных настроек
        collator = Collator.getInstance(new Locale(country, language));
    }
 
    /**
     * Этот метод выполняет сравнение имен двух файлов.
     * Возвращает:
     *     1 если первый параметр (о1) больше второго (о2),
     *    -1 если первый параметр (о1) меньше второго (о2),
     *     0 если они равны.
     * Имя первого файла считается больше второго имени, если
     * первый файл находится ближе к корню дерева папок.
     * Если файлы находятся в одной папке, то больше то имя,
     * которое идет первым по алфавиту.
     * @param o1 объект типа File
     * @param o2 объект типа File
     * @return результат сравнения
     */
    public int compare(Object o1, Object o2) {
        //если объекты не равны null и имеют тип File
        if(o1 != null && o2 != null &&
                o1 instanceof File && o2 instanceof File) {
            //приводим к типу File
            File f1 = (File)o1;
            File f2 = (File)o2;
            //получаем полный путь к имени файла
            String fullPath1 = f1.getAbsolutePath();
            String fullPath2 = f2.getAbsolutePath();
            //проверяем равенство имен
            if(fullPath1.equals(fullPath2)) {
                //возвращаем 0, т.к. имена одинаковы
                return 0;
            }
            //определяем глубину размещения файла в дереве папок
            //для этого разбиваем полный путь к файлу на
            //лексемы, и определяем их количество
            String[] res1 = p.split(fullPath1);
            String[] res2 = p.split(fullPath2);
            if(res1.length > res2.length) {
                //возвращаем 1, если глубина вложения первого
                //файла больше глубины вложения второго
                return 1;
            }
            if(res1.length < res2.length) {
                //возвращаем "-1" в противном случае
                return -1;
            }
            if(res1.length == res2.length) {
                //если файлы находятся на одинаковой глубине,
                //сортируем их в соответствии с алфавитом
                return collator.compare(fullPath1, fullPath2);
            }
        }
        //здесь мы возвращаем 0, т.к. сравнение объектов
        //выполнить невозможно (т.е. считаем, что объекты
        //одинаковые, во всяком случае, сортировать их
        //нет смысла)
        return 0;
    }
 
    /**
     * Этот метод выполняет сортировку списка файлов
     * @param fileList не отсортированный список файлов
     * @return отсортированный список файлов
     */
    public List sort(List fileList) {
        //создаем список для результатов (такого же размера
        //как и исходный список)
        ArrayList res = new ArrayList(fileList.size());
        //копируем список
        res.addAll(fileList);
        //выполняем сортировку
        Collections.sort(res, this);
        //возвращаем результат
        return res;
    }
}

Как видите, значительная часть работы выполнена с помощью стандартных библиотек Java. Так что, можете быть уверены, время, потраченное на их изучение, быстро окупиться.

Если вы захотите изменить способ сортировки, например, сортировать файлы по их размеру, то просто измените метод compare.

Обеспечить поддержку нескольких видов сортировки немного сложнее. Я могу посоветовать использовать следующий метод.

Добавляем несколько констант и одну переменную.
private final int SORT_BY_NAME = 1; //сортировка по имени файла
private final int SORT_BY_SIZE = 2; //сортировка по размеру файла
 
private int sortType = 1; //в этой переменной сохраняем текущий тип сортировки

Во всех методах задаём тип сортировки:
public List sortByName(List fileList) {
    sortType = SORT_BY_NAME;
    ...
}
public List sortBySize(List fileList) {
    sortType = SORT_BY_SIZE;
    ...
}

А в методе compare добавляем оператор switch и, конечно, все нужные алгоритмы сравнения.
switch (sortType) {
    case SORT_BY_NAME:
    //сравнение объектов по их имени
    case SORT_BY_SIZE:
    //сравнение объектов по их размеру
}

Вот и все. Теперь мы можем не только искать файлы, но и выводить результаты поиска в удобном нам виде.

Добавлено: 17 Апреля 2018 17:20:16 Добавил: Андрей Ковальчук

Метод рекурсивного спуска. Java Math Parser

Класс предназначен для интерпретирования арифметических выражений методом рекурсивного спуска.
Поддерживаемые операции:

Побитовое И            &
Побитовое ИЛИ          |
Побитовое НЕ           ~
Сложение               +
Вычитание              -
Умножение              *
Деление                /
Остаток от деления     %
Целочисленное деление  \
Возведение в степень   ^


Поддерживаемые функции:
sin(x)   - синус
cos(x)   - косинус
tan(x)   - тангенс
ctg(x)   - котангенс
sinh(x)  - гиперболический синус
cosh(x)  - гиперболический косинус
tanh(x)  - гиперболический тангенс
sec(x)   - секанс
cosec(x) - косеканс
abs(x)   - модуль числа
sqrt(x)  - квадратный корень
ln(x)    - натуральный логарифм
lg(x)    - десятичный логарифм
log(x,y) - логарифм x по основанию y
xor(x,y) - побитовое исключающее ИЛИ




MathParser.java

import java.util.HashMap;

/**
 *
 * Класс модифицирован автором ShamaN.
 * Метод рекурсивного спуска для интерпретирования математических выражений.
 * Поддерживаются тригонометрические функции с одним/двумя параметрами.
 * @author shurik
 * @version 1.1
 */
public class MathParser {

    private static HashMap<String, Double> var;

    public MathParser() {
            var = new HashMap<>();
            setVariable("pi",Math.PI);
            setVariable("e",Math.E);
    }

    
    /**
     * Вставить новую переменную
     * @param varName имя переменной
     * @param varValue значение переменной
     */
    public static void setVariable(String varName, Double varValue) {
            var.put(varName, varValue);
    }
    
    /**
     * Заменяет значение существующей переменной
     * @param varName имя переменной
     * @param varValue значение переменной
     */
    public void replaceVariable(String varName, Double varValue) {       
            var.replace(varName, varValue);
    }

    /**
     * 
     * @param varName
     * @return Возвращает значение переменной varName
     * @throws Exception ругаемся на отсутствие переменной
     */
    public Double getVariable(String varName) throws Exception {
        if(!var.containsKey(varName)) {
            throw new Exception("Error:Try get unexists "+
                                               "variable '"+varName+"'" );
        }
        return var.get(varName);
    }

    /**
     * Парсим математическое выражение
     * @param s математическое выражение
     * @return результат
     * @throws Exception 
     */
    public double Parse(String s) throws Exception {
        if(s.isEmpty())
            throw new Exception("Empty expression");
        Result result = binaryFunc(s);
        if (!result.rest.isEmpty())
            throw new Exception("Error: can't full parse \n "+
                                              "rest: " + result.rest);
        return result.acc;
    }
    

    private Result binaryFunc(String s) throws Exception{
        
        Result cur;
        
        if(s.charAt(0) == '~'){
            cur = plusMinus(s.substring(1));
            
            cur.acc = ~ (int)cur.acc;
            return cur;
        }
        
        cur = plusMinus(s);
        double acc = cur.acc;
        
        cur.rest = skipSpaces(cur.rest);
        
        while(cur.rest.length() > 0){
            if(!(cur.rest.charAt(0) == '&' ||
                 cur.rest.charAt(0) == '|' || 
                 cur.rest.charAt(0) == '~')) break;
            
            char sign = cur.rest.charAt(0);
            String next = cur.rest.substring(1);
            cur = plusMinus(next);
            

            if(sign == '&')
                    acc = (int)acc & (int)cur.acc;
            else
                    acc = (int)acc | (int)cur.acc;
        }
        
        return new Result(acc,cur.rest);
        
    }

    private Result plusMinus(String s) throws Exception {

        Result cur = mulDiv(s);
        double acc = cur.acc;
        
        cur.rest = skipSpaces(cur.rest);

        while(cur.rest.length() > 0){
            if(!(cur.rest.charAt(0) == '+' || cur.rest.charAt(0) == '-'))
                    break;
            
            char sign = cur.rest.charAt(0);
            String next = cur.rest.substring(1);

            cur = binaryFunc(next);

            if(sign == '+')
                    acc+=cur.acc;
            else
                    acc-=cur.acc;
        }
        return new Result(acc,cur.rest);
    }

    


    private Result mulDiv(String s) throws Exception{
        Result cur = exponentiation(s);
        double acc = cur.acc;

        cur.rest = skipSpaces(cur.rest);
        
        
        while(true){
            if(cur.rest.length() == 0)
                    return cur;
                
            char sign = cur.rest.charAt(0);
            if(sign != '*' && sign != '/' && sign != '%' && sign != '\\') 
                return cur;

            String next = cur.rest.substring(1);
            Result right = exponentiation(next);
            switch(sign){
                case '*': 
                    acc*=right.acc; 
                    break;
                case '/': 
                    acc/=right.acc; 
                    break;
                case '%': // остаток от деления
                    acc%=right.acc; 
                    break; 
                case '\\': // целочисленное деление
                    acc = (acc - acc % right.acc)/right.acc; 
                    break;
            }
            cur = new Result(acc,right.rest);
        }
    }


    private Result exponentiation(String s) throws Exception{
        Result cur = bracket(s);
        double acc = cur.acc;
        
        cur.rest = skipSpaces(cur.rest);

        while(true){
            
            if(cur.rest.length() == 0) return cur;
            if(cur.rest.charAt(0) !='^') break;

            String next = cur.rest.substring(1);
            cur = bracket(next);
            cur.acc = Math.pow(acc,cur.acc);
        } 
        return cur;
    }


    private Result bracket(String s) throws Exception{
        
        s = skipSpaces(s);
        char zeroChar = s.charAt(0);
        if (zeroChar == '(') {
            Result r = binaryFunc(s.substring(1));
            if (!r.rest.isEmpty()) {
                r.rest = r.rest.substring(1);
            } else {
                throw new Exception("Expected closing bracket");
            }
            return r;
        }
        return functionVariable(s);
    }

    private Result functionVariable(String s) throws Exception{
        String f = "";
        int i = 0;
        // ищем название функции или переменной
        // имя обязательно должна начинаться с буквы
        while (i < s.length() && (Character.isLetter(s.charAt(i)) || 
              ( Character.isDigit(s.charAt(i)) && i > 0 ) )) {
            f += s.charAt(i);
            i++;
        }
        if (!f.isEmpty()) { // если что-нибудь нашли
            if ( s.length() > i && s.charAt( i ) == '(') { 
            // и следующий символ скобка значит - это функция
                Result r = binaryFunc(s.substring(f.length()+1));
                
                if(!r.rest.isEmpty() && r.rest.charAt(0) == ','){
                // если функция с двумя параметрами
                    double acc = r.acc;
                    Result r2 = binaryFunc(r.rest.substring(1));
                    
                    r2 = closeBracket(r2);
                    return processFunction(f, acc,r2);

                } else {
                    r = closeBracket(r);
                    return processFunction(f, r);
                }
            } else { // иначе - это переменная
                return new Result(getVariable(f), s.substring(f.length()));
            }
        }
        return num(s);
    }
    private Result closeBracket(Result r) throws Exception{
        if(!r.rest.isEmpty() && r.rest.charAt(0) ==')'){
            r.rest = r.rest.substring(1);
        } else
            throw new Exception("Expected closing bracket");
        return r;
    }

    private Result num(String s) throws Exception{
        int i = 0;
        int dot_cnt = 0;
        boolean negative = false;
        // число также может начинаться с минуса
        if( s.charAt(0) == '-' ){
            negative = true;
            s = s.substring( 1 );
        }
        // разрешаем только цифры и точку
        while (i < s.length() && 
              (Character.isDigit(s.charAt(i)) || s.charAt(i) == '.')) {
            // но также проверяем, что в числе может быть только одна точка!
            if (s.charAt(i) == '.' && ++dot_cnt > 1) {
                throw new Exception("not valid number '" 
                                    + s.substring(0, i + 1) + "'");
            }
            i++;
        }
        if( i == 0 ){ // что-либо похожее на число мы не нашли
            throw new Exception("can't get valid number in '" + s + "'" );
        }

        double dPart = Double.parseDouble(s.substring(0, i));
        if(negative) dPart = -dPart;
        String restPart = s.substring(i);

        return new Result(dPart, restPart);
    }

    private Result processFunction(String func, Result r) throws Exception{
        switch (func) {
            case "sin":
                return new Result(Math.sin(r.acc), r.rest);
            case "sinh": // гиперболический синус
                return new Result(Math.sinh(r.acc), r.rest);
            case "cos": 
                return new Result(Math.cos(r.acc), r.rest);
            case "cosh": // гиперболический косинус
                return new Result(Math.cosh(r.acc), r.rest);
            case "tan":
                return new Result(Math.tan(r.acc), r.rest);
            case "tanh": // гиперболический тангенс
                return new Result(Math.tanh(r.acc), r.rest);
            case "ctg":
                return new Result(1/Math.tan(r.acc), r.rest);
            case "sec": // секанс
                return new Result(1/Math.cos(r.acc), r.rest);
            case "cosec": // косеканс
                return new Result(1/Math.sin(r.acc), r.rest);   
            case "abs":
                return new Result(Math.abs(r.acc), r.rest);
            case "ln":
                return new Result(Math.log(r.acc), r.rest);
            case "lg": // десятичный логарифм
                return new Result(Math.log10(r.acc), r.rest);
            case "sqrt":
                return new Result(Math.sqrt(r.acc), r.rest);
            default:
                throw new Exception("function '" + func + "' is not       
                                                              defined");    
        }
    }
    private Result processFunction(String func,
                                   double acc, 
                                   Result r) throws Exception{
        switch(func){
            case "log": // логарифм x по основанию y
                return new Result(Math.log(acc)/Math.log(r.acc),
                                  r.rest);
            case "xor": // исключающее или 
                return new Result((int)acc ^ (int)r.acc,r.rest);
            default:
                throw new Exception("function '" + func + 
                                    "' is not defined");
        }
    }
    
    private String skipSpaces(String s){
        return s.trim();
    }
    

    private class Result {
        public double acc; // Аккумулятор
        public String rest; // остаток строки, которую мы еще не обработали
        public Result(double v, String r) {
            this.acc = v;
            this.rest = r;
        }
    }
}


Пример использования:
Main.java
public class Main{
    public static void main(String[] args){
        MathParser parser = new MathParser();
        String[] expressions = {"2+4*3-8^3",
                                "4*sin(0.5)+2*cos(2*0.5)",
                                "log(64,2)*lg(100)",
                                "xor(65,83)",
                                "63 & 95",
                                "2*(5-7",
                                "x*5",
                                "",
                                "2*pi*50",
                                "e^2+1",
                                "6.78.-7"};
        
        for(String expression:expressions){
            System.out.print(expression+"  ");
            try{
                System.out.print(parser.Parse(expression)+"\n");
            } catch(Exception e){
                System.out.println(e.getMessage());
            }
        }  
    }
}


Результат тестирования:
2+4*3-8^3 = -498.0
4*sin(0.5)+2*cos(2*0.5) = 2.9983067661530916
log(64,2)*lg(100) = 12.0
xor(65,83) = 18.0
63 & 95 = 31.0
2*(5-7 = Expected closing bracket
x*5 = Error:Try get unexists variable 'x'
2^6+8 = 72.0
2*pi*50 = 314.1592653589793
e^2+1 = 8.389056098930649
6.78.-7 = not valid number '6.78.'

Добавлено: 18 Мая 2015 21:20:03 Добавил: Василий Рыбин

AppJet – платформа для создания web приложений



Сегодня хочу рассказать об одном очень интересном сервисе – AppJet.

Позиционируется он, насколько я понял, для обучения программированию. Во всяком случае «руководство по программированию для абсолютных новичков» присутствует.

Вообще идея очень интересная.

Чтобы написать обычное web приложение вам нужно знать несколько языков (например, HTML + JavaScript или HTML + PHP, а лучше HTML + CSS + PHP + JavaScript + SQL + библиотеки и фреймворки ;) ).

Здесь нужны только знания JavaScript. Точнее можно только изучать JavaScript, а для реализации серверной части придется освоить лишь небольшой API.

Проще всего это объяснить на примере. Создадим обычный счетчик количества обращений к странице (код я скопировал из справки).

import("storage");
 
if (!storage.count) {
    storage.count = 0;
}
storage.count += 1;
 
printp("I count ",storage.count, " hits.");
 
page.setTitle("Hit me baby one more time");


В принципе, особые пояснения тут не нужны. Сначала мы импортируем библиотеку storage. После этого можем работать с объектом storage.

В данном случае мы проверяем, существует ли свойство count, и если оно не существует, присваиваем ему ноль (создание свойства происходит автоматически).

Функция printp выводит сообщение, а page.setTitle – устанавливает заголовок страницы.

Работа с самим сервисом тоже предельно простая. Регистрируемся. –> переходим в раздел MyApps –> жмем кнопку “Create new app” и видим такую картинку:



Слева окно для ввода кода, справа – просмотр результата.

Для приведенного примера, нажимаем кнопку Reload и значение счетчика увеличивается на единицу.

В общем, сервис предоставляет следующие возможности:

1) Доступ к базе данных из JavaScript объектов.

2) Для работы нужен только браузер.

3) Огромное количество примеров (это их заявление, я насчитал примерно 420 приложений и полсотни библиотек).

4) JavaScript используется для создания серверного кода (с помощью специальных библиотек).

5) Можно привязать свой домен к приложению (не пробовал).

6) Статистика для опубликованных приложений (показывает количество посетителей, количество клонов, комментарии и число строк кода).

В заключение. Сервис вряд ли можно рассматривать как альтернативу разработке полноценных web приложений. Тем не менее, с его помощью можно очень быстро продемонстрировать «абсолютным новичкам» принципы работы web приложений.

До встречи!

Добавлено: 06 Мая 2015 22:30:29 Добавил: Андрей Ковальчук

Крестики-нолики

Мой первый проект на Java. Говорят - код читабельный, табуляция расставлена по правилам. Можно скачать с github.
Буду рад услышать замечания и подсказки, как улучшить код:)
https://github.com/Vsailor/TicTac2




Иерархия классов:


Прямая ссылка: http://imgdepo.ru/id/i6692234

Form.java

abstract public class Form {

    protected static final int SIZE_OF_MATRIX = 8;

    protected static final char BORDER_MATERIAL = '#';

    protected static final char EMPTY_CELL = ' ';

    protected static char[][] matrix = new char[SIZE_OF_MATRIX][SIZE_OF_MATRIX];

    protected static final char FIRST_TOP_COORD = 'a';

    protected static final char FIRST_LEFT_COORD = '1';

    protected static final char MARK_X = 'X';

    protected static final char MARK_O = 'O';

    protected static final int WINNER_SCORE = 3;

    protected static final int STRINGS_MATRIX_COUNT = 3;

    protected static final int TOP_AND_LEFT_BORDER_SIZE = 2;

    protected static final int DOWN_AND_RIGHT_BORDER_SIZE = 1;

    protected static final String COMPUTER_NAME = "Computer";

    protected static final void wrongInputMessage () {

        System.out.println("Wrong input. Please, repeat input.");

    }

    protected static final void notEmptyCellMessage () {

        System.out.println("This cell isn't empty. Please, repeat input.");

    }

}

IPlayer.java
public interface IPlayer {

    public char getMark ();

    public void setMark (char mark);

    public String getPlayerName();

    public void setPlayerName(String playerName);

    public void go (Square square, Round round);

}

Human.java
import java.util.Scanner;

public class Human extends Form implements IPlayer {

    private String playerName = "Player";

    public void setPlayerName (String playerName) {
        this.playerName = playerName;
    }

    public String getPlayerName () {
        return playerName;
    }

    private char mark;

    public Human (char mark) {

        this.mark = mark;

    }

    public Human () {}

    public void setMark (char mark) {

        this.mark = mark;

    };

    public void go (Square square, Round round) {

        Mark playerMark = new Mark(mark);
        Scanner input= new Scanner(System.in);
        String str;

        do {
            do {

                str = input.next();
                playerMark.consoleInput(str);

            } while(!playerMark.cinGood(str));

            if (!square.emptyCell(playerMark.getLeftCoord(), playerMark.getTopCoord())) {

                notEmptyCellMessage();

            }

        } while (!square.emptyCell(playerMark.getLeftCoord(), playerMark.getTopCoord()));

        square.putMark(playerMark);


    };

    public char getMark () {

        return mark;

    };


}

Computer.java
import java.util.Random;

public class Computer extends Form implements IPlayer {

    private char mark;

    private String playerName = "Computer";

    public void setPlayerName (String playerName) {
        this.playerName = playerName;
    }

    public String getPlayerName () {
        return playerName;
    }

    public Computer (char mark) {

        setMark(mark);

    }

    public Computer () {}

    private boolean canPutMarkInTheCenterOfTheMatrix (Square square) {

        if (square.emptyCell('2', 'b')) {

            return true;

        } else {

            return false;

        }

    }

    private void putMarkInCenterOfTheMatrix (Square square, Mark mark) {

        mark.setLeftCoord('2');
        mark.setTopCoord('b');

        if (square.emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {

            square.putMark(mark);

        }

    }


    private boolean canPutMarkInTheConnerOfTheMatrix (Square square) {

        if (square.emptyCell('1','a') || square.emptyCell('1','c') || square.emptyCell('3','a') || square.emptyCell('3','c')) {

            return true;

        } else {

            return false;

        }

    }

    private void putMarkInTheConnerOfTheMatrix (Square square, Mark mark) {

        Random rand = new Random(System.currentTimeMillis());

        do {
            switch (rand.nextInt(4)) {

                case 0:
                    mark.setLeftCoord('1');
                    mark.setTopCoord('a');
                    break;
                case 1:
                    mark.setLeftCoord('1');
                    mark.setTopCoord('c');
                    break;
                case 2:
                    mark.setLeftCoord('3');
                    mark.setTopCoord('a');
                    break;
                case 3:
                    mark.setLeftCoord('3');
                    mark.setTopCoord('c');
                    break;
                default:
            }

        } while (!square.emptyCell(mark.getLeftCoord(),mark.getTopCoord()));

        square.putMark(mark);

    }



    private void putMarkInTheRandomPlace (Square square, Mark mark) {

        Random rand = new Random(System.currentTimeMillis());

        do {

            switch (rand.nextInt(3)) {

                case 0:
                    mark.setLeftCoord('1');
                    break;
                case 1:
                    mark.setLeftCoord('2');
                    break;
                case 2:
                    mark.setLeftCoord('3');
                    break;
                default:
            }

            switch (rand.nextInt(3)) {

                case 0:
                    mark.setTopCoord('a');
                    break;
                case 1:
                    mark.setTopCoord('b');
                    break;
                case 2:
                    mark.setTopCoord('c');
                    break;
                default:
            }
        } while (!square.emptyCell(mark.getLeftCoord(),mark.getTopCoord()));

        square.putMark(mark);

    }


    private boolean playerWillBeWinnerInTheNextStep (Square square, IPlayer player) {

        Mark mark = new Mark(player.getMark());

        for (char i=FIRST_LEFT_COORD; i<FIRST_LEFT_COORD + STRINGS_MATRIX_COUNT; i++) {

            for (char j=FIRST_TOP_COORD; j<FIRST_TOP_COORD + STRINGS_MATRIX_COUNT; j++) {

                mark.setLeftCoord(i);
                mark.setTopCoord(j);

                if (square.emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {

                    square.putMark(mark);

                    if (square.winner(player)) {

                        square.clearCell(mark.getLeftCoord(), mark.getTopCoord());

                        return true;

                    } else {

                        square.clearCell(mark.getLeftCoord(), mark.getTopCoord());

                    }


                }


            }
        }

        return false;

    }

    private void blockCellThatPlayerWillNotBeWinnerInTheNextStep (Square square, Human human) {

        Mark mark = new Mark(human.getMark());

        for (char i=FIRST_LEFT_COORD; i<FIRST_LEFT_COORD + STRINGS_MATRIX_COUNT; i++) {

            for (char j=FIRST_TOP_COORD; j<FIRST_TOP_COORD + STRINGS_MATRIX_COUNT; j++) {

                mark.setLeftCoord(i);
                mark.setTopCoord(j);

                if (square.emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {

                    square.putMark(mark);

                    if (square.winner(human)) {

                        square.clearCell(mark.getLeftCoord(), mark.getTopCoord());

                        if (human.getMark() == MARK_X) {

                            mark.setMark(MARK_O);

                        } else {

                            mark.setMark(MARK_X);

                        }


                        square.putMark(mark);

                        return;


                    } else {

                        square.clearCell(mark.getLeftCoord(), mark.getTopCoord());

                    }


                }


            }
        }

    }


    private void chooseCellToWinInTheNextStep (Square square, IPlayer player) {

        Mark mark = new Mark(player.getMark());

        for (char i=FIRST_LEFT_COORD; i<FIRST_LEFT_COORD + STRINGS_MATRIX_COUNT; i++) {

            for (char j=FIRST_TOP_COORD; j<FIRST_TOP_COORD + STRINGS_MATRIX_COUNT; j++) {

                mark.setLeftCoord(i);
                mark.setTopCoord(j);

                if (square.emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {

                    square.putMark(mark);

                    if (!square.winner(player)) {

                        square.clearCell(mark.getLeftCoord(), mark.getTopCoord());

                    } else {

                        return;

                    }


                }


            }
        }

    }


    public void setMark (char mark) {

        this.mark = mark;

    }

    public char getMark () {

        return mark;

    };

    private boolean cleverRandom (Square square, Human human, Mark mark) {

        Mark humanMark = new Mark(human.getMark());
        if (square.belongs(humanMark, '2', 'a') && square.belongs(humanMark, '1', 'b')) {
            mark.setLeftCoord('1');
            mark.setTopCoord('a');
            square.putMark(mark);
            return true;

        }

        if (square.belongs(humanMark, '1', 'b') && square.belongs(humanMark, '2', 'c')) {
            mark.setLeftCoord('1');
            mark.setTopCoord('c');
            square.putMark(mark);
            return true;

        }

        if (square.belongs(humanMark, '3', 'b') && square.belongs(humanMark, '2', 'c')) {
            mark.setLeftCoord('3');
            mark.setTopCoord('c');
            square.putMark(mark);
            return true;

        }

        if (square.belongs(humanMark, '3', 'b') && square.belongs(humanMark, '2', 'a')) {
            mark.setLeftCoord('3');
            mark.setTopCoord('a');
            square.putMark(mark);
            return true;

        }

        return false;
    }

    public void go (Square square, Round round) {

        Mark humanMark;
        Mark computerMark = new Mark(this.getMark());

        Human fakeHuman;

        if (round.start == 1) {
            if (this.getMark() == MARK_X) {
                fakeHuman = new Human(MARK_O);
                humanMark = new Mark(MARK_O);
            } else {

                fakeHuman = new Human(MARK_X);
                humanMark = new Mark(MARK_X);
            }



        } else {
            if (this.getMark() == MARK_O) {
                fakeHuman = new Human(MARK_X);
                humanMark = new Mark(MARK_X);
            } else {

                fakeHuman = new Human(MARK_O);
                humanMark = new Mark(MARK_O);
            }

        }


        if (playerWillBeWinnerInTheNextStep(square, this)) {

            chooseCellToWinInTheNextStep(square, this);
            return;

        }

        if (playerWillBeWinnerInTheNextStep(square, fakeHuman)) {

            blockCellThatPlayerWillNotBeWinnerInTheNextStep(square, fakeHuman);
            return;

        }

        computerMark.setLeftCoord('2');
        computerMark.setTopCoord('b');

        if (square.emptyCell(computerMark.getLeftCoord(), computerMark.getTopCoord())) {

            square.putMark(computerMark);

            return;

        }

        if (!cleverRandom(square, fakeHuman, computerMark)) {

            if (square.emptyCell('1', 'a') || square.emptyCell('1', 'c') || square.emptyCell('3', 'a') || square.emptyCell('3', 'c')) {

                putMarkInTheConnerOfTheMatrix(square, computerMark);
                return;

            }


        }
        putMarkInTheRandomPlace(square, computerMark);
    }

}

Round.java
import java.util.Scanner;

public class Round extends Form {

    public int start = 0;

    private char typeOfGame;

    public char getTypeOfGame() {
        return typeOfGame;
    }

    public void registration (IPlayer player1, IPlayer player2) {

        Scanner input= new Scanner(System.in);

        if (player1.getPlayerName() == COMPUTER_NAME) {

            System.out.println("Enter your name:");

            player2.setPlayerName(input.next());


        } else if (player2.getPlayerName() == COMPUTER_NAME) {

            System.out.println("Enter your name:");

            player1.setPlayerName(input.next());


        } else {

            System.out.println("Name of first player:");
            player1.setPlayerName(input.next());
            System.out.println("Hello " + player1.getPlayerName() + "!");
            System.out.println("Name of second player:");
            player2.setPlayerName(input.next());
            System.out.println("Hello " + player2.getPlayerName() + "!");

        }

    }

    public void setMarksForPlayers (IPlayer player1, IPlayer player2) {

        Scanner input= new Scanner(System.in);
        String str;
        System.out.println("Who will be playing X?");
        System.out.println();

        if (player1.getPlayerName() == COMPUTER_NAME || player2.getPlayerName() == COMPUTER_NAME) {

            System.out.println("1. Me");
            System.out.println("2. " + COMPUTER_NAME);
            System.out.println();
            char answer = '0';

            do {

                str = input.next();

                if (str.length() == 1) {

                    char []var = str.toCharArray();

                    answer = var[0];

                    if (!((var[0] == '1' ) || (var[0] == '2'))) {

                        wrongInputMessage();

                    }

                    if (answer == '1') {

                        this.start = 1;
                    }
                    if (answer == '2') {

                        this.start = 2;
                    }

                } else {

                    wrongInputMessage();

                }

            } while(!(answer == '1' || answer == '2'));


        } else {

            System.out.println("1. " + player1.getPlayerName());
            System.out.println("2. " + player2.getPlayerName());
            System.out.println();
            char answer = '0';

            do {

                str = input.next();

                if (str.length() == 1) {

                    char []var = str.toCharArray();

                    answer = var[0];

                    if (!((var[0] == '1' ) || (var[0] == '2'))) {

                        wrongInputMessage();

                    }

                    if (answer == '1') {

                        start = 1;
                    } else {

                        start = 2;

                    }

                } else {

                    wrongInputMessage();

                }

            } while(!(answer == '1' || answer == '2'));

        }

    }

    public void hello() {

        String str;

        System.out.println();
        System.out.println("***************************************************************");
        System.out.println("*                                                             *");
        System.out.println("*                            TIC TAC                          *");
        System.out.println("*                                                             *");
        System.out.println("*                             ALPHA                           *");
        System.out.println("*                                                             *");
        System.out.println("***************************************************************");
        System.out.println();
        System.out.println("Choose the type of the game:");
        System.out.println();
        System.out.println("1. Player VS Player");
        System.out.println("2. Player VS Computer");
        System.out.println();

        Scanner input= new Scanner(System.in);

        do {

            str = input.next();

            if (str.length() == 1) {

                char []var = str.toCharArray();

                typeOfGame = var[0];

                if (!((var[0] == '1' ) || (var[0] == '2'))) {

                    wrongInputMessage();

                }

            } else {

                wrongInputMessage();

            }

        } while(!(typeOfGame == '1' || typeOfGame == '2'));


    }

    public boolean restartGame() {

        Scanner input= new Scanner(System.in);

        System.out.println("Do you want to restart the game?[y/n] ");
        String str;

        char ans = 0;

        do {

            str = input.next();
            if (str.length() == 1) {

                char []var = str.toCharArray();

                ans = var[0];

                if (!((var[0] == 'y' ) || (var[0] == 'n'))) {

                    wrongInputMessage();

                }
            } else {

                wrongInputMessage();

            }

        } while(!(ans == 'y' || ans == 'n'));

        if (ans == 'y') {

            return true;

        } else {
            System.out.println("Good bye!");

            return false;

        }


    }

}

Mark.java

public class Mark extends Form {

    private char mark;

    private char leftCoord;

    private char topCoord;

    public Mark (char mark) {

        setMark(mark);

    }


    public void setMark (char mark) {

        if (mark == MARK_X || mark == MARK_O) {

            this.mark = mark;

        } else {

            System.out.println("Wrong mark input.");

        }

    }

    public Mark () {}

    public char getMark() {
        return mark;
    }

    public char getTopCoord() {
        return topCoord;
    }

    public char getLeftCoord() {
        return leftCoord;
    }

    public void setLeftCoord(char leftCoord) {

        if (leftCoord>=FIRST_LEFT_COORD && leftCoord<=FIRST_LEFT_COORD+SIZE_OF_MATRIX/2-TOP_AND_LEFT_BORDER_SIZE) {

            this.leftCoord = leftCoord;

        }
    }

    public void setTopCoord(char topCoord) {

        if (topCoord>=FIRST_TOP_COORD && topCoord<=FIRST_TOP_COORD+SIZE_OF_MATRIX/2-TOP_AND_LEFT_BORDER_SIZE){
            this.topCoord = topCoord;
        }

    }


    public void consoleInput(String str) {

        char []string = str.toCharArray();

        setTopCoord(string[0]);

        setLeftCoord(string[1]);

    }

    public boolean cinGood(String str) {

        char []string = str.toCharArray();

        if (str.length()==2) {

            if (string[0] >= FIRST_TOP_COORD && string[0] <= FIRST_TOP_COORD+SIZE_OF_MATRIX/2-TOP_AND_LEFT_BORDER_SIZE) {

                if (string[1] >= FIRST_LEFT_COORD && string[1] <= FIRST_LEFT_COORD+SIZE_OF_MATRIX/2-DOWN_AND_RIGHT_BORDER_SIZE) {

                    return true;

                } else {

                    wrongInputMessage();

                    return false;

                }
            } else {

                wrongInputMessage();

                return false;
            }

        } else {

            wrongInputMessage();

            return false;
        }


    }

}

Square.java
import java.util.Scanner;

public class Square extends Form {

    public Square() {

        for (int i=0; i< SIZE_OF_MATRIX; i++) {

            eraseLine(i);

        }

        setBorder();

    }

    private void eraseLine (int line_number) {

        for (int i=0; i< SIZE_OF_MATRIX; i++){
            matrix[line_number][i] = EMPTY_CELL;
        }

    }

    private boolean winnerScore (int count) {

        if (count == WINNER_SCORE) {

            return true;

        } else {

            return false;

        }

    }

    private void setBorder() {

        for (int i=TOP_AND_LEFT_BORDER_SIZE-1; i< SIZE_OF_MATRIX; i+=2) {

            for (int k=TOP_AND_LEFT_BORDER_SIZE-1; k< SIZE_OF_MATRIX; k++) {

                matrix[i][k] = BORDER_MATERIAL;

            }

            for (int k=TOP_AND_LEFT_BORDER_SIZE; k< SIZE_OF_MATRIX; k++) {

                matrix[k][i] = BORDER_MATERIAL;

            }

        }

        char topCoord = FIRST_TOP_COORD;

        for (int i=TOP_AND_LEFT_BORDER_SIZE; i< SIZE_OF_MATRIX; i+=2) {

            matrix[0][i] = topCoord;
            topCoord++;

        }

        char leftCoord = FIRST_LEFT_COORD;

        for (int i=TOP_AND_LEFT_BORDER_SIZE; i< SIZE_OF_MATRIX; i+=2) {

            matrix[i][0] = leftCoord;
            leftCoord++;

        }

    }

    public int countOfMarks (char mark) {

        int count = 0;


        for (int i=0; i<SIZE_OF_MATRIX; i++) {

            for (int k=0; k<SIZE_OF_MATRIX; k++) {

                if (matrix[i][k] == mark) {

                    count++;

                }



            }
        }

        return count;

    }

    private boolean checkWinInHorizontalAndVerticalLines (IPlayer player) {

        int leftLineCount = 0;

        int topLineCount = 0;

        for (int i=0; i<SIZE_OF_MATRIX; i++) {

            for (int k=0; k<SIZE_OF_MATRIX; k++) {

                if (matrix[i][k] == player.getMark()) {

                    leftLineCount++;

                }

                if (matrix[k][i] == player.getMark()) {

                    topLineCount++;

                }

                if (winnerScore(leftLineCount) || winnerScore(topLineCount)) {

                    return true;

                }

            }

            leftLineCount = 0;

            topLineCount = 0;
        }

        return false;

    }


    private boolean checkWinInDiagonalLines (IPlayer player) {

        int count1 = 0;

        for (int i=0; i<SIZE_OF_MATRIX; i++) {

            if (matrix[i][i] == player.getMark()) {

                count1++;

            }

        }

        int count2 = 0;

        for (int i=SIZE_OF_MATRIX-DOWN_AND_RIGHT_BORDER_SIZE, j=TOP_AND_LEFT_BORDER_SIZE-1; i>=TOP_AND_LEFT_BORDER_SIZE; i--, j++) {

            if (matrix[i][j] == player.getMark()) {

                count2++;

            }

        }


        if (count1 == WINNER_SCORE || count2 == WINNER_SCORE) {

            return true;

        }   else {

            return false;

        }
    }

    private boolean playerWillBeWinnerInTheNextStep (IPlayer player) {

        Mark mark = new Mark(player.getMark());

        for (char i=FIRST_LEFT_COORD; i<FIRST_LEFT_COORD + STRINGS_MATRIX_COUNT; i++) {

            for (char j=FIRST_TOP_COORD; j<FIRST_TOP_COORD + STRINGS_MATRIX_COUNT; j++) {


                mark.setLeftCoord(i);
                mark.setTopCoord(j);


                if (emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {

                    putMark(mark);

                    if (winner(player)) {

                        clearCell(mark.getLeftCoord(), mark.getTopCoord());

                        return true;

                    } else {

                        clearCell(mark.getLeftCoord(), mark.getTopCoord());

                    }


                }


            }
        }

        return false;

    }


    private void showMatrixLine (int line_number) {

        for (int i=0; i< SIZE_OF_MATRIX; i++) {

            System.out.print(matrix[line_number][i]);

        }

    }


    public void showMatrix () {

        for (int i=0; i< SIZE_OF_MATRIX; i++) {

            showMatrixLine(i);
            System.out.println();

        }

    }

    public void winMessage (IPlayer player) {

        System.out.print(player.getPlayerName() + " is winner!");

    }


    public boolean winner (IPlayer player) {

        if (checkWinInHorizontalAndVerticalLines(player) || checkWinInDiagonalLines(player)) {

            return true;

        } else {

            return false;

        }

    }

    public boolean belongs (Mark mark, char leftCoord, char topCoord) {

        if (matrix[(leftCoord-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(topCoord-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] == mark.getMark()) {

            return true;

        }
        return false;


    }

    public boolean endWithoutWinner () {

        for (int i=TOP_AND_LEFT_BORDER_SIZE; i<SIZE_OF_MATRIX; i++) {

            for (int k=TOP_AND_LEFT_BORDER_SIZE; k<SIZE_OF_MATRIX; k++) {

                if (matrix[i][k] == EMPTY_CELL) {

                    return false;

                }

            }


        }

        return true;

    }


    public void endWithoutWinnerMessage () {

        System.out.println("Game over. Winner is absent.");

    }


    public boolean emptyCell (char leftCoord, char topCoord) {

        if (matrix[(leftCoord-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(topCoord-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] == EMPTY_CELL) {

            return true;

        } else {

            return false;

        }
    }


    public void clearCell(char leftCoord, char topCoord) {

        matrix[(leftCoord-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(topCoord-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] = EMPTY_CELL;

    }


    public void putMark (Mark mark) {

        if (matrix[(mark.getLeftCoord()-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(mark.getTopCoord()-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] == EMPTY_CELL) {

            matrix[(mark.getLeftCoord()-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(mark.getTopCoord()-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] = mark.getMark();

        }

    }

}

Main.java
import java.util.Scanner;

public class Main extends Form {
    public static void main(String[] args) {

        Round round;

        do {
            round = new Round();
            Square square = new Square();
            round.hello();
            IPlayer player1 = new Human();
            IPlayer player2;
            if (round.getTypeOfGame() == '2') {

                player2 = new Computer();

            } else {

                player2 = new Human();

            }
            round.registration(player1,player2);
            round.setMarksForPlayers(player1, player2);

            if (round.start == 1) {
                player1.setMark(MARK_X);
                player2.setMark(MARK_O);

            } else {

                player1.setMark(MARK_O);
                player2.setMark(MARK_X);

            }
            square.showMatrix();
            while (true) {

                if (round.start == 1) {
                    player1.go(square,round);
                    square.showMatrix();
                    if (square.winner(player1)) {

                        square.winMessage(player1);
                        break;
                    }

                    if (square.endWithoutWinner()) {

                        square.endWithoutWinnerMessage();
                        break;

                    }
                    round.start = 2;

                } else {
                    player2.go(square, round);
                    square.showMatrix();
                    if (square.winner(player2)) {

                        square.winMessage(player2);
                        break;
                    }

                    if (square.endWithoutWinner()) {

                        square.endWithoutWinnerMessage();
                        break;

                    }
                    round.start = 1;
                }


            }
        } while (round.restartGame());
    }
}

Добавлено: 20 Мая 2014 01:57:42 Добавил: Андрей Ковальчук

Bijective на Java,только encode,decode пишите сами,если нужно

public class Crypt {

    private static final String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-";
    private String result = "";
    private static final int base = alphabet.length();

    public String encode(int number) {
        char[] alphabetArray = alphabet.toCharArray();
        if (number == 0) {
            String temp = "";
            temp += alphabet.charAt(0);
            return temp;
        }

        while (number > 0) {
            result += alphabetArray[number % base];
            number = (int) Math.floor(number / base);
        }
        return reverse(result);
    }

    private String reverse(String inputString) {
        String temp = "";
        for (int i = inputString.length() - 1; i >= 0; i--) {
            temp += inputString.charAt(i);
        }
        return temp;
    }
}

Добавлено: 16 Февраля 2014 01:47:56 Добавил: Андрей Ковальчук

Проверка числа на простоту

public static boolean isPrime(int n) {
        if (n == 2) return true;
        if (n % 2 == 0 || n == 1) return false;
        long limit = (long)Math.sqrt(n);
        for (int i = 3; i <= limit; i += 2)
            if (n % i == 0) return false;
        return true;
    }

Добавлено: 20 Января 2014 09:20:41 Добавил: Андрей Ковальчук

Преобразовать строку в число Java.

Для преобразования строки в число на языке java существует несколько способов.

    byte b = Byte.parseByte("123");

    short s = Short.parseShort("123");

    int i = Integer.parseInt("123");

    long l = Long.parseLong("123");

    float f = Float.parseFloat("123.4");

    double d = Double.parseDouble("123.4e10")

Мой самый любимый Integer.parseInt(String);

Обратное действие (преобразование числа в строку) проще для запоминания, так как название методов совпадает во многих языках веб-программирования.
Выглядит запись так:
Integer i = 5; 
i = i.toString();

Добавлено: 29 Сентября 2013 02:18:04 Добавил: Андрей Ковальчук

Список дисков и их размеры JAVA

Для получения списка дисков и из размеров можно написать простенький код.
import java.io.File;

/**
 * Created with IntelliJ IDEA.
 * User: dimka3210
 * Date: 02.12.12
 * Time: 10:50
 * To change this template use MyFile | Settings | MyFile Templates.
 */
public class Main {
    public static String toGb(Long size){
         return String.valueOf(size/(1024/*Kb*/*1024/*Mb*/*1024/*Gb*/)+" Gb");
    }

    public static String toGbFloat(Float size){
        return String.valueOf(size/(1024/*Kb*/*1024/*Mb*/*1024/*Gb*/)+" Gb");
    }

    public static void main(String[] args) throws Exception {
        /**
         * Точка входа
         */
        //MyFile.writeFile();
        for(File f : File.listRoots()){
            System.out.println(f.toString()+" Size: "+ toGb(f.getTotalSpace())+"; Empty: "+toGbFloat(Float.parseFloat(String.valueOf(f.getFreeSpace()))));
        }
    }
}





Как видим всё прекрасно работает.

Добавлено: 29 Сентября 2013 02:16:53 Добавил: Андрей Ковальчук

Работа с датами в Java.

Тут опишу о такой утилите в java как Calendar. Именно он и позволяет работать с текущей датой.
Строковое представлени даты мы можем получить просто, не сложнее чем в php.

import java.util.Date;
import static java.lang.System.out;

public class Main {
    public static void main(String[] args){
        Date d = new Date();
        out.println(d.toString());
    }
}

У меня результат такой



Но если мы хотим свой формат, например как передавать строковый формат в функции date() в php.
То тут всё немного сложнее, но только для первого раза. Именно здесь нам и потребуется утилита календарь.
import java.util.Calendar;
import static java.lang.System.out;

public class Main {
    public static void main(String[] args){
        Calendar cal = Calendar.getInstance();
        out.println(cal.get(Calendar.YEAR));
    }
}

Выведет нам на экран текущий год.

Давайте вовпробуем воссоздать вот такое date(time(), "Y-m-d H:i:s"); на java.

У меня получилось вот так
import java.util.Calendar;
import static java.lang.System.out;

public class Main {
    public static void main(String[] args){
        String sOut = ""; // String out;
        Calendar cal = Calendar.getInstance();
        sOut = sOut + cal.get(Calendar.YEAR) + "-";
        sOut += (cal.get(Calendar.MONTH)+1) + "-";
        sOut += cal.get(Calendar.DAY_OF_MONTH) + " ";
        sOut += cal.get(Calendar.HOUR_OF_DAY) + ":";
        sOut += cal.get(Calendar.MINUTE) + ":";
        sOut += cal.get(Calendar.SECOND);
        out.println(sOut);
    }
}

Результат такой

Добавлено: 29 Сентября 2013 02:15:19 Добавил: Андрей Ковальчук

Java. Все события мыши.

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

package ru.dimka3210;
 
import javax.swing.*;
import java.awt.event.*;
 
/**
 * User: dimka3210
 * Date: 28.03.13
 * Time: 21:27
 */
public class MyFrame extends JFrame {
    public static void main(String[] args) {
        new MyFrame();
    }
 
    public MyFrame() {
        setSize(500, 500);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                System.exit(0);
            }
        });
 
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);    // Клик
                System.out.println("mouseClicked ->" + e.getX() + "->" + e.getY());
            }
 
            @Override
            public void mousePressed(MouseEvent e) {
                super.mousePressed(e);    // Кнопка прижата
                System.out.println("mousePressed ->" + e.getX() + "->" + e.getY());
            }
 
            @Override
            public void mouseReleased(MouseEvent e) {
                super.mouseReleased(e);    // Кнопка отжата
                System.out.println("mouseReleased ->" + e.getX() + "->" + e.getY());
 
            }
 
            @Override
            public void mouseEntered(MouseEvent e) {
                super.mouseEntered(e);    // Мышь "над окном"б вошла на территорию окна
                System.out.println("mouseEntered ->" + e.getX() + "->" + e.getY());
 
            }
 
            @Override
            public void mouseExited(MouseEvent e) {
                super.mouseExited(e);    // Мышь покинула окно
                System.out.println("mouseExited ->" + e.getX() + "->" + e.getY());
 
            }
 
        });
 
        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                super.mouseDragged(e);    // Перемещение мыши с прижатой кнопкой
                System.out.println("mouseDragged ->" + e.getX() + "->" + e.getY());
 
            }
 
            @Override
            public void mouseMoved(MouseEvent e) {
                super.mouseMoved(e);    // Перемещение мыши с отжатыми кнопками
                System.out.println("mouseMoved ->" + e.getX() + "->" + e.getY());
 
            }
        });
 
        addMouseWheelListener(new MouseAdapter() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                super.mouseWheelMoved(e);    // Прокрутка "колёсиком" мыши
                System.out.println("mouseWheelMoved ->" + e.getX() + "->" + e.getY());
 
            }
        });
 
        setVisible(true);
    }
}

Добавлено: 28 Сентября 2013 11:14:56 Добавил: Андрей Ковальчук

Рабочий пример java.util.Properties

Ух, и довольно ж долго я с ним провозился. Как-то не легко мне далось это знание, да и само оно какое-то размытое, но по порядку.

Итак, возникла задача в нашем реминдере сделать запоминание настроек, своего городить не хотелось, решил погуглить. Нагуглил волшебный класс java.util.Properties. Ну и начал его использовать. Да вот только порядок сздания потоков что то все забывают указать. Короче вот тут выкладываю рабочий примерчик, что бы не было у остальных проблем.

Файл Main.java

import java.io.*;
 
import java.util.*;
 
 
 
/**
 
 * User: dimka3210
 
 * Date: 10.03.13
 
 * Time: 10:20
 
 */
 
public class Main {
 
    public static void main(String args[]) throws IOException {
 
        String filePath = "property.ini";
 
        FileInputStream fileInputStream = null;
 
        FileOutputStream fileOutputStream = null;
 
        Properties properties = new Properties();
 
        HashMap<String, String> arraySettings = new HashMap<String, String>();
 
 
 
        try {
 
            fileInputStream = new FileInputStream(filePath);
 
            properties.load(fileInputStream);
 
            Enumeration enumeration = properties.keys();
 
            //properties.setProperty("test", "test");
 
            while (enumeration.hasMoreElements()){
 
                String key = enumeration.nextElement().toString();
 
                arraySettings.put(key, properties.getProperty(key));
 
                if (arraySettings.get(key).equals("test")){
 
                    arraySettings.remove("test");
 
                }
 
            }
 
 
 
            System.out.println(arraySettings);
 
 
 
            fileOutputStream = new FileOutputStream(filePath);
 
            properties.store(fileOutputStream, "no comment");
 
 
 
        } catch (FileNotFoundException e) {
 
            new File("property.ini").createNewFile();
 
            System.out.println("createNewFile");
 
            e.getMessage();
 
        } catch (InvalidPropertiesFormatException e) {
 
            e.getMessage();
 
        } catch (IOException e) {
 
            e.getMessage();
 
        } finally {
 
            fileOutputStream.close();
 
            fileInputStream.close();
 
        }
 
    }
 
}

Добавлено: 28 Сентября 2013 11:11:48 Добавил: Андрей Ковальчук