Pull to refresh

Comments 68

Лично меня от попыток миграции останавливает такая простая вещь,
как баги в maven (по большей части видел в плагинах, типа MJAR-249).

Ну т.е., не у вас одного сломалось, разработчики maven тоже вынуждены были фиксить кое-что. И это нехороший признак — никогда на моей памяти новая версия JDK не ломала системы сборки.
>Ничего просто не соберётся
А вы чем собираете? У меня с Maven проблем не было, всё собирается, я даже ни каких module-info.java не добавлял. И в зависимостях куча древних JAR-ов. И в проекте ничего не менял, всё стандартно по мавенскому шаблону.

>Это обычно нужно, чтобы понять, где искать файлы приложения — конфигурацию, плагины и т.п.
У приложения должен быть константный каталог в user.home с нужной конфигурацией. Если хотите узнать о текущем процессе больше, то появился новый API ProcessHandle.

>Files.readAllLines("/etc/mime.types", Charset.defaultCharset())
Проверил — у меня работает.
>Ничего просто не соберётся

Это про модульные приложения. Обычные на JAR'ах и CLASSPATH'ах соберутся. Точнее, соберутся не хуже чем в 9 (там тоже понаполомали).

У приложения должен быть константный каталог в user.home с нужной конфигурацией.

Угу, а статические конфиги всякие, плагины, ресурсы и прочую муть? А если у меня «portable» (а у меня именно так)?
В папке приложения теперь может быть только один файл? Простите, но это глупо. А ProcessHandle вернёт вам совершенно не то — файл может быть запущен разными способами, включая запуск из всяких «запускальщиков».

>Files.readAllLines("/etc/mime.types", Charset.defaultCharset())
Проверил — у меня работает.

Проверили эту строчку или «Files.readAllLines(»/etc/mime.types", Charset.defaultCharset())"? Падает в недрах JRE.
>а статические конфиги всякие
/etc/app.name

>плагины
Обычно в user.home/app.name, можно в /usr/lib/app.name Можно даже в /usr/lib/jvm

>ресурсы и прочую муть
Обычно пакуется в JAR

>файл может быть запущен разными способами, включая запуск из всяких «запускальщиков»
Если вам нужны подобные хаки, то гуглите новые хаки для 10-ки, если старые перестали работать.

>Проверили эту строчку или
Не нашел, чем у вас там строчка отличается. Просто скопировал, код из статьи в IDE и всё.
У вас точно кросс-платформенное приложение? ;) Но фактически вы предлагаете в папке программы держать ровно один файл. Я вас уверяю, что есть множество случаев, когда нужно больше. Не говоря уже о том, что подход в любом случае спорный.
Один JAR — снова, вы вводите искусственные ограничения.
Простой пример — приложение под Windows взаимодействует с другими исполняемыми файлами, которые оно же устанавливает. Или приложение сильно модульное, где набор модулей задаётся на этапе установки. И ещё 1001 и одна ситуация.

Если вам нужны подобные хаки, то гуглите новые хаки для 10-ки, если старые перестали работать.

Хаки? Мне нужно обычное кросс-платформенное desktop GUI приложение и чтобы оно реально работало. Хаки… Тут ещё для девятки половину «хаков» не написали, а они снова поломали.
>У вас точно кросс-платформенное приложение? ;)
Да. В Windows приложение должно лежать в Program Files/app.name. И по прежнему есть user.home

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

>приложение под Windows взаимодействует с другими исполняемыми файлами
>Или приложение сильно модульное, где набор модулей задаётся на этапе установки
Для таких ситуаций делают инсталятор. И как я говорил, всё должно лежать в Program Files/app.name, в других ОС читайте инструкции, где и что должно лежать.

>Хаки? Мне нужно обычное кросс-платформенное desktop GUI приложение и чтобы оно реально работало.
Я вам предложил вариант. Он рабочий. Можете также использовать ProcessHandle API, если вы не наврнёте новых хаков на пускалку вашего JAR-а, то это API будет нормально работать.
На деле вариант оказывается не такой уж и рабочий. Чтобы получить ресурсы данного jar-файла, вам нужно знать путь к нему
stackoverflow.com/a/3923182/8238588
см. метод getResourcesFromJarFile
Эт вы из мира всяких инсталлятуров и скриптов к нам пришли. В моём случае пользователь просто распаковывает tgz и вперёд. Ну либо docker run, на худой конец.

Я не могу сказать почему отломился readAllLines в моём случае. Там происходит какая-то хрень с буферами внутри и всё разлетается. И дело не в кодировке, так как файл /etc/mime.types содержит только ASCII. Просто сам факт того, что JVM v10 подавился вполне нормальным текстовым файлом, который нормально читался в 8-й JVM и кучей других программ — говорит сам за себя.
>В моём случае пользователь просто распаковывает tgz и вперёд
И что, вы в рантайме не можете создать user.home/.app.name скопировав туда конфиги из JAR-а? И туда же устанавливать плагины, если у вас настолько простое развёртывание?

>говорит сам за себя
В 99.9% подобных багов это криворукость разработчика, а не сбой промышленной платформы с миллионами разработчиков.
Права на папку кто будет задавать? Под Win? А если два приложения на одном компьютере?

Промышленная платформа, как только мы говорим о десктоп приложениях — говно с огромными проблемами. Имею наглость так утверждать. Кроссплатформенности нет. Совместимость между версиями рушится раз в год. Базового функционала нет. Критические баги висят по пять лет.
>Права на папку кто будет задавать?
Установщик или ваше приложение в рантайме.

>А если два приложения на одном компьютере?
Продумываете где и что хранить, когда два приложения на компьютере.

>Кроссплатформенности нет.
Есть, но в разумных пределах.

>говно с огромными проблемами. Имею наглость так утверждать.
Вас никто не держит. Только на других платформах всё еще хуже.
>И что, вы в рантайме не можете создать user.home/.app.name скопировав туда конфиги из JAR-а? И туда же устанавливать плагины, если у вас настолько простое развёртывание?

Можно, конечно, но это был немного не тот случай. Просто немного печально, что больше нельзя получить путь к файлу с entry point. Требуется переписывание из-за нарушения обратной совместимости, как минимум.
Куча других программ также могут заглючить с текстовыми файлами. Выложите этот файл, я проверю у себя.
На другой машине тот же самый файл /etc/mime.types не привёл к исключению внутри JVM 10, что довольно странно

pastebin.com/6QHQH75H
Я ниже ответил, в чём проблема.
>Java, как язык программирования, начинает переживать свой упадок
Нет, здесь он начинает расцвет.

>и тогда на смену Java нужно искать другой инструмент
Т.е. искать новый инструмент и переписывать код с нуля у вас время найдётся, а почитать документацию и пофиксить недокументированные хаки баги: «Разбираться, в чём проблема времени не хватило.» ©

Именно так. У меня приложение. Я за него деньги получаю. Миграция на 9 кончилась кошмаром и переписыванием массы кода. Миграция на 10 пока прошла более-менее успешно, но не без костылей.
И я, например, отлично понимаю, когда у человека нет времени в игрушки играться. У него есть задача ему нужен инструмент, а если инструмент не работает и всё время ломается, то его нужно менять инструмент. Когда время позволяет — я копаюсь в говне. Но если у меня есть работающее, свеже-написанное приложение, а мне звонит заказчик и в панике говорит, что юзеры не могут больше скачать JRE9, то времени и желания переписывать кучу кода у меня нет — мне нужно часто и много кушать.
>то времени и желания переписывать кучу кода у меня нет
Так сидите на 8-ке, она до 2020 поддерживается. Зачем вы ринулись под 9-ку всё переписывать? На 9-ку толком никто не переходил, только с 10-ой, когда более-менее всё отшлифовалось — люди стали переползать.

>а если инструмент не работает и всё время ломается, то его нужно менять инструмент
А вы думаете где-то лучше? ) Везде так, это ИТ, куча легаси и постоянное движение впёред. И джава среди прочих инструментов еще более-менее вменяемая.
А ничего, что 8 не рекомендуется для новых разработок и все время предлагает перейти на более свежую версию, пугая пользователей. Более менее отшлифоваться оно должно было ещё до выхода релиза 9. А то получается, три год что уже мажорная версия сменилась, и две версии устаревшими объявлены, а оно всё еще «не отшлифовалось». Это как бы признак огромного кризиса и проблем в языке. Не говоря о том, что Вы, практически, предлагаете не писать десктоп приложения и коротко-живущие на Java, с чего мы и начали.
>8 не рекомендуется для новых разработок
Всё верно, зачем новую разработку начинать на устаревшей платформе? Кто так делает?

>все время предлагает перейти на более свежую версию
Не видел такого, т.е. у пользователя на Windows стоит 8-ка и Updater постоянно предлагает обновиться на 10-ку?

>Это как бы признак огромного кризиса и проблем в языке.
Нет, это перемены, необходимые для дальнейшего роста популярности JVM. Сделали, то, что давно нужно было сделать. Такие точки перелома есть везде, например Windows 98 -> Windows XP или x32 -> x64 и т.д.
Я имел ввиду — в долгосрочной перспективе. Не связываться с новыми проектами на Java, например. Ну это если я прав, а я ещё не уверен. Может всё починят всё-таки.

Про malformed input у меня было в восьмёрке ещё. Это несовпадение кодировками. У меня было когда читал в utf8 (стандартная кодировка), а в файле был иврит в какой-то ещё (iso что-то, windows что-то — не помню).

В файле вроде только ASCII. К тому же вызов изнутри явы я никак поменять не могу.
Локали там поломаны у вас. Причём, обещали именно в 10 всё сделать круто ASCII.
>К тому же вызов изнутри явы я никак поменять не могу
Можете создать свой FileTypeDetector через ServiceLoader он подгрузится и выполнится первым. То что в файле ASCII это без разницы. Там нет детектора кодировки файла, поэтому берётся Charset.defaultCharset(), вы сами это указали в статье. И видимо у вас там какой-нибудь UTF-16 возвращается и он начинает читать однобайтовую кодировку, как двухбайтовую.
Хотя сейчас глянул код defaultCharset, lookup(csn) просто выкидывает эксепшен, если у вас file.encoding == null. И там же рядом выставляет UTF-8, если не удалось детектировать кодировку по значению file.encoding, что с первого взгляда глупо (можно было бы тогда и в первом случае делать кодировку UTF-8):

                String csn = GetPropertyAction
                        .privilegedGetProperty("file.encoding");
                Charset cs = lookup(csn);
                if (cs != null)
                    defaultCharset = cs;
                else
                    defaultCharset = sun.nio.cs.UTF_8.INSTANCE;

В конечном итоге всё равно проверяется по расширению. Поэтому проще было не дёргать probeContentType а проверять расширение самому. Но использование кастомного FileTypeDetector — это слишком

Да проблема просто решается, проверяйте system properties на наличие file.encoding и если оно в null, то выставляйте в UTF-8. И тогда defaultCharset отработает без исключений и откроет mime.type файл. Можете в OpenJDK багтрекер сообщить об этой проблеме, если еще никто не сообщал.
Ок, как смогу добраться до машины, где воспроизводится, так и попробую. Однако, насколько я помню из отладчика, файерболл там вылетал из другого места.
Воспроизвёл. Код:
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.charset.Charset;

public final class Test {
        public final static void main(final String args[])
        throws Exception {
                Files.readAllLines(Paths.get("/etc/mime.types"), Charset.defaultCharset());
        }
}


Стэктрэйс:
$ java Test 
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
        at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
        at java.io.InputStreamReader.read(InputStreamReader.java:184)
        at java.io.BufferedReader.fill(BufferedReader.java:161)
        at java.io.BufferedReader.readLine(BufferedReader.java:324)
        at java.io.BufferedReader.readLine(BufferedReader.java:389)
        at java.nio.file.Files.readAllLines(Files.java:3205)
        at Test.main(Test.java:8)
[kurila@ruxxkurilad2c tmp]$ java -version
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
openjdk version "1.8.0_162"
OpenJDK Runtime Environment (build 1.8.0_162-b12)
OpenJDK 64-Bit Server VM (build 25.162-b12, mixed mode)
В классе sun.nio.cs.CharsetDecoder есть метод decode, в котором есть участок:
            if (cr.isUnderflow()) {
                if (endOfInput && in.hasRemaining()) {
                    cr = CoderResult.malformedForLength(in.remaining());
                    // Fall through to malformed-input case
                } else {
                    return cr;
                }
            }

final var someStrings = (List<String>) new ArrayList<>();


да уж. за что боролись. както совсем подурацки выглядит.
хотя конечно можно понять причины.
но хотелось тыгда уж чтото вроде
List<String> someStrings = new ArrayList<>();

вариант:
List<> someStrings = new ArrayList<String>();

возможно даже лучше. хотя смотря какая цель.
UFO landed and left these words here
UFO landed and left these words here
UFO landed and left these words here
там более общая проблема.
конкретно для локальной переменной — ежели её передавать куда то, то нужно будет скобки писать и т.д., если она не List ну и в таком духе
UFO landed and left these words here
традиция. использовать минимальный интерфейс
UFO landed and left these words here
Ну для локальных, оно впринципе пофиг, да.
все равно у текущего состояния var есть какая то недосказанность.
скажем в котлине аналогичный вывод типов сделан интереснее
При вызове любой метод, принимающий List, пример и его наследника.

Ну… не совсем любой.
Вот вам пятничный пример:


import java.util.List;
import java.util.ArrayList;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class Test {

    public static void main(String... args) throws Throwable {

        ArrayList<String> list = new ArrayList<>();

        list.add("Test!");

        MethodHandles.Lookup lookup = MethodHandles.lookup();

        MethodHandle testMH = lookup.findStatic(
            Test.class, "test",
            MethodType.methodType(void.class, List.class)
        );

        testMH.invokeExact((List<String>) list);

        System.out.println();

        testMH.invokeExact(list);

    }

    private static void test(List<String> values) {
        for(String s : values) {
            System.out.println(s);
        }
    }

}

Сколько раз будет напечатана строка "Test!" после компиляции и запуска?

UFO landed and left these words here
То, что так делать нужно никто не утверждал. Цель комментария — продемонстрировать ложность процитированного утверждения.
«Размышления о реализации local variable type inference»
а джава как должна узнать какой супер интерфейс из множества делать var'у?
ну и вам очевидно «подсвечивает» не джава а IDE, так что решение этой проблемы на их плечах и в чём тут «джаву» обвинять я не понимаю.

Ну и в целом какие-то глобальные выводы делаете от обиды, что само сразу работать не стало :)
ЗЫ: «Провал при попытке определения MIME-типа файла.» это тоже мега проблемой не выглядит и на мой взгляд джуну по силу разобраться в чём дело.
а джава как должна узнать какой супер интерфейс из множества делать var'у?

а почему нет? минимально возможный, на основе статического анализа кода. не?

ну и вам очевидно «подсвечивает» не джава а IDE, так что решение этой проблемы на их плечах и в чём тут «джаву» обвинять я не понимаю.

ну если IDE догадывается, то и компилятор тоже вполне мог бы

Ну и в целом какие-то глобальные выводы делаете от обиды, что само сразу работать не стало :)
Не совсем. Я ждал что в 10-ке проблем с модулями уже не будет, но осталось множество вещей, которые делают модули совершенно неюзабельными. Не стало работать ни сразу, ни потом. Для полноты картины — вот, например, удачная цитата:
Wow… this makes jlink from hard to use to useless for the foreseeable future. – pupeno Apr 7 at 9:36

взято отсюда
stackoverflow.com/questions/48408454/java-9-generating-a-runtime-image-with-jlink-using-3rd-party-jars
ЗЫ: «Провал при попытке определения MIME-типа файла.» это тоже мега проблемой не выглядит и на мой взгляд джуну по силу разобраться в чём дело.
У меня нету столько джунов, чтобы бросить их на решение этих 1000 и 1 мелочей. Самому — лень, естественно. Не барское это дело. Я как-то, когда берусь за задачу, обычно выставляю себе лимит времени.
минимально возможный
Как определен «минимальный»?

ну если IDE догадывается, то и компилятор тоже вполне мог бы
Зачем вообще в типе подменять на интерфейс?
Вроде как так принято — использовать минимально необходимый интерфейс в качестве типа. Для уменьшения потенциальной связности. Local variable type inference нарушает этот принцип.
Т.е. авторитет разработчиков языка не остановил вас от разбирательства в деталях, а авторитет человека неизвестного останавливает.

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

Пока что выглядит как призыв к анемичности (если я корректно интерпретировал «минимальность»).
Я изначально неправильно выразился. «Анемичность» нужна для уменьшения потенциальной связности.
Какой минимальный-то? List, Collection, Iterable, Serializable? Что-то еще?
Хорошо, вот вам конкретная ситуация (собственно, оригинальная из поста).
var strings = new ArrayList<String>();

Какой здесь должен быть тип у переменной strings?

Object, если это конец области видимости. Если нет, то вы не раскрыли тему

Так как раз в этом суть. В джаве тип определяется декларацией, а не использованием. И это глобальное поведение. И var иначе работать не имеет права. Соответственно, данная строчка должна определять тип однозначно и независимо от того, финальный это вызов или же дальше будет еще strings.size() или strings.trimToSize().

Более того, если тип определяется дальнейшим использованием то эта ситуация полностью идентична как раз typeOf(strings) ≡ ArrayList<String>.
В джаве тип определяется декларацией, а не использованием.
  • В таком случае весь смысл "var" просто отваливается.


И var иначе работать не имеет права.
  • Непонятно, на основании чего сделан такой вывод. Законы мироздания мешают? В некоторых JVM-based языках вывод типа вполне работает. Что мешало сделать его в яве — непонятно.


Соответственно, данная строчка должна определять тип однозначно и независимо
  • Кому должна?

По второму пункту с автовыводом понятно. дает тот же тип, что справа.
Если хочешь специфику, пиши конкретный тип.

Компилятор мог бы для локальной переменной с "var" самостоятельно выводить минимально необходимый тип, однако он этого не делает. Фича сырая и кастрированная (почему нет "val"?)

UFO landed and left these words here
Переход на 9 или 10 обещает пока что много боли, так как многие используемые библиотеки собраны под 8-ку и просто не будут работать. Особенно, если вы захотите использовать модули (простого решения проблем с библиотеками пока не наблюдается).
Тут возникло много споров по поводу того, нормально собирается или нет.
Так вот.
Hello-world проект на Spring Boot скачан со спрингового же репозитория с Java 9 не работает.
На 8-й всё шикарно. =)
Чую скоро будет боль. Много боли.
UFO landed and left these words here

Что уж говорить, если даже стандартный пример Java2Demo, скачанный с официального сайта Oracle из раздела JDK 8u172 Demos and Samples, просто не запускается на JDK 10.

Они все испортят ©! Сейчас мы переживаем фактически начало заката Java. Экосистема не будет поспевать за новым релизным циклом, а Java движется в сторону постоянного ломания совместимости. С Java 8 прокатило, поскольку все давно ждали лямбды и стримы. Но в последних версиях количество вещей реально полезных для финального пользователя, остается минимальным. В итоге экосистема форкнется на две: с одной стороны будет небольшая группа early adopters, а с другой — огромный "легаси", который не будет спешить никуда мигрировать. Резко упадет количество решений, совместимых с новыми версиями Java, и общий интерес к Java платформе потихоньку начнет падать в угоду альтернативам. По моим оценкам Java 8 задержится еще минимум лет на 5, а потом внезапно появится что-то еще...

С трудом и болью перенес один из проектов на 9, на 10 не смог — отваливаются библиотеки. А теперь 9 не поддерживается, на 8 обратно переходить — как-то тупо. Так и сижу на 9.

Sign up to leave a comment.

Articles