Как стать автором
Обновить

Комментарии 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>();

возможно даже лучше. хотя смотря какая цель.
НЛО прилетело и опубликовало эту надпись здесь
тогда у someStrings будет тип ArrayList
НЛО прилетело и опубликовало эту надпись здесь
а нужен List
НЛО прилетело и опубликовало эту надпись здесь
там более общая проблема.
конкретно для локальной переменной — ежели её передавать куда то, то нужно будет скобки писать и т.д., если она не List ну и в таком духе
НЛО прилетело и опубликовало эту надпись здесь
традиция. использовать минимальный интерфейс
НЛО прилетело и опубликовало эту надпись здесь
Ну для локальных, оно впринципе пофиг, да.
все равно у текущего состояния 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!" после компиляции и запуска?

НЛО прилетело и опубликовало эту надпись здесь
То, что так делать нужно никто не утверждал. Цель комментария — продемонстрировать ложность процитированного утверждения.
«Размышления о реализации 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"?)

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

Что уж говорить, если даже стандартный пример 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.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории