Блог о программировании

Июнь 29, 2011

 

Main args, netbeans

Пара простых вещей (про Java/Scala + CLI и NetBeans)

Самый популярный и набивший оскомину пример HelloWorld встречается, наверное, уже во всех учебниках по программированию:

// Пример из туториала: http://download.oracle.com/javase/tutorial/getStarted/application/index.html class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); // Display the string. } }

Здесь String[] args — аргументы командной строки.
Например:
java HelloWorldApp 1 2 означает, что args будет равно {"1", "2"}.

Если передается всего один аргумент (например, "debug"), то все очень просто — можно подсмотреть пример из туториала: cmdLineArgs.

В случае, если аргументов много (как в гнусных линуксовых командах), то можно использовать какую-нибудь готовую библиотеку:

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

В том случае, если аргументы не такие сложные и не слишком простые, а что-то среднее, то тянуть для этих целей дополнительную библиотеку нет никакого смысла. Например, если нужно передать что-то вроде: "-x -size 1024 -v". Обычно это бывает, когда требуется небольшая, почти "одноразовая" программа...

Многие настолько не любят писать разбор таких аргументов, что лепят все параметры в системные свойства (java ... -Dfoo="some string"), чтобы потом дергать их через System.getProperty().
Это конечно удобно, но не всегда нормально.

Проще написать разбор обычными стандартными средствами:

public class App {   public static void main(String[] args) { boolean v = false, x = false; int size = 0; for (int i=0;i<args.length;++i) { String arg = args[i]; if (arg.equals("-v")) { v = true; } else if (arg.equals("-size")) { size = Integer.parseInt(args[++i]);//да, здесь может быть ArrayIndexOutOfBoundsException } else if (arg.equals("-x")) { x = true; } } System.err.println("v = " + v); System.err.println("x = " + x); System.err.println("size = " + size); } }

В Scala все то же самое.
Тривиальный случай – делаем как в примере на официальном сайте: Snippet: Match Arguments.
Что-то очень сложное – подключаем сторонние библиотеки (ту же апачевскую или jopt), что и в Java случае.
В том случае, если что-то среднее, то можно написать на чистой Scala:

object App { def main(args:Array[String]) = { var v = false; var x = false; var size = 0 ("" +: args :+ "") reduceLeft ( (i, j) => { i match { case "-v" => v = true case "-size" => size = j.toInt case "-x" => x = true case _ => }; j }) println("v =" + v ) println("x = " + x) println("size = " + size) } }

Про другую известную многим фишку, о которой хотел рассказать — макросы в NetBeans-ах.
Точнее, про самый популярный макрос - debug-var. Вызывается по нажатию: Ctrl-J D.
Вообще макросы в нетбинсах есть уже много лет, по-крайне мере, когда я только начинал использовать нетбинс (3.* версии), они уже там были.
Например, для Scala можно сделать макрос, который будет вставлять в код: println("var=" + var)

Настроить можно здесь:
Tools -> Option -> Editor -> Macros

Про другие полезные макросы можно почитать здесь

Блог о программировании

Июнь 1, 2011

 

Немного карри

Использовать карринг в Scala одно удовольствие.
Само определение каррирования(или карринга, названо в честь Хаскелла Карри):

Для функции h типа h : (A × B) → C оператор каррирования Λ выполняет преобразование
Λ(h) : A → (B → C)

Отметим, что Λ - это оператор, то есть "функция над функциями".
Например берем функцию foo(x,y), каррируем и получаем moo(x)(y) - функцию от x которая возвращает функцию от y.

Таким образом мы можем сводим программу к вычислению функции от одного аргумента.

Чтобы выполнить карирование, можно вызвать Function.curried. Сейчас это уже устаревший метод, т.к. curried можно вызывать сразу у функции.

Небольшой пример (для наглядности в императивном стиле):

scala> val foo = (x:Int,y:Int) => x + y // функция от 2(ДВУХ) аргументов x и y. scala> foo(1,2) // просто сложили и получили три scala> val moo = foo.curried // получили функцию от 1(ОДНОГО) аргумента, которая возвращает scala> val zoo = moo(1) // функцию от 1(ОДНОГО) аргумента scala> zoo(2) // урраа! получили три scala> // можно каррировать и так: scala> def noo(x:Int, y:Int) = x * y scala> val a = noo _ // получили функцию от 2-х аргументов (подробнее см. partially applied function) scala> val b = a.curried scala> b(2) // = фунция 2 * аргумент scala> b(2)(3) // = 6

Метод curried можно найти в трейтах начиная от Function2 и заканчивая Function22.
Это значит, что вы можете использовать его для функций от 2 аргументов и до функций с 22-аргументами включительно.

Для функций без аргументов и с одним аргументом использовать бессмысленно.

Для функций с более чем 22-мя не поддерживается (таких трейтов вообще нет).
Например если Вы захотите сделать:
val foo = (x0:Int,x1:Int и т.д. до x22:Int) => 0
то получите ошибку компиляции:
"implementation restricts functions to 22 parameters".

Чтобы не возникало путаницы, поясню.

  • Во-первых:
    Это не значит, что вы не можете объявлять методы
    def foo(x0:Int,x1:Int и т.д. до x22:Int) = 0
    Это будет работать, но использовать в полную "силу" возможности Scala по работе с функциями уже не получится.
    Можно считать, что это "обычный" метод с 23 аргументами...
  • Во-вторых:
    Функции с varargs (переменным количество аргументов) работают нормально. Здесь никаких проблем с каррирование быть не должно.
  • В-третьих:
    Если у вас функции с более чем 22 аргументами это π#_!@#?!!!
    Думаете такого не бывает? Когда-то я работал в организации, в которой нужно было писать и разбираться со скриптами на лиспе (было и такое в моей жизни). Так вот, некоторые умельцы декларировали функции от 15-ти и более аргументов.
    Я в очередной раз взываю ко всем программистам с планеты Земля.
    Пожалуйста, постарайтесь так больше не делать. Уж очень неприятно работать с таким кодом.

Блог о программировании

Февраль 26, 2011

 

Scala. Pattern Matching


Продолжил работу по созданию учебных материалов по Scala.
Выкладываю черновую версию одной из глав.

Сопоставление по образцу (pattern matching). Начало.


В качестве вариантов перевода слова match с английского языка словарь Lingvo приводит следующие варианты:

match [mæʧ] 3) а) подбирать(под пару, под стать; по цвету, форме) to be well / ill matched — быть хорошо / плохо подобранным; хорошо / плохо сочетаться ... б) подходить, соответствовать (под пару; по цвету, форме) dress with a hat to match — платье с удачно подобранной шляпкой ...

В языке Scala ключевое слово match также используется для того, чтобы подбирать или находить соответствие:

e match { case p1 => e1 // ... case pn => en }

Где e, e1, en - некие выражения (expression) , а p1, pn - шаблоны (pattern) по которыми мы пытаемся найти соответствия.

Такая конструкция напоминает обычный switch / case из языков программирования Java или С/C++.

Сравним примеры:

Scala Java C
a match { case 0 => print("zero")   case 1 => print("one")   case _ => print("too much") }
switch (a) { case 0: System.out.print("zero"); break;   case 1: System.out.print("one"); break;   default: System.out.print("too much"); break; }
switch (a) { case 0: printf("zero"); break;   case 1: printf("zero"); break;   default: printf("too much"); break; }

Tips. В Scala можно указать сразу несколько условий в case

a match { case 1 | 2 | 3 => println("один, два, или три") }

Рассмотрим подробнее наш пример. В нем объект a "сравнивается" с разными шаблонами.
Для a равному 0, будет будет исполнен код print("zero").
Для а равному 1, будет выполнено print("one").
Для остальных случаев в Scala есть символ-джокер. Он обозначается символом подчёркивания _ . Таким образом case _ сработает в том случае, если другие шаблоны не подошли. Похожее поведение в Java реализуется с помощью слова default .

Tips. Символ-джокер, он же wild-card. По аналогии с карточными играми, например покером, в котором такая "дикая" карта (wild card) может стать другой картой по желанию игрока (например "пятым" тузом).
Простыми примерами таких символов может служить знак * в Unix/Windows скриптах или символ % в SQL-ном LIKE. В Scala wild-card "_" используется не только в case-ах, но и в других конструкциях.

Важной особенностью языка Scala заключается в том, что в отличие от switch/case С или Java, match умеет работать со строками. Более того match можно использовать для сопоставление объектов так называемых case классов, работу с которыми бы подробно рассмотрим в следующей главе.

Tips. Eсли мы попробуем например декомпилировать (javap -c ) указанный выше пример, мы обнаружим что Scala компилятор создаёт не плохой байт-код, аналогичный тому если бы мы писали на Java используя switch/case.

Итак, попробуем использовать полученные знания.
Представим, что у нас есть некоторый набор команд К. Например К = { F, +, - } :
F → пойти прямо
+ → повернуть направо
- → повернуть налево

Напишем программу, которая будет исполнять эти команды:

// полный текст программы будет приведён в конце главы cmd foreach (i => i match { case 'F' => { g.setColor(Color.red) val x2 = (x + length*cos(α)).toInt val y2 = (y + length*sin(α)).toInt g.drawLine(x, y, x2,y2) x = x2; y = y2; } case '+' => α += 0.5*Pi case '-' => α -= 0.5*Pi } )

Здесь cmd - обозначает строку с последовательностью различных команд. Например "F−F++F−F", будет означать - прямо, налево, прямо, направо, направо, прямо, налево, прямо.
Значение переменных x, y, α будут задавать текущие координаты и направление движения нашей системы.

Используем ещё раз силу match и применив какую-нибудь простую L-system-у, напишем программу которая будет рекурсивно создавать нам красивую последовательность команд.

Например, пусть будет следующее правило преобразований:
F → F+F-F-FF+F+F-F
+ → +
- → -

На языке Scala это можно записать следующим образом:

def next(x:String): String = { var result = new StringBuilder() x.foreach(p=> p match { case 'F' => result ++= "F+F-F-FF+F+F-F" case i => result +=i } ) result.toString }

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

Исходный код. В качестве эксперимента можно таким образом нарисовать салфетку серпинского или снежинку коха.

// Использование программного кода только в учебных целях. // Автор: Виталий Л. vit@programmisty.com import java.awt.Color import java.awt.image.BufferedImage import java.io.File import javax.imageio.ImageIO import scala.math._   object FractalLab {     def main(s:Array[String]) { // Пользуемся только стандартным JavaAPI. Никакие процессингы тут не нужны. Учимся все-таки... val w = 512; val h = w; // квадрат 512x512 val image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB) val g = image.getGraphics()   var α = 0.0; var x = 0; var y = h/2; // координаты. внимание, α - альфа. сохраняйте исходник в UTF-8.   def draw(cmd:String, length: Int) { // Используем match cmd foreach (i => i match { case 'F' => { g.setColor(Color.red) val x2 = (x + length*cos(α)).toInt val y2 = (y + length*sin(α)).toInt g.drawLine(x, y, x2,y2) x = x2; y = y2; } case '+' => α += 0.5*Pi case '-' => α -= 0.5*Pi } ) } // вспомогательная функция генератор цепочки команд def generate(s:String, level:Int, f:(String)=>String ):String = { if (level > 0) generate(f(s), level-1, f) else s }   // функция создающая новые команды, на базе старых def next(x:String): String = { var result = new StringBuilder() // используем match x.foreach(p=> p match { case 'F' => result ++= "F+F-F-FF+F+F-F" case i => result +=i } ) result.toString } // рисуем с шагов 2 пикселя цепочку команда 4 поколения. draw(generate("F", 4, next), 2) // сохраняем в файл ImageIO.write(image, "png", new File("koch.png")) } }

Продолжение следует...

Блог о программировании

Февраль 14, 2011

 

Netbeans Scala Maven

Если вам приходилось работать в связке Netbeans 6.9.1 + Scala + Maven, то вы могли заметить, что компиляция происходит сильно медленнее, чем если бы вы НЕ использовали maven-scala-plugin.
Дело в том, что по умолчанию компиляция запускается в режиме "компилировать все классы". Такое поведение можно изменить, указав в настройках для recompileMode значение modified-only (компилировать только измененные). По-умолчанию оно all.
В некоторых случаях перевод в режим modified-only удобен, например если ваша задача не выпуск финальной версии продукта, а работа над определенным куском кода в режиме "написал, нажал Shift-F6, посмотрел что получилось...".
Внимание! Перевод recompileMode в режим modified-only может привести к нежелательным последствиям и побочным эффектам. Как говорится, не уверен - не обгоняй (а уверен - обгоняй).

Пример возможной (но далеко не оптимальной) модификации pom.xml.

<plugin> <groupId>org.scala-tools</groupId> <artifactId>maven-scala-plugin</artifactId> <configuration> <recompileMode>modified-only</recompileMode> </configuration> </plugin>

Блог о программировании

Февраль 2, 2011

 

Принцип работы FFT и Scala

Разбор алгоритма быстрого преобразования фурье (он же Fast Fourier transform, он же FFT).

Целью публикации является отобразить суть алгоритма, а не создание быстрой по скорости работы реализации.
Т.к. в этой программе я буду интенсивно использовать объекты вместо примитивных типов, а также рекурсию,
скорость работы будет заведомо уступать многим другим реализациям FFT, которые можно сейчас найти
в интернете в огромном количестве в открытом доступе.

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

Для начала вернёмся к определению комплексных чисел:

/* * Автор: Лигай Виталий vit@programmisty.com * Author: VITALIY LIGAY */ import scala.math._   class Complex (val x: Double, val y: Double) {   def +(c : Complex) = new Complex(x + c.x, y + c.y) def -(c : Complex) = new Complex(x - c.x, y - c.y) def *(c : Complex) = new Complex(x * c.x - y*c.y, y*c.x + x * c.y) def /(c : Complex) = new Complex( (x * c.x - y*c.y) / (c.x * c.x + c.y*c.y) , (y * c.x - x * c.y)/ (c.x * c.x + c.y*c.y))   // sqrt(x*x + y*y) def abs() = hypot(x, y) def abs2() = x*x + y*y override def toString() = x + "+i" + y }

Эта такая преамбула, теперь возьмем выжимку из русской википедии относительно принципа работы FFT.

Кстати, подробную реализацию FFT на java я нашел здесь.

/* * Автор: Лигай Виталий vit@programmisty.com * Author: VITALIY LIGAY */ import scala.math._;   object FFT {   def fft(x : Array[Complex]) : Array[Complex] = { val N = x.length if (N % 2 != 0) { throw new RuntimeException("N должно делится на 2. В этом изюминка метода.") } // результат преобразования val y = new Array[Complex](N) if (N > 2) { // четная половина val half = new Array[Complex](N/2) for (n <- 0 until N/2) { half(n) = x(2*n) } val y0 = fft(half)   // нечетная половина for (n <- 0 until N/2) { half(n) = x(2*n + 1) } val y1 = fft(half)   val ω = -2*Pi/N for (m <-0 until N/2) { // -i*2πk/N. Особая благодарность формуле Эйлера: http://en.wikipedia.org/wiki/Euler%27s_formula val exp = new Complex(cos(ω*m), sin(ω*m)) y(m) = y0(m) + exp * y1(m) y(m + N/2) = y0(m) - exp * y1(m) } } else { // для двух элементов y(0) = x(0) + x(1) y(1) = x(0) - x(1) } y }   // выводим содержимое массива def show(x :Array[Complex], title: String) { println(title); println("-------------------"); for (i <- 0 to x.length - 1) { printf("%f %n", x(i).abs); } println(); }   def main(a: Array[String]) = { val N = 16; val x = new Array[Complex](N);   // я - волна, обычная волна... val step = 2*Pi/N; for (i <- 0 to N-1) { x(i) = new Complex(cos(i*step), sin(i*step)); } show(x, "x"); // val y = fft(x); show(y, "y"); } }

P.S.: Эта первая реализация, которая пришла в голову, многое можно упростить. Будут идеи - пишите.

Java на habrahabr

Январь 26, 2011

 

JAVA / Немного мыслей о будущем платформы Java

Захотелось попробовать развить здесь одну любопытную дискуссию, которая была начала тема в комментах к будущему подкасту Радио-Т (кстати сами подкасты бывают иногда интересны), но тут же заглохла из-за отсутствия кворума.

Дискуссия о, собственно, будущем Java как языка, и как платформы.
Если вкратце — что могут сделать те, кто направляет развитие Java, чтобы удержать ее на плаву в течении долгого времени. По ссылке выше обсуждение пошло было в сторону того, почему в лабораториях Microsoft Research более или менее активно разрабатываются альтернативные языки для платформы .NET (такие, например, как F#), а вот Sun/Oracle с такой поддержкой альтернативным языкам отстают.

Блог о программировании

Декабрь 30, 2010

 

Поиск. КПМ-алгоритм

Недавно на досуге решил написать алгоритм КПМ  (КнутаМорриса — Пратта) для Scala.

Изначально, мне нужно было решить простенькую задачку - найти последовательность байт в потоке байте. Сделал на Java. Потом, решил сделать тоже самое на Scala. Занятно то, что в стандартной библиотеке Scala используется именно КПМ.

Вот мой вариант.

object KPM {   def search(source: Seq[Any], m:Seq[Any]): Int = { // вычисляем значение префикс-функции val p = prefix(m) // длина строки которую ищем (вообще не обязательно строки) val length = m.size // кол-во совпадений var k = 0 // позиция от начала var i = 0 val it = source.iterator // перебираем все элементы while (it.hasNext && k < length) { // тек. элемент val current = it.next // pos - позиция тек. элемента в списке while (k > 0 && current != m(k)) { k = p(k - 1) }   if (current == m(k)) { // еще одно совпадение k +=1 } // следующая буква i+=1 } // всё совпало if (k == length) { i - length } else { -1 } }   // префикс-функция def prefix(s: Seq[Any]):Array[Int] = { val p = new Array[Int](s.size); p(0)=0 for (i <- 1 to s.size-1) { // длина предыдущего префикса var length = p(i - 1) while (length > 0 && s(i) != s(length)) { length = p(length - 1) } if (s(length) == s(i)) length += 1 p(i)=length; } return p; }   def main(arr : Array[String]) = { val s = "abacaba" val m = "aca" val list = s.toList println(search(s, m)) println(s.indexOf(m)) } }

Чтобы разобраться в том как работает алгоритм, надо понять что такое префикс-функция.

Что же такое вообще префикс и суффикс?
Если грубо префикс - это подстрока, которая начинается с первого символа. Для строки "happy", строки ha, happ, h будут являться префиксами.

Суффикс, это как префикс, только с последним символом. Например, для строки "happy", строки "appy", "y"  будут суффиксами.

Префикс и суффиксы, которые совпадают со всей строкой целиком нас не интересуют.

Теперь введем понятие префикс-функции. Префикс-функции от строки — длина наибольшего префикса, который не совпадает с этой строкой и одновременно является её суффиксом. Если более простым языком, длина самого большого префикса, который также является и суффиксом (естественно, не совпадает со всей строкой).  А если еще проще, длина самых больших одинаковых кусков спереди и сзади строки.

Например.

pi("abacaba") = 3 pi("aba") = 1 pi("ab") = 0

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

Например для abacaba, Pi("abacaba",i)

"a":0
"ab":0
"aba":1
"abac":0
"abaca":1
"abacab":2
"abacaba":3

получаем P("abacaba") =0010123

Ну а потом читаем википедию

Блог о программировании

Октябрь 20, 2010

 

Читерство в NetBeans. Ввод и использования мат. символов и букв греческого алфавита .

Оригинальная идея взята из поста Gabriel's software development blog. Статья в довольно старая, еще в прошлом году опубликованная.

Если коротко:

val Π = Math.Pi
def √(x:Double)=Math.sqrt(x)
val x= √(9*Π)
def ∑(r:Range)(f:Int =>Int)=r.reduceLeft(_+ f(_))
def ∏(r:Range)(f:Int =>Int)=r.reduceLeft(_* f(_))

val s= ∑(1 to 100)(x=>x^2)

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

В итоге случайно недавно придумал как это можно сделать просто и удобно средствами IDE, а точнее в NetBeans.

Просто я вбил все нужные мне символы в Code Templates (Tools → Options → Editor → Code Templates) и сделал два макроса для [Alt+<] = "→" и [Alt+<] = "⇒".

Как это работает можно посмотреть здесь:

http://www.youtube.com/watch?v=mVz6DyZrzms

То есть вы вводите например alpha и жмете [Tab] и затем вставляется α. Самое главное, это настраивается только например для Scala, таким образом это не мешает при работе на других языках. Также если вы хотите написать просто alpha, вы просто не нажимайте [Tab] и всё!

P.S.: На самом вбивать весь греческий алфавит довольно скучное занятие, можно найти файл вроде этого:

C:\Documents and Settings\<USER_NAME>\.netbeans\6.9\config\Editors\text\x-scala\CodeTemplates\org-netbeans-modules-editor-settings-CustomCodeTemplates.xml

и сгенерить все аббревиатуры.

Вот пример моего файла - CustomCodeTemplates.zip. Внимание! Это только пример, возможно он Вам не подойдет.

Будьте аккуратны, перед обновлением сделайте резервную копию!

Блог о программировании

Октябрь 11, 2010

 

Магия унарных операторов в Scala (unary_)

Многие знают, что в Scala возможна перегрузка операторов.

К примеру, пусть у нас будет класс - двухмерная точка:

class Point(val x: Double, val y: Double) {   def -(p: Point) = new Point(x-p.x, y-p.y); def +(p: Point) = new Point(x+p.x, y+p.y);   }

Работать с ней приятно:

val p1 = new Point(2,2); val p2 = new Point(1,1); val p = p2 - p1;

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

val p = new Point(2,2); val antiP = -p;

Конечно, вы можете попробовать сделать так:

// ТАК ДЕЛАТЬ НЕ НАДО! def -() = new Point(-x,-y);

Такой код конечно скомпилируется, но тогда и пользоваться им придется следующим образом:

val antiP = p-;

Что же делать?
Этот случай в спецификации языка Scala описан в разделе 6.12.1 Prefix Operations.
В таких ситуациях следует использовать магическую фразу "unary_"!
Она работает только для четырех операторов: -, +, ~, !.

Таким образом, дополнив нашу точку следующим методом:

class Point(val x: Double, val y: Double) { def unary_-() = new Point(-x,-y); def -(p: Point) = new Point(x-p.x, y-p.y); def +(p: Point) = new Point(x+p.x, y+p.y); }

Мы можем делать следующие вещи:

val antiP = -p;

Таким образом оператор стал префиксным.

Ради научного интереса Вы можете переопределить еще парочку операторов, например !p - получить точку симметричную относительно оси Y, ~p - относительно оси X, создав таким образом целый "зоопарк" прикольных операторов.

  class Point(val x: Double, val y: Double) {   // !p | p // --------- // -p | ~p def unary_-() = new Point(-x,-y); def unary_!() = new Point(-x,y); def unary_~() = new Point(x,-y);   def -(p: Point) = new Point(x-p.x, y-p.y); def +(p: Point) = new Point(x+p.x, y+p.y); }

Конечно можно еще для полноты ощущений перегрузить унарный плюс (unary_+), но это на любителя.

Что касается других операторов (кроме -,+,~,!), то на них "unary_" не действует. Например можно конечно сделать метод unary_*, но автоматически становится префиксным он не будет. Другими словами вызов *p - не сработает, а сработает только p.unary_*(). Думаю, это не то, что вам хотелось.
Кстати, работает как -p, так и p.unary_-(). Метод unary_-() никуда не делся, просто у нас в добавок к нему появился еще один более простой способ его вызвать.

Блог о программировании

Октябрь 4, 2010

 

Практикум по программированию на Java и Scala. Занятие №4.

Продолжаю вести практикум по программированию на Java и Scala.

Сегодня было четвертое занятие. Я уже стал многих студентов узнавать в лицо. В среднем на занятия приходит около 25 человек. Аудиторию нам дали хорошую, есть проектор, и вроде неплохие компьютеры. На них уже был установлен Eclipse  или NetBeans. Правда все равно студентов больше чем компьютеров, так что многим приходится работать в лучших традициях eXtreme Programming -- вдвоем, а иногда и втроем за одним компьютером.  Некоторые приносят свои ноутбуком, что сильно спасает ситуацию.

Как-то упустил из виду процесс согласования программы, предварительно договаривались о семестровом двухпарном или годовом однопарном, а в итоге получился семестровый однопарный. Так что приходится сильно стараться чтобы уложится в семестр. Из теории стараюсь передать самую суть и больше времени уделить практическим занятиям. Во-первых сам курс называется "практикум", а во-вторых теорию можно узнать из документации, спецификаций и разных книжек, а вот так чтобы в режиме реального времени написать/запустить/спросить почему не работает/узнать где и что не так,  можно далеко не везде и не всегда. Разве что на работе, но там как правило более жесткий и циничный подход к людям.

На прошлом занятии поигрались с циклами, условными переходами и приступили к освоению ООП в Java. Закончил занятие тем, что пытался объяснить, что такое interface и множественное наследование. Кажется студентам оно не понравилось.

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

Сегодня рассказывал про ввод-вывод (java.io). NIO трогать не стал, только путать. Для наглядности, показал картинку из матрицы и сказал, что поток (stream) - это как поток воды, только из байт.

После небольшой вводной про потоки и их методы приступили к практическим занятиям.

С помощью OutputStream, а точнее FileOutputStream записали строку "hello world" в файл. Затем получили содержимое этого файла.

Потом скопировали содержимое одного файла в другой.

Потом я попросил сделать копирования файлов с использованием буфера - массива байт

(т.е. создаем byte[] buff = new byte[LENGTH], и через is.read(buff) и os.write(buff,0,length) копируем в цикле весь файл).

Потом рассказал  про BufferedInputStream и BufferedOutputStream...

Затем мы использовали ZipOutputStream и сделали zip-архив.

Я очень хотел на этих примерах раскрыть ООП-ность подхода работы с потоками -- есть абстрактный класс OutputStream и много разных его реализаций, которые и в файл записывать могут, и в массив байт, и буферизовывать вывод, и даже шифровать.

Вот здесь произошла небольшая заминка,  я планировал рассказать как использовать CipherOutputStream и зашифровать что-нибудь на основе password-based encryption. Но как оказалось времени осталось мало и не хотелось грузить такой сложной информацией, в общем мы приступили к обработке исключений, поскольку они при работе с IO возникают везде, да и в принципе нужно знать что это такое.

Я показал что такое try,catch, throws, finally. Рассмотрели простые примеры. Затем я рассказал про Throwable, Exception, Error, RuntimeException. Кто от кого наследуется и для кого нужно указывать throws.

Исключения студентам понравились, боюсь как бы они не стали использовать не в тех местах (то есть повсюду)... Надо будет в следующий раз рассказать о "темной стороне" работы с ними.

На следующем занятии начну работу с сетью. Задача минимум - URL, сокеты,  а так может еще запустим Tomcat, расскажу про Reader/Writer, сделаем простенький сервлет. Потом останется рассказать про базы данных и всякие интересный плюшки типа GWT (хотя сейчас думаю что может и не стоит об этой Google-овой технологии рассказывать), а затем Scala! Вот тут начнется самое интересное - паттерн_матчинг, миксинги, перегрузка операторов...

 
<< < 2 из 2 > >>