код Kotlin & Java

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 02 июн 2017, 17:45

Olej писал(а): После трансформации оба файла, и Complex.kt (который был мной взят где-то из публичной библиотеки в Интернет) и poly.kt (который написан под задачу) содержат синтаксические ошибки (с точки зрения семантики Kotlin).
Ошибки в poly.kt как-то связаны с конструктором Double, который "определён в kotlin.Double" и, нужно думать, отличается от определений в Java.
Это, насколько я понял, связано с тем, что в преобразованных выражениях по типу:

Код: Выделить всё

     val x = Double(st.nextElement() as String).toDouble()
... здесь Double совпадает по написанию с базовым типом Kotlin, а в исходном коде имелась в виду Java обёртка Double для примитивного типа JVM double. Теперь тип для x должен бы быть Double? ...
Со всем этим буду разбираться по (переводу) документации Kotlin здесь: Основные типы.

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 02 июн 2017, 19:26

Olej писал(а): ... здесь Double совпадает по написанию с базовым типом Kotlin, а в исходном коде имелась в виду Java обёртка Double для примитивного типа JVM double. Теперь тип для x должен бы быть Double? ...
Со всем этим буду разбираться по (переводу) документации Kotlin здесь: Основные типы.
Удалось это победить, заменив показанные комментированные строки но новые не комментированные:

Код: Выделить всё

//                    val x = Double(st.nextElement() as String).toDouble()
                    val x: Double? = (st.nextElement() as String).toDouble()
//                    val y = Double(st.nextElement() as String).toDouble()
                    val y: Double? = (st.nextElement() as String).toDouble()
//                    polygon.add(Complex(x, y))
                    polygon.add(Complex(x!!, y!!))
Читаем о всём этом здесь: Nullable типы и Non-Null типы:
- меняем типы x & y на Nullable Double? (обёртка Java Double);
- но трансформация Complex определила конструктор как:

Код: Выделить всё

    /**
     * Create a complex number initially equal to x + iy
     */
    constructor(x: Double, y: Double) {
        re = x //.toDouble()
        im = y //.toDouble()
    }
- он требует Non-Null и не допустит Nullable тип Double?
- не желая менять автоматически сгенерированный класс Complex ...
- используем оператор !! (описано там же):

Код: Выделить всё

   polygon.add(Complex(x!!, y!!))
Теперь всё компилируется и успешно выполняется ... аналогично исходному приложению на Java!
Вложения
k3.png

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 02 июн 2017, 20:07

Olej писал(а): Теперь всё компилируется и успешно выполняется ... аналогично исходному приложению на Java!
При запуске (Run) собранного в IDEA проекта, там печатается полная строка запуска (скопируем)...
В каталоге собранного проекта:

Код: Выделить всё

[olej@dell triangle]$ pwd
/home/olej/IdeaProjects/triangle/out/production/triangle

[olej@dell triangle]$ ls 
Complex.class  Complex$Companion.class  poly.class  Polygon.class
Это собранные IDEA .class для JVM.
Из этого каталога $HOME/IdeaProjects/$PROECT/out/production/$PROECT запускаю в терминале приложение в JVM:

Код: Выделить всё

[olej@dell triangle]$ /usr/lib/jvm/java-1.8.0-openjdk/bin/java -javaagent:/home/olej/idea-IC-171.4424.56/lib/idea_rt.jar=42979:/home/olej/idea-IC-171.4424.56/bin -Dfile.encoding=UTF-8 -classpath /usr/lib/jvm/java-1.8.0-openjdk/jre/lib/charsets.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/cldrdata.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/dnsns.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/jaccess.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/localedata.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/nashorn.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/sunec.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/sunjce_provider.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/sunpkcs11.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/zipfs.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/jce.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/jsse.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/management-agent.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/resources.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/rt.jar:/home/olej/IdeaProjects/triangle/out/production/triangle:/home/olej/.IdeaIC2017.1/config/plugins/Kotlin/kotlinc/lib/kotlin-runtime.jar:/home/olej/.IdeaIC2017.1/config/plugins/Kotlin/kotlinc/lib/kotlin-reflect.jar poly
координаты вершин в формате: X Y
вершина № 1 : 0 0
вершина № 2 : 0 1
вершина № 3 : 1 0
вершина № 4 : 
вершин 3 : [0.0,0.0] [0.0,1.0] [1.0,0.0] 
периметр = 3.414213562373095
площадь = 0.5
---------------------------------
координаты вершин в формате: X Y
вершина № 1 : завершение работы
Вот это и есть готовое приложение!
Вложения
Complex.kt
(7.73 КБ) 86 скачиваний
poly.kt
(3.16 КБ) 91 скачивание

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 02 июн 2017, 20:16

Olej писал(а):

Код: Выделить всё

[olej@dell triangle]$ /usr/lib/jvm/java-1.8.0-openjdk/bin/java -javaagent:/home/olej/idea-IC-171.4424.56/lib/idea_rt.jar=42979:/home/olej/idea-IC-171.4424.56/bin -Dfile.encoding=UTF-8 -classpath /usr/lib/jvm/java-1.8.0-openjdk/jre/lib/charsets.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/cldrdata.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/dnsns.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/jaccess.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/localedata.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/nashorn.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/sunec.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/sunjce_provider.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/sunpkcs11.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/zipfs.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/jce.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/jsse.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/management-agent.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/resources.jar:/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/rt.jar:/home/olej/IdeaProjects/triangle/out/production/triangle:/home/olej/.IdeaIC2017.1/config/plugins/Kotlin/kotlinc/lib/kotlin-runtime.jar:/home/olej/.IdeaIC2017.1/config/plugins/Kotlin/kotlinc/lib/kotlin-reflect.jar poly
Вот это и есть готовое приложение!
Сотрудники компании JetBrains (разработчика) подсказали:
всё, что начинается с /usr/lib/jvm/java-1.8.0-openjdk/, можно пропустить

Код: Выделить всё

[olej@dell triangle]$ java -javaagent:/home/olej/idea-IC-171.4424.56/lib/idea_rt.jar=42979:/home/olej/idea-IC-171.4424.56/bin -Dfile.encoding=UTF-8 -classpath /home/olej/IdeaProjects/triangle/out/production/triangle:/home/olej/.IdeaIC2017.1/config/plugins/Kotlin/kotlinc/lib/kotlin-runtime.jar poly
координаты вершин в формате: X Y
вершина № 1 : 
завершение работы

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 02 июн 2017, 21:00

Теперь сравним эквиваленты (более того, сгенерированные автоматически!) кода на Java и кода на Kotlin, выполняющиеся на одной и той же Java виртуальной языковой машине JVM (сами файлы прикреплены к сообщениям ранее):

- poly.java (было):

Код: Выделить всё

import java.io.*;
import java.util.*;
import java.lang.Double.*;

class Polygon extends ArrayList<Complex> {        // class Complex заимствуется из отдельного файла 
   public String toString()  {
      String ret = "";
      for( int i = 0; i < size(); i++ ) 
         ret += "[" + ( new Double( get( i ).re ) ).toString() + "," +
                      ( new Double( get( i ).im ) ).toString() + "] ";
       return ret;
   }
   public double perimeter() {
      double summa = 0.0;
      for( int i = 0; i < size(); i++ ) 
         summa += get( i ).minus( i != size() - 1 ? get( i + 1 ) : get( 0 ) ).r();
      return summa;
   }
   public double square() {
      double summa = 0.0;
      for( int i = 1; i < size() - 1; i++ ) {
         Complex side1 = get( i ).minus( get( 0 ) ),
                 side2 = get( i + 1 ).minus( get( 0 ) );
         summa += side1.r() * side2.r() *
                  Math.abs( Math.sin( side1.theta() - side2.theta() ) ) / 2.; 
      }
      return summa;
   }
} 

public class poly {
   public static void main( String[] args ) {
      Scanner in = new Scanner( System.in );      // создание объекта чтения из стандартного потока ввода
      while( true ) { 
         System.out.println( "координаты вершин в формате: X Y" );
         Polygon polygon = new Polygon();
         String coord = ""; 
         while( true ) { 
            System.out.printf( "%s%d%s", "вершина № ", polygon.size() + 1, " : " );
            try { coord = in.nextLine(); }        // чтение строки из консоли
            catch( java.util.NoSuchElementException ex ) {
               System.out.println( "завершение работы" );
               System.exit( 0 );                  // EOF: ^D
            }
            if( 0 == coord.length() ) 
               if( polygon.size() != 0 ) break;   // завершение многоугольника
               else {
                  System.out.println( "завершение работы" );
                  System.exit( 0 );
               }
            try {                                 // выделение координат
               StringTokenizer st = new StringTokenizer( coord, " \t\n" );
               double x = ( new Double( (String)st.nextElement() ) ).doubleValue(),
                      y = ( new Double( (String)st.nextElement() ) ).doubleValue();
               polygon.add( new Complex( x, y ) );
            }
            catch( java.util.NoSuchElementException ex ) {
               System.out.println( "ошибка ввода!: " + ex.toString() ); 
               continue;
            }
            catch( java.lang.NumberFormatException ex ) {
               System.out.println( "ошибка формата!: " + ex.toString() ); 
               continue;
            }
         }
         System.out.println( "вершин " + polygon.size() + " : " + polygon );
         System.out.println( "периметр = " + polygon.perimeter() );
         System.out.println( "площадь = " + polygon.square() );
         System.out.println( "---------------------------------" );
      }
   }
}   
- poly.kt (стало):

Код: Выделить всё

import java.io.*
import java.util.*
import java.lang.Double.*

internal class Polygon : ArrayList<Complex>() {        // class Complex заимствуется из отдельного файла
    override fun toString(): String {
        var ret = ""
        for (i in 0..size - 1)
            ret += "[" + get(i).re.toString() + "," +
                    get(i).im.toString() + "] "
        return ret
    }

    fun perimeter(): Double {
        var summa = 0.0
        for (i in 0..size - 1)
            summa += get(i).minus(if (i != size - 1) get(i + 1) else get(0)).r()
        return summa
    }

    fun square(): Double {
        var summa = 0.0
        for (i in 1..size - 1 - 1) {
            val side1 = get(i).minus(get(0))
            val side2 = get(i + 1).minus(get(0))
            summa += side1.r() * side2.r() *
                    Math.abs(Math.sin(side1.theta() - side2.theta())) / 2.0
        }
        return summa
    }
}

object poly {
    @JvmStatic fun main(args: Array<String>) {
        val `in` = Scanner(System.`in`)      // создание объекта чтения из стандартного потока ввода
        while (true) {
            println("координаты вершин в формате: X Y")
            val polygon = Polygon()
            var coord = ""
            while (true) {
                System.out.printf("%s%d%s", "вершина № ", polygon.size + 1, " : ")
                try {
                    coord = `in`.nextLine()
                }        // чтение строки из консоли
                catch (ex: java.util.NoSuchElementException) {
                    println("завершение работы")
                    System.exit(0)                  // EOF: ^D
                }
                if (0 == coord.length)
                    if (polygon.size != 0)
                        break   // завершение многоугольника
                    else {
                        println("завершение работы")
                        System.exit(0)
                    }
                try {                                 // выделение координат
                    val st = StringTokenizer(coord, " \t\n")
                    val x: Double? = (st.nextElement() as String).toDouble()
                    val y: Double? = (st.nextElement() as String).toDouble()
                    polygon.add(Complex(x!!, y!!))
                } catch (ex: java.util.NoSuchElementException) {
                    println("ошибка ввода!: " + ex.toString())
                    continue
                } catch (ex: java.lang.NumberFormatException) {
                    println("ошибка формата!: " + ex.toString())
                    continue
                }
            }
            println("вершин " + polygon.size + " : " + polygon)
            println("периметр = " + polygon.perimeter())
            println("площадь = " + polygon.square())
            println("---------------------------------")
        }
    }
}

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 02 июн 2017, 21:09

Olej писал(а):Теперь сравним эквиваленты
Это практически "подстрочный" перевод ;-) :

Код: Выделить всё

[olej@dell triangle.java]$ wc -l poly.java
75 poly.java

[olej@dell triangle]$ wc -l poly.kt
79 poly.kt
Но! - это механический перевод (посмотрели как это делается)...
Тем не менее:
- в Kotlin есть целый ряд конструкций высокого уровня, которых нет в Java и близко...
- но не это даже главное - Kotlin спроектирован для надёжного контроля объектов Nullable типов, не имеющих возможности возбуждать NullPointerException исключение!

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 02 июн 2017, 23:07

Olej писал(а): - в Kotlin есть целый ряд конструкций высокого уровня, которых нет в Java и близко...
Дальше меня интересует именно тестирование таких конструкций ... по крайней мере, самых интересных.
Описания синтаксиса/семантики черпаем здесь:
Reference - оригинальная документация
Руководство по языку Kotlin - перевод этой документации

Но прежде разбираемся с терминальной (CLI) сборкой.
На примере простейшей программы:

Код: Выделить всё

fun main(args: Array<String>) {
    println("Hello, World!")
}
Потому что:
- мне совершенно нет нужды в могучей среде IDEA для простейших тестов ... хотелось бы использовать простейшую терминальную сборку;
- привязка инструмента (в данном случае языка Kotlin) к реализации (в данном случае среда разработки IDEA) - плохая идея, и здесь как-раз случай проверить что это не так;

Варианты сборки (и запуска), они мне все пригодятся ;-) ...

1. То, что описано в README - сборка всего в архив jar:

Код: Выделить всё

[olej@dell tests]$ kotlinc test_fun.kt -include-runtime -d test_fun.jar

[olej@dell tests]$ java -jar test_fun.jar
Hello, World!

[olej@dell tests]$ ls -l test_fun.jar 
-rw-rw-r-- 1 olej olej 865731 июн  2 23:14 test_fun.jar
2. Сборка в .class :

Код: Выделить всё

[olej@dell tests]$ kotlinc test_fun.kt -include-runtime -d xxx

[olej@dell tests]$ tree xxx
xxx
├── META-INF
│   └── main.kotlin_module
└── Test_funKt.class

1 directory, 2 files

[olej@dell tests]$ ls -l xxx/Test_funKt.class 
-rw-rw-r-- 1 olej olej 972 июн  2 22:35 xxx/Test_funKt.class
Обратите внимание на размер!
Но при этом гораздо усложняется запуск приложения:

Код: Выделить всё

[olej@dell tests]$ which kotlinc
~/.sdkman/candidates/kotlin/current/bin/kotlinc

[olej@dell kotlin]$ ls -l  ~/.sdkman/candidates/kotlin/
итого 4
drwxr-xr-x 1 olej olej 44 апр 27 19:33 1.1.2-2
lrwxrwxrwx 1 olej olej 44 май 25 12:31 current -> /home/olej/.sdkman/candidates/kotlin/1.1.2-2

Код: Выделить всё

[olej@dell tests]$ pwd
/home/olej/2017_WORK/own.WORK/Kotlin/tests

[olej@dell tests]$ java -classpath $HOME/.sdkman/candidates/kotlin/1.1.2-2/lib/kotlin-runner.jar:xxx Test_funKt
Hello, World!
Или так:

Код: Выделить всё

[olej@dell tests]$ cd xxx

[olej@dell xxx]$ pwd
/home/olej/2017_WORK/own.WORK/Kotlin/tests/xxx

[olej@dell xxx]$ java -classpath $HOME/.sdkman/candidates/kotlin/1.1.2-2/lib/kotlin-runner.jar:./ Test_funKt
Hello, World!
Вложения
test_fun.kt
(65 байт) 83 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 02 июн 2017, 23:29

Olej писал(а): На примере простейшей программы:

Код: Выделить всё

fun main(args: Array<String>) {
    println("Hello, World!")
}
Здесь уже вылезает радикальное отличие от Java - функции Kotlin могут быть вне класса! Стартовую функцию main() не нужно как статический метод заворачивать в фиктивный класс.
Т.е. доведенная до абсурда объектность Java здесь ослаблена.

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 03 июн 2017, 13:28

Olej писал(а):
Olej писал(а): - в Kotlin есть целый ряд конструкций высокого уровня, которых нет в Java и близко...
Дальше меня интересует именно тестирование таких конструкций ... по крайней мере, самых интересных.
Тестирую функции (и функции-методы), как наиболее сильно отличающуюся часть...
Но для начала сделаю тестовое приложение, в которое я смогу в произвольном количестве дописывать тестируемые функции (или фрагменты кода).
Вот как-то так:

Код: Выделить всё

import java.lang.Math.*
import java.util.Scanner.*

fun tg( x: Double ): Double = sin( x ) / cos( x ); // функция - одиночное выражение

fun test1(): Unit {
    printHello( "Kotlin" )
    printHello( null )
    // `return Unit` или `return` необязательны
}

fun printHello(name: String?): Unit {
    if (name != null)
        println("Hello ${name}")
    else
        println("Hi there!")
}

fun main( args: Array<String> ) {
    val tests: Array< ()->Unit > = arrayOf(
            { println( tg( 1.0 ) ); },
            { test1() }
    )
    if(args.size == 0)
        for (f in tests)
           f()
    else
        for (i in args.indices) {
           try {
                val x = args[i].toInt()
                if(x <= 0 || x > tests.size) {
                    println("ошибка размера!: " + args[i])
                    continue
                }
                println( x.toString() + " ------------------------------------------" )
                tests[ x - 1 ]()
            } catch (ex: java.lang.NumberFormatException) {
                println("ошибка формата!: " + args[i])
            }
        }
}
Это компилируется и выполняется так:

Код: Выделить всё

[olej@dell tests]$ make test_fun.jar
kotlinc test_fun.kt -include-runtime -d test_fun.jar

[olej@dell tests]$ java -jar test_fun.jar 0 1 2
ошибка размера!: 0
1 ------------------------------------------
1.557407724654902
2 ------------------------------------------
Hello Kotlin
Hi there!

[olej@dell tests]$ java -jar test_fun.jar 
1.557407724654902
Hello Kotlin
Hi there!
- если запуск без параметров - последовательно выполняются все тесты из массива функций tests
- если запуск с числовыми порядковыми номерами тестов - выполняются только эти тесты
- если параметр не число или выходит за пределы наличествующих тестов - диагностируется ошибка
Дальше это даст мне возможность, при тестировании какой-то возможности функций, показывать только код этой функции (вставленной в массив tests) + результат её выполнения... а не тянуть весь накопленный код для всех тестов.
Вложения
test_fun.kt
(1.16 КБ) 88 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: код Kotlin & Java

Непрочитанное сообщение Olej » 03 июн 2017, 13:43

Olej писал(а): Вот как-то так:
Уже пока писался этот тест (и изучался по каждому поводу синтаксис-семантика языка) по нему (по сравнению с Java "по аналогии") можно сделать некоторые выводы:
- все объявления (переменные, константы, параметры функций и др.) сделаны в стиле Pascal / Modula / Go, а не C / C++ / Java

Вообще, очень и очень много конструкций заимствовано из Go:
- порядок объявлений
- лябда / анонимные функции, функциональные замыкания ... и вообще всё, что связано с функциональным программированием
- множественные возвращаемые значения

В каком-то смысле, Kotlin продолжает (развивает) языковую линию Java / Scala ровно в том направлении, в каком Go продолжает (развивает) языковую линию C / C++ !

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 4 гостя