Use of ‘_’ as an identifier might not be supported in releases after Java SE 8

Внезапно. Хотелось использовать gettext для локализации шаблонов в разрабатываемом мною статическом генераторе jpress(скоро опубликую на гитхаб), но javac 8-ой версии ругнулся на метод public String _(final String string) { тем что не нужно так его именовать, т.к. в следующих релизах джавы он может не поддерживаться(нарушат обратную совместимость?!).

Гугление вывело меня на JEP 213 в котором есть факт что “_” будет удалено, но не сказано почему.

Однако самое интересное было найдено в списках рассылки:

> Your suspicion is mostly right, except that we are certainly NOT going to
> do Scala’s “wunderbar”. However, things it might be used for include
> things like “I don’t want to give this variable a name” (such as catch
> parameters that are never used.)
Brian Goetz

Что делать? Использовать два нижних подчеркивания! 😀

TP-Link TP-WR842ND v1.1 and TD-W8968 v3

Сегодня занялся админскими делами и наконец-то дома заменил данный провайдером (byfly) ZTE ZXV10 W300 на TD-W8968.

Задача настройки ADSL на нем не такая простая как я думал, но уже ADSL настроен и интернет раздается по Wi-Fi, когда будет время надо будет покрутить другие ручки такие как второй/третий SSID для гостей/со включеным VPN.

В общем пишите, если нужно помогу его настроить.

Тем временем второй TP-Link’овский роутер, TP-WR842ND который после прошивки на гаруглью я успешно сделал кирпичом (как я не знаю :D) пришлось восстанавливать. Первая мысль что пора вспоминать UART и идти за паяльником к счастью осталась просто мыслью: данный роутер умеет восстанавливать себя сам (sic! спасибо китайцам за эти роутеры, с ними даже GPL идет распечатанная!) В общем вооружившись tftp я восстановил его (опять непонятно как :D). Пользовался я следующими гайдами:

http://wiki.openwrt.org/toh/tp-link/tl-wr842nd
http://forum.tp-linkru.com/viewtopic.php?f=216&t=1292

В общем остался я доволен тем что делают китайцы. Кстати, если еще не слышали, то посмотрите на смартфон Oneplus One: он тоже на открытой прошивке работает – CyanogenMod, надеюсь со временем все больше таких девайсов будет.

Семантика Enum в Java

Ничего интересного, просто JavaDoc метода name и toString из класса Enum.


/**
* Returns the name of this enum constant, exactly as declared in its
* enum declaration.
*
* Most programmers should use the {@link #toString} method in
* preference to this one, as the toString method may return
* a more user-friendly name.
This method is designed primarily for
* use in specialized situations where correctness depends on getting the
* exact name, which will not vary from release to release.
*
* @return the name of this enum constant
*/
public final String name() {
return name;
}

name – final метод, а значит переопределять его мы не можем, а вот toString естественно можно:


/**
* Returns the name of this enum constant, as contained in the
* declaration. This method may be overridden, though it typically
* isn't necessary or desirable. An enum type should override this
* method when a more "programmer-friendly" string form exists.
*
* @return the name of this enum constant
*/
public String toString() {
return name;
}

Т.е. для получения enum в виде стринги в большинстве случаев используем name, toString может использоваться для красивых логов (если enum содержит какие-либо поля).

60578090

Изучаем Bash. Как не отправить все в /dev/null

В скрипте инициализации RHEL допущена ошибка, приводящая к удалению всех файлов

Не делать assert’ов в критических точках приложения – отличный способ выстрелить в ногу с рикошетом в голову.

Пример из новости выше:

   stop
rm -rf $SQUID_PIDFILE_DIR/*
start

Без контекста заметить проблему трудно, но точно известно если переменная SQUID_PIDFILE_DIR не будет определена мы выполним:

   rm -rf /*

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

   stop
[ -z "$SQUID_PIDFILE_DIR" ] || exit 42
rm -rf $SQUID_PIDFILE_DIR/*
start

При таком подходе мы бы никогда не вызвали команду rm на корне файловой системы.

Про контрактное программирование на Java можно почитать здесь.

Вы все еще используете Files.lines()?

Привет, и в очередной раз мы поговорим про новшества Java 8, а точнее Files.lines().

Что может быть проще:

public class FilesLines {

public static void main(String[] args) throws Exception {

Path path = Paths.get("/home/ruslan/test.txt");

for (int i = 0; i < 10000; i++) {
Files.lines(path).count();
}
}
}

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

Запустим этот код под Ubuntu 14.04

java -version
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)

Результат:

Exception in thread "main" java.nio.file.FileSystemException: /home/ruslan/test.txt: Too many open files
at sun.nio.fs.UnixException.translateToIOException(UnixException.java:91)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214)
at java.nio.file.Files.newByteChannel(Files.java:361)
at java.nio.file.Files.newByteChannel(Files.java:407)
at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:384)
at java.nio.file.Files.newInputStream(Files.java:152)
at java.nio.file.Files.newBufferedReader(Files.java:2784)
at java.nio.file.Files.lines(Files.java:3744)
at java.nio.file.Files.lines(Files.java:3785)
at by.ibragimov.jpress.FilesLines.main(FilesLines.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

wtf

Что-же говорит нам документация? Посмотрим: File#lines(Path path) не содержит ничего подозрительного, но внутри просто делегирует вызов в Files#lines(Path path, Charset cs), а вот тут уже JavaDoc’и на намекают:

    /**
* ...
* The returned stream encapsulates a {@link Reader}. If timely
* disposal of file system resources is required, the try-with-resources
* construct should be used to ensure that the stream's
* {@link Stream#close close} method is invoked after the stream operations
* are completed.
* ...
*/[code]

Ну и исправленная версия напоследок:

[code lang="java"]public class FilesLines {

public static void main(String[] args) throws Exception {

Path path = Paths.get("/home/ruslan/test.txt");

for (int i = 0; i < 10000; i++) {
try(Stream<String> stream = Files.lines(path)) {
stream.count();
}
}
}
}

Вывод как всегда один: читайте документацию.

Best markdown library for Java

tiled-editor-and-web-preview

Для своего мини проекта потребовалась имплементация markdown to html парсера\конвертора. Я рассматривал процессоры найденные в mvnrepository и хочу сразу сказать – все плохо.

Итак были успешно протестированы следующие библиотеки:

am.ik.marked4j:marked4j:0.9.1
com.github.rjeschke:txtmark:0.11
com.sangupta:nutz:0.5.0
net.redhogs.actuarius:actuarius_2.10:0.2.7
org.markdownj:markdownj-core:0.4
org.pegdown:pegdown:1.4.2
ru.circumflex:circumflex-md:2.0.RC2

Я не случайно выделил успешно, в процессе одна из библиотек не завелась т.к. не было scala в classpath (а как зависимость она не додумалась ее включить). Несколько библиотек крашились на файлах сложнее хидеров и листов.

Из прошедших отличились org.pegdown:pegdown:1.4.2 и ru.circumflex:circumflex-md:2.0.RC2: они тянут приличный объем библиотек. Причем ru.circumflex:circumflex-md:2.0.RC2 отличился дважды, он притянул с собой log4j как зависимость!

Лучшей из все оказалась имплементация на JS! Да, именно так! am.ik.marked4j:marked4j:0.9.1 запускает библиотеку marked.js на скриптовом движке джавы и отдает результат полученный от скрипта. Как следствие ожидать сотни обработанных markdown файлов в секунду не стоит.

Что же я выбрал? Я выбрал AsciiDoc.

Почему AsciiDoc лучше Markdown?

1. У AsciiDoc есть хорошая документация и много фич
2. Он умеет не только AsciiDoc -> Html, но и в HTML5, DocBook 5 или 4.5, EPUB3, PDF и т.д.
3. Разработчики предоставляются возможность из коробки использовать его на JVM (JRuby и все такое)
4. С AsciidocFX можно писать и просматривать документы AsciiDoc на любой платформе.

Выводы

Если вы упорот, то можете написать очередной парсер с AST для markdown на Java, а потом еще больше упороться и прикрутить туда поддержку пары дополнений к стандартному синтаксису(кстати, какой стандартный? этот http://commonmark.org/? Или тот, который продвигает автор данного языка разметки?). Или взять какую-нибудь JS либу-парсер markdown и запускать ее под nashorn. А что если нужно больше чем просто markdown (который из коробки очень ограничен), например таблицы, подсветка синтаксиса кода, сноски или оглавление? Да это всё есть в некоторых диалектах mardown, например Github Flavored Markdown, но по моему очень скромному мнению стоит использовать AsciiDoc в котором всё это из коробки и хорошо документировано. А еще AsciiDoc нативно поддерживается на GitHub.

Файл с результатами работы библиотек: markdown-test.

Basic syntax comparison (Markdown vs AsciiDoc)

Git Bash for Windows

В целом командная строка под оффтопик это страх и ужас. sh.exe конечно же спасает, но отсутствие тесной интеграции с системой (в linux можно делать все из консоли) создает неудобства. В общем пользователям git bash for win посвящается: запускаем несколько окон с гитом в нужных проектах из bat файла:

rem git-win.bat
cd C:\dev\projects\project1
start "" "%SYSTEMDRIVE%\Program Files (x86)\Git\bin\sh.exe" --login -i

cd C:\dev\projects\project2
start "" "%SYSTEMDRIVE%\Program Files (x86)\Git\bin\sh.exe" --login -i

Если у вас 32-битная система(интересно, остались еще такие?) то этот файл

rem git-win-x86.bat
cd C:\dev\projects\project1
start "" "%ProgramFiles%\Git\bin\sh.exe" --login -i

cd C:\dev\projects\project2
start "" "%ProgramFiles%\Git\bin\sh.exe" --login -i

Flyway and Spring Boot

Добавив jar файл с flyway-core в classpath приложения написанного на Spring Boot и не настроив миграции можно получить следующее исключение:

Caused by: org.flywaydb.core.api.FlywayException: Unable to determine URL for classpath location: db/migration (ClassLoader: sun.misc.Launcher$AppClassLoader@58644d46)

Добавление проперти flyway.enabled = false в application.properties решает проблему но! только при запуске приложения. К сожалению тесты не используют application.properties.

# application.properties
flyway.enabled=false

Быстрый поиск приводит нас например сюда: http://stackoverflow.com/questions/26210786/spring-boot-not-using-application-properties-in-tests, если вас не удовлетворил данный подход/решение то предлагаю пойти дальше и посмотреть мои конфигурационные файлы.

В данном проекте используется java configuration:

@ContextConfiguration(classes = { TestAppConfig.class })
@RunWith(SpringJUnit4ClassRunner.class)
// ... other annotations
public abstract class BaseSpringTest {
// ...
}
@Configuration
@Import({ AppConfig.class })
public class TestAppConfig {
// ...
}
@Configuration
@EnableAutoConfiguration(exclude = { FlywayAutoConfiguration.class })
@ComponentScan("by.ibragimov.rkeep")
public class AppConfig {
// ...
}

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

Ссылки:
Execute Flyway database migrations on startup
Appendix A. Common application properties
org.springframework.boot.autoconfigure.flyway.FlywayProperties.java
Auto-configuration

Geek Cup

geek_cup

1. Одинаковые шестнадцатеричные цифры представлены одной и той же буквой:

(DRINKCOFFEE << F) + (BEHAPPY << D) = ITRANSITION

2. Предыдущее поколение в “Game of Life” с минимальным количеством живых клеток:

□□□□□□□□□□□□□□□□□□□□
□□■□□■□□□■□□■□□■□□■□
□■□□■□■□■□□■□□■□□■□□
□■□□■□■□■■□■■□■■□■■□
□■□□■□■□■□□■□□■□□■□□
□□■□□■□□■□□■□□□■□□■□
□□□□□□□□□□□□□□□□□□□□

3.

puts ->(v){r,c,l=0<=>v.abs,1,->(n,g;r,c){g>=~-n||g<=1?1:->(){r,c=1,2;->(){->{r=r+l[n-g,c]if(c+g<=n)}[];c+=1;}[]while(c<=g);r}[];};r+=l[v,c]and(c=c+1)while(c-v<=0)l=->(l){l+=1}[r]}[0xc0ffee]