葡京娱乐棋牌官网[翻译]现代java开发指南 第一部分

葡京娱乐棋牌官网[翻译]现代java开发指南 第一部分

当代java开发指南 第一有些

第一有的:Java就非是公父亲那期的法

首先局部,亚片

与历史及另外其它的言语相比,这里要破除c语言和cobol语言,现在尤其多之干活屡遭,有用的代码用Java语言描绘起。在20年前Java首次披露时,它引起了软件界的狂飙。在当时,相对c++语言,Java语言要又简明,更安全,而且以一段时间后,Java语言的性为取得了晋升(这仗让现实的采取状况,一个重型的Java程序于一致之c++程序相比,可能会慢一点,或者同一快,或者重新快一些)。比起c++,Java牺牲非常少性能,却提供了伟大的生产力提升。

Java是一门blue-collar
language,程序员值得信任的工具,它独自见面动已经让别的语言尝试了的没错的见地,同时多新的性状只会失去解决重要的痛点问题。Java是否一直钟情它的沉重是一个开放性的题材,但它们真的是奋力给从曾的道路未被当下的时尚所左右最远。在智能芯片,嵌入式设备以及重型主机及,java都以用于编写代码。甚至被用来编排对任务与安要求苛刻的硬件实时软件。

但,最近有些年,Java获得了森负面的评头品足,特别是在互联网初创企业面临。相对于别的言语如Ruby和python,Java显得死板,而且和布局自由之框架如Rails相比,java的网页开发框架需要采用大量的xml文件举行啊布局文件。进一步说,java于大型企业被常见采取导致了java所使用的编程模式及做法在一个百般大的有鲜明等级关系之艺集团中会生有因此,但是这些编程模式以及做法对迅速开打破常规的初创企业吧,不是挺合适。

然,Java已变更。Java最近益了lambda表达式和traits。以库的款式提供了像erlang和go所支持之轻量级线程。并且最好紧要的凡,提供了一个现代的、轻量级的方用于代替陈旧笨重以恢宏xml为底蕴之法,指导API、库和框架的统筹。

不久前有些年,Java生态圈有了有有意思的行:大量的以jvm为根基的程序语言变得流行;其中一些言语设计之不行吓(我个人喜欢Clojure和Kotlin)。但是同这些有效或者推荐的语言相比,Java及其余基于JVM的言语来说,确实发生几乎单长:熟悉,技持,成熟,和社区。通过新代器和新代的库房,Java实际上在即时几个点开了过多底行事。因此,许多的硅谷初创店,一而他俩成长壮大后,就会回去Java,或者至少是回JVM上,这点便非会见另外人惊异了。

随即卖介绍性指南的对象是怀念上如何勾勒现代精简Java代码的程序员(900万),或者是那些听到了或体验过Java坏的上面的Python/Ruby/Javascript程序员。并且指南展示了Java中一度改变的方和这些改动之面什么让Java获得任何人拍手叫好的特性,灵活性与而监控性而未会见牺牲太多的Java沉稳方面。

JVM

本着Java术语简单价绍一下,Java在概念上给分成三独片:Java,Java运行时库和Java虚拟机,或者叫JVM。如果你熟悉Node.js,Java语言类同于JavaScript,运行时库类同于Node.js,JVM类同于V8引擎。JVM和周转时库被从包改成大家所熟知的Java运行时环境,或者叫JRE(虽然常人们说JVM实际上指的凡JRE)。Java开发工具,JDK,是依靠有一个JRE的发行版,通常包括多开发工具像java编绎器javac,还有不少主次监控以及总体性分析工具。JRE通常发生几乎只支行,如支持嵌入式设备开支版本,但是仍博客中,我们才会干到JRE支持服务器(桌面)开发的版本,这虽是明摆着的
JavaSE(Java标准版)。

来一对门类实现了JVM和JRE的正儿八经,其中一些是开源的门类,还有部分凡是商项目。有些JVM非常出格,如有些JVM运行硬件实时嵌入式设备软件,还有JVM可以以伟大的内存达到运行软件。但是咱用会见利用HotSpot,一个出于Oracle支持的的轻易,通用的JVM实现,同时HotSpot也是从头源OpenJDK列之均等有些。

Java构建JVM,JVM同时运行Java(虽然JVM最近为其他语言做了有专程的改动)。但是什么是JVM,Cliff
Click的斯演讲讲了啊是JVM,简单的话,JVM是如出一辙宝抽象现实的魔法机器。JVM使用好,简单和行之有效之悬空,好像无限的内存和多态,这些听起来实现代价十分高,并且实现这些特征用这么迅疾的款型以致于她们能挺易能够同没有提供这些中抽象的周转时竞争。更需说明的凡,JVM拥有极好内存回收算法并能够当大范围的出品面临应用,JVM的JIT允许内联和优化虚方法的调用(这是众言语中最好管用的抽像的核心),在保留虚方法的用途的而,使调用虚方法非常有益及便捷。JVM的JIT(即经常编绎器)是基础之尖端性能优化编绎器,和你的运一起运行。

自JVM也暗藏了好多底操作系统级别的细节,如内存模型(代码在不同的CPU上运行怎样对待外的CPU操作引起的变量的状态的变通)和运定时器。JVM还提供周转时动态链接,热代码交换,监控几乎所有以JVM上运行的代码,还起库中的代码。

及时并无是说JVM是无微不至的。当前Java的数组缺失存放复杂结构体的能力(计划以当Java9受到化解),还有相当的尾调用优化。尽管JVM有这般的问题,但是JVM的成熟,测试好,快速,灵活,还来添加的周转时解析以及监理,让自己不见面考虑运行一个根本要的服务器进程在别的任何基础之上(除了JVM别无选择)。

反驳都够了。在咱们深入教之前,你应有下载在这里下载最新的JDK,或者采取你系统自带的保管管理器安装时的OpenJDK。

构建

为我们开现代Java构建工具旅程。在大丰富之一致段落历史时空内,Java出现了几个构建工具,如Ant和Maven,他们多数都基于XML。但是现代底Java开发者使用Gradle(最近成为Android的官方构建工具)。Gradle是一个成熟,深入开发,现代Java构建工具,它应用了于Groovy基础及的DSL语言来验证构建过程。他并了Maven的简单性和Ant的强大性和灵活性,同时抛弃有的XML。但是Gradle并无是从来不错误:当他要尽通用的有的简单和可声明式的同时,就见面生不少事务变得稀不通用,这便要求回到回来使用命令式的Groovy。

今天叫咱应用Gradle创建一个初的Java项目。首先,我们打此处下载Gradle,安装。现在我们开创办项目,项目名为JModern。创建一个叫Jmodern的目录,切换到击刚才创建的目,执行:

gradle init --type java-library

Gradle
创建了品种之初步文件夹结构,包括子类(Library.javaLibraryTest.java),我们将以末端去这片单文件:

figure1

代码在src/main/java/目下,测试代码在src/test/java目下。我们拿主类命名也jmodern.Main(所以主类的源文件就在src/main/java/jmodern/Main.java),这个顺序将会见将Hello World次召开一点细的成形。同时为了使Gradle更方便,将见面用Google's Guava。使用你欣赏的编辑器创建src/main/java/jmodern/Main.java,初始的代码如下:

package jmodern;

import com.google.common.base.Strings;

public class Main {
    public static void main(String[] args) {
        System.out.println(triple("Hello World!"));
        System.out.println("My name is " + System.getProperty("jmodern.name"));
    }

    static String triple(String str) {
        return Strings.repeat(str, 3);
    }
}

对应创建一个微的测试用例:在src/test/java/jmodern/MainTest.java:

package jmodern;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;

public class MainTest {
    @Test
    public void testTriple() {
        assertThat(Main.triple("AB"), equalTo("ABABAB"));
    }
}

每当项目根本目录,找到build.gradle文件,修改该公文:

apply plugin: 'java'
apply plugin: 'application'

sourceCompatibility = '1.8'

mainClassName = 'jmodern.Main'

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.google.guava:guava:17.0'

    testCompile 'junit:junit:4.11' // A dependency for a test framework.
}

run {
    systemProperty 'jmodern.name', 'Jack'
}

构建程序设置jmoder.Main为主类,声明Guava否该次的靠库,并且jmodern.name也系统特性,方便运行时读取。当输入以下命令:

gradle run

Gradle会从Maven中心库下载Guava,编绎程序,然后运行程序,把jmodern.name设置成"Jack"。总的长河就是是这样。

连通下,运行一下测试:

gradle build

变的测试报告当build/reports/tests/index.html

figure2

IDE

聊人说IDE会稳藏编程语言的题目。好吧,对于这题目,我尚未看法,但是不论而以任何语言,一个好的IDE总是发出帮带的,而Java在就点做的无限好。当然在文章被精选IDE不是重要之有些,总是要提一下,在Java世界面临,有三雅IDE:Eclipse,IntelliJ
IDEA,和NetBeans,你应有下采取一下后两者。IntelliJ可能是三者之中最精的IDE,而NetBeans应该是不过契合程序员直觉和最好轻使(我道也极其难堪)的IDE。NetBeans通过Gradle的插件对Gradle有尽好之支撑。Eclipse是最好给欢迎的IDE。我以博年前感觉Eclipse变得乱七八糟,就不下Eclipse了。当然要您是一个长久使用Eclipse的用户,也没啊问题。

安装了Gradle插件,我们的微项目在NetBeans中的榜样如下:

figure3

本人无限欢喜NetBeans的Gradle插件功能不仅是坐IDE列出了颇具有关项目之仗,还发生另的安排插件也能排有,所以我们唯有需要在构建文件被扬言他们同样软。如果您在品种中多新的倚重库,在NetBeans中右键单击项目,选择Reload Project,然后IDE将生充斥而初增加的依赖库。如果你右键单击Dependencies结点,选择Download Sources,IDE会下载依赖库的源代码和有关javadoc,这样您不怕得调剂第三方库的代码,还会查第三方库的文档。

据此Markdown编写文档

长期以来,Java通过Javadoc生成大好之API文档,而且Java开发者也习惯写Javadoc形式的笺注。但是现代底Java开发者喜欢下Markdown,喜欢使用Markdown为Javadoc增加点乐趣。为了达成在Javadoc使用Markdown,我们于构建文件被dependencies一些的前面,增加Pegdown DocletJavadoc插件:

configurations {
    markdownDoclet
}

然后,在dependencies中添加一行:

markdownDoclet 'ch.raffael.pegdown-doclet:pegdown-doclet:1.1.1'

末尾,构建文件的末梢加是片段:

javadoc.options {
    docletpath = configurations.markdownDoclet.files.asType(List) // gradle should relly make this simpler
    doclet = "ch.raffael.doclets.pegdown.PegdownDoclet"
    addStringOption("parse-timeout", "10")
}

竟,可以当Javadoc注释使用Markdown,还有语法高亮。

卿恐怕会见惦记关掉你的IDE的注解格式化功能(在Netbeans: Preferences ->
Editor -> Formatting, choose Java and Comments, and uncheck Enable
Comments Formatting)。IntelliJ
有一个插件克强亮在Javadoc中之Markdown语法。

为测试新增的安装,我们为艺术randomString多Markdown格式的javadoc,函数如下:

/**
 * ## The Random String Generator
 *
 * This method doesn't do much, except for generating a random string. It:
 *
 *  * Generates a random string at a given length, `length`
 *  * Uses only characters in the range given by `from` and `to`.
 *
 * Example:
 *
 *  // 这里有问题
 * randomString(new Random(), 'a', 'z', 10);
 *  
 *
 * @param r      the random number generator
 * @param from   the first character in the character range, inclusive
 * @param to     the last character in the character range, inclusive
 * @param length the length of the generated string
 * @return the generated string of length `length`
 */
public static String randomString(Random r, char from, char to, int length) ...

然后以命令gradle javadocbuild/docs/javadoc/生成html格式文档:

figure4

相似自己无常用之作用,因为IDE对这功能的语法高亮支持的免太好。但是当您得以文档中描写例子时,这个力量会让您的做事易得更轻松。

因而Java8状简洁之代码

近年来发表之Java8为Java语言带来了酷可怜的改,因为java原生支持lambda表达式。lambda表达式解决了一个主要的题目,在过去人们解决做一些简短从却写不成立之长的代码。为了展示lambda有多大之协助,我用出我能够想到的叫人老生气的,简单的数量操作代码,并拿这段代码改用Java8状起。这个事例产生了一个list,里面含有了随机生成的学员名字,然后进行以他们之头字母进行分组,并因漂亮的样式打印出。现在,修改Main类:

package jmodern;

import java.util.List;
import java.util.Map;
import java.util.Random;
import static java.util.stream.Collectors.*;
import static java.util.stream.IntStream.range;

public class Main {
    public static void main(String[] args) {
        // generate a list of 100 random names
        List<String> students = range(0, 100).mapToObj(i -> randomString(new Random(), 'A', 'Z', 10)).collect(toList());

        // sort names and group by the first letter
        Map<Character, List<String>> directory = students.stream().sorted().collect(groupingBy(name -> name.charAt(0)));

        // print a nicely-formatted student directory
        directory.forEach((letter, names) -> System.out.println(letter + "\n\t" + names.stream().collect(joining("\n\t"))));
    }

    public static String randomString(Random r, char from, char to, int length) {
        return r.ints(from, to + 1).limit(length).mapToObj(x -> Character.toString((char)x)).collect(Collectors.joining());
    }
}

Java自动推导了具有lambda的参数类型,Java确保了参数是路安全之,并且使您用IDE,IDE中的活动完成和重构功能对这些参数还好为此之。Java不会见像c++使用auto和c#中的var再有Go一样,自动推导局部变量,因为如此见面让代码的可读性降低。但是及时并无意味要要手动输入这些项目。例如,光标在students.stream().sorted().collect(Collectors.groupingBy(name -> name.charAt(0)))旋即一行代码上,在NetBeans中遵循下Alt+Enter,IDE会推导出结果当的路(这里是Map<Character, String>)。

假设想发一下函数式编程的作风,将main函数改成为下面的花样:

public static void main(String[] args) {
    range(0, 100)
            .mapToObj(i -> randomString(new Random(), 'A', 'Z', 10))
            .sorted()
            .collect(groupingBy(name -> name.charAt(0)))
            .forEach((letter, names) -> System.out.println(letter + "\n\t" + names.stream().collect(joining("\n\t"))));
}

与以前的代码确实不均等(看啦,没有项目),但是就应当不顶好了解这段代码的意。

纵然Java有lambda,但是Java仍然没有函数类型。其实,lambda在java中给移成为类似为functional接口,即来一个空洞方法的接口。这种自动转换使遗留代码能够和lambda在同非常好的行事。例如:Arrays.sort方法是得一个Comparateor接口的实例,这个接口简单描述成单一的揭露抽象
int compare(T o1, T o2)计。在java8蒙,可以以lambda表达式对字符串数组进行排序,根据数组元素的老三独字符:

Arrays.sort(array, (a, b) -> a.charAt(2) - b.charAt(2));

Java8吧增加了能够实现方式的接口(将这种接口换变成“traits”)。例如,FooBar接口有有限个方式,一个凡空洞方法foo,另一个是发默认实现之bar。另一个useFooBar调用FooBar

interface FooBar {
    int foo(int x);
    default boolean bar(int x) { return true; }
}

int useFooBar(int x, FooBar fb) {
    return fb.bar(x) ? fb.foo(x) : -1;
}

虽然FooBar发生三三两两独点子,但是仅仅出一个foo举凡空泛的,所以FooBar呢是一个函数接口,并且可以下lambda表达式创建FooBar,例如:

useFooBar(3, x -> x * x)

将会晤回9。

透过Fibers实现轻量级并发控制

产生成百上千总人口及本人一样,都对准出现数据结构感兴趣,而立即同块是JVM的后花园。一方面,JVM对于CPU的出现原语提供了低档方法而CAS结构与内存栅栏,另一方面结合内存回收机制提供了平台中立之内存模型。但是,对那些使用并发控制的程序员来说,并无是以扩大他们的软件,而采用并发控制,而是她俩不得不动并发控制而自己之软件可扩大。从马上方面说,Java并作控制并无是颇好,是发题目。

真正,Java从初始即深受设计改为出现控制,并且在各个一个本中都强调他的面世控制数据结构。Java已高质量的兑现了成千上万不胜实用之产出数据结构(如并发HashMap,并发SkipListMap,并发LinkedQueue),有些都没有以Erlang和Go中实现。Java的出现控制一般性领先c++5年或者又丰富的日。但是你会发觉对高效地行使这些出现控制数据结构异常困难。当我们应用线程和沿经常,刚开你见面发觉其工作的雅好,到了后面当您用还多并作控制时,发现这些措施无能够可怜好的恢弘。然后我们使用线程池和波,这半个东西发生非常好的扩展性,但是若晤面发现那个麻烦去说共享变量,特别是在语言级别没有针对性共享变量的可变性进行界定。进一步说,如果你的题目是外核级线程不能够十分好的恢宏,那么对事件的异步处理是一个坏想法。为什么未略修补线程的题材吗?这恰是Erlang和Go所采用的主意:轻量级的用户线程。轻量级用户线程通过简单,阻塞式的编程方法迅速使用并结构,将内核级的起控制映射到程序级的产出控制,而休用牺牲可扩展性,同时比锁和信号还简短。

Quasar凡一个我们创建的开源库,它给JVM增加了真的轻量级线程(在Quasar叫纤程),同得克挺好之跟系统级线程很好当一齐的干活。Quasar同Go的CSP一样,同时发生一个基结Erlang的Actor系统。对付并发控制,纤程是一个怪好的取舍。纤程简单、优美和飞跃。现在给咱来探它:

先是,我们装构建脚本,添加以下的代码在build.gradle中:

configurations {
    quasar
}

dependencies {
    compile "co.paralleluniverse:quasar-core:0.5.0:jdk8"
    quasar "co.paralleluniverse:quasar-core:0.5.0:jdk8"
}

run {
    jvmArgs "-javaagent:${configurations.quasar.iterator().next()}" // gradle should make this simpler, too
}

创新依赖,编辑Main.java:

package jmodern;

import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.strands.Strand;
import co.paralleluniverse.strands.channels.Channel;
import co.paralleluniverse.strands.channels.Channels;

public class Main {
    public static void main(String[] args) throws Exception {
        final Channel<Integer> ch = Channels.newChannel(0);

        new Fiber<Void>(() -> {
            for (int i = 0; i < 10; i++) {
                Strand.sleep(100);
                ch.send(i);
            }
            ch.close();
        }).start();

        new Fiber<Void>(() -> {
            Integer x;
            while((x = ch.receive()) != null)
                System.out.println("--> " + x);
        }).start().join(); // join waits for this fiber to finish
    }
}

如今有通过channel,有少数单纤程可以进行通信。

Strand.sleep,和Strand接近的有方,在原来生Java线程和fiber中还能够好好之运行。现在咱们用首先独fiber替换成原生的线程:

new Thread(Strand.toRunnable(() -> {
    for (int i = 0; i < 10; i++) {
        Strand.sleep(100);
        ch.send(i);
    }
    ch.close();
})).start();

就吗运行的挺好(当然我们曾当我们的用被运作百万级的fiber,也为此了几千线程)。

咱俩处于时而channel selection (模拟Go的select)。

package jmodern;

import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.strands.Strand;
import co.paralleluniverse.strands.channels.Channel;
import co.paralleluniverse.strands.channels.Channels;
import co.paralleluniverse.strands.channels.SelectAction;
import static co.paralleluniverse.strands.channels.Selector.*;

public class Main {
    public static void main(String[] args) throws Exception {
        final Channel<Integer> ch1 = Channels.newChannel(0);
        final Channel<String> ch2 = Channels.newChannel(0);

        new Fiber<Void>(() -> {
            for (int i = 0; i < 10; i++) {
                Strand.sleep(100);
                ch1.send(i);
            }
            ch1.close();
        }).start();

        new Fiber<Void>(() -> {
            for (int i = 0; i < 10; i++) {
                Strand.sleep(130);
                ch2.send(Character.toString((char)('a' + i)));
            }
            ch2.close();
        }).start();

        new Fiber<Void>(() -> {
            for (int i = 0; i < 10; i++) {
                SelectAction<Object> sa
                        = select(receive(ch1),
                                receive(ch2));
                switch (sa.index()) {
                    case 0:
                        System.out.println(sa.message() != null ? "Got a number: " + (int) sa.message() : "ch1 closed");
                        break;
                    case 1:
                        System.out.println(sa.message() != null ? "Got a string: " + (String) sa.message() : "ch2 closed");
                        break;
                }
            }
        }).start().join(); // join waits for this fiber to finish
    }
}

自Quasar
0.6.0开始,可以在挑选状态中采用应用lambda表达式,最新的代码可以写成这么:

for (int i = 0; i < 10; i++) {
    select(
        receive(ch1, x -> System.out.println(x != null ? "Got a number: " + x : "ch1 closed")),
        receive(ch2, x -> System.out.println(x != null ? "Got a string: " + x : "ch2 closed")));
}

瞧fiber的胜性能io:

package jmodern;

import co.paralleluniverse.fibers.*;
import co.paralleluniverse.fibers.io.*;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.*;
import java.nio.charset.*;

public class Main {
    static final int PORT = 1234;
    static final Charset charset = Charset.forName("UTF-8");

    public static void main(String[] args) throws Exception {
        new Fiber(() -> {
            try {
                System.out.println("Starting server");
                FiberServerSocketChannel socket = FiberServerSocketChannel.open().bind(new InetSocketAddress(PORT));
                for (;;) {
                    FiberSocketChannel ch = socket.accept();
                    new Fiber(() -> {
                        try {
                            ByteBuffer buf = ByteBuffer.allocateDirect(1024);
                            int n = ch.read(buf);
                            String response = "HTTP/1.0 200 OK\r\nDate: Fri, 31 Dec 1999 23:59:59 GMT\r\n"
                                            + "Content-Type: text/html\r\nContent-Length: 0\r\n\r\n";
                            n = ch.write(charset.newEncoder().encode(CharBuffer.wrap(response)));
                            ch.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
        System.out.println("started");
        Thread.sleep(Long.MAX_VALUE);
    }
}

我们举行了什么?首先我们启动了一个直循环的fiber,用于收纳TCP连接。对于每一个连连上之连天,这个fiber会启动另外一个fiber去读请求,发送回应,然后倒闭。这段代码是死IO的,在后台使用异步EPoll
IO,所以它们和异步IO服务器,有相同的扩展性。(我们用于Quasar中极大的增进IO性能)。

然而容错的Actor和热代码的转移

Actor模型,受欢迎是发一半因是Erlang,意图是编写而容错,高可保障的下。它用动用细分成单身可容错的器皿单元-Actors,标准化处理不当被还原措施。

当我们初步Actor,将compile "co.paralleluniverse:quasar-actors:0.5.0"
加到你的构建脚论被之仗中失。

咱重写Main函数,要为咱的用可容错,代码会变的越复杂。

package jmodern;

import co.paralleluniverse.actors.*;
import co.paralleluniverse.fibers.*;
import co.paralleluniverse.strands.Strand;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) throws Exception {
        new NaiveActor("naive").spawn();
        Strand.sleep(Long.MAX_VALUE);
    }

    static class BadActor extends BasicActor<String, Void> {
        private int count;

        @Override
        protected Void doRun() throws InterruptedException, SuspendExecution {
            System.out.println("(re)starting actor");
            for (;;) {
                String m = receive(300, TimeUnit.MILLISECONDS);
                if (m != null)
                    System.out.println("Got a message: " + m);
                System.out.println("I am but a lowly actor that sometimes fails: - " + (count++));

                if (ThreadLocalRandom.current().nextInt(30) == 0)
                    throw new RuntimeException("darn");

                checkCodeSwap(); // this is a convenient time for a code swap
            }
        }
    }

    static class NaiveActor extends BasicActor<Void, Void> {
        private ActorRef<String> myBadActor;

        public NaiveActor(String name) {
            super(name);
        }

        @Override
        protected Void doRun() throws InterruptedException, SuspendExecution {
            spawnBadActor();

            int count = 0;
            for (;;) {
                receive(500, TimeUnit.MILLISECONDS);
                myBadActor.send("hi from " + self() + " number " + (count++));
            }
        }

        private void spawnBadActor() {
            myBadActor = new BadActor().spawn();
            watch(myBadActor);
        }

        @Override
        protected Void handleLifecycleMessage(LifecycleMessage m) {
            if (m instanceof ExitMessage && Objects.equals(((ExitMessage) m).getActor(), myBadActor)) {
                System.out.println("My bad actor has just died of '" + ((ExitMessage) m).getCause() + "'. Restarting.");
                spawnBadActor();
            }
            return super.handleLifecycleMessage(m);
        }
    }
}

代码中生一个NaiveActor有一个BadActor,这个起下的底Actor会偶然失败。由于我们的父actor监控子Actor,当子Actor过早的万分去,父actor会得到关照,然后重新开动一个新的Actor。

是例子,Java相当的可恶,特别是当她因此instanceof测试消息之种以及转移消息之类的当儿。这一头通过模式匹配Clojure和Kotlin做的可比好(以后我会犯一样首关于Kotlin的稿子)。所以,是的,所有的门类检查和类型转换相当另人嫌。这种类型代码鼓励而去试试一下Kotlin,你实在该去使用一下(我就算试过,我好喜爱Kotlin,但是要是用以生产条件下其还有待成熟)。就个人来说,这种令人作呕非常小。

返回主要问题来。一个基于Actor的可容错系统首要的机件是削减宕机时间不论是由于下的谬误,还是由系统保障。我们将以其次局部探索JVM的军事管制,接下展示一下Actor之热代码交换。

以热代码交换的题材上,有几乎种植方式(例如:JMX,将在第二局部唠)。但是现在我们透过督查文件系统来促成。首先在类型目录下创办一个让modules支行文件夹,在build.gradlerun补给加以下代码:

systemProperty "co.paralleluniverse.actors.moduleDir", "${rootProject.projectDir}/modules"

开辟终端,启动程序。程序启动后,回到IDE,修改BadActor

@Upgrade
static class BadActor extends BasicActor<String, Void> {
    private int count;

    @Override
    protected Void doRun() throws InterruptedException, SuspendExecution {
        System.out.println("(re)starting actor");
        for (;;) {
            String m = receive(300, TimeUnit.MILLISECONDS);
            if (m != null)
                System.out.println("Got a message: " + m);
            System.out.println("I am a lowly, but improved, actor that still sometimes fails: - " + (count++));

            if (ThreadLocalRandom.current().nextInt(100) == 0)
                throw new RuntimeException("darn");

            checkCodeSwap(); // this is a convenient time for a code swap
        }
    }
}

俺们加了@Upgrade注解,因为咱们想给这看似进行提升,这个近乎修改后砸变少了。现在次还于运作,新起来一个极,通过gradle jar,重新构建程序。不熟悉java程序员,JAR(Java
Archive)用来打包Java模块(在亚部分会讨论Java打包和布局)。最后,在第二单极端中,复制build/libs/jmodern.jarmodeules文本夹着,使用命令:

cp build/libs/jmodern.jar modules

乃会看程序更新运行了(这个时节在你的操作系统,大概只要十秒)。注意不像我们当砸后再开动BadActor,当我们交换代码时,程序中之中间变量保存下去了。

规划一个基于Actor设计而容错的系统是一个怪老之主题,但是我梦想您既针对性其稍微觉得。

尖端话题:可插拔类型

利落前,我们用追究一个悬的领域。我们连下去介绍的家伙还无投入到现代Java开发工具箱被,因为使用她仍异常麻烦,不过她以会起IDE融合中落好处,现在以此家伙还很陌生。虽然这样,如果这个家伙持继开发以不止增加,它带的可能性非常的不胜,如果他非会见以疯子手中被胡用,它用见面好有价,这虽是干吗我们管其列在这边。

以Java8面临,一个秘最管用之新特征,是种类注解和可拔类型系统。Java编绎器现在兴在旁地方多对品种的笺注(一会我们举个例子)。这里做注解预处理器,打发可插拔类型系统。这些是可选的种类系统,可以关闭或者打开,能叫Java代码够长强大的因项目检查的静态验证功能。Checker框架哪怕如此一个库,它同意高档开发者写好的可插拔类型系统,包括连续,类型接口等。它自己连了几乎种植档次系统,如检查只是空类型,污染项目,正则表达式,物理单位类型,不可变数据等等。

Checker目前尚不可知杀好的跟IDE一起工作,所有这节,我拿无利用IDE。首先修改build.gradle,增加:

configurations {
    checker
}

dependencies {
    checker 'org.checkerframework:jdk8:1.8.1'
    compile 'org.checkerframework:checker:1.8.1'
}

交对应的configurations,dependencies部分。

下一场,增加下面有及构建文件中:

compileJava {
    options.fork = true
    options.forkOptions.jvmArgs = ["-Xbootclasspath/p:${configurations.checker.asPath}:${System.getenv('JAVA_HOME')}/lib/tools.jar"]
    options.compilerArgs = ['-processor', 'org.checkerframework.checker.nullness.NullnessChecker,org.checkerframework.checker.units.UnitsChecker,org.checkerframework.checker.tainting.TaintingChecker']
}

正而自说之,笨重的。

末尾一行说明我们采取Checker的空值类型系统,物理单位类型系统,污染数据类型系统。

现今我们举行有试行。首先,试一下空值类型系统,他能防空指针的荒唐。

package jmodern;

import org.checkerframework.checker.nullness.qual.*;

public class Main {
    public static void main(String[] args) {
        String str1 = "hi";
        foo(str1); // we know str1 to be non-null

        String str2 = System.getProperty("foo");
        // foo(str2); // <-- doesn't compile as str2 may be null
        if (str2 != null)
            foo(str2); // after the null test it compiles
    }

    static void foo(@NonNull String s) {
        System.out.println("==> " + s.length());
    }
}

Checker的开发者很友善,注解了全方位JD可空的回来路,所以当有@NonNull注时,从库中返回值不要回null值,。

联网下去,我们摸索一下单位项目系统,防止单位类型转换错误。

package jmodern;

import org.checkerframework.checker.units.qual.*;

public class Main {
    @SuppressWarnings("unsafe") private static final @m int m = (@m int)1; // define 1 meter
    @SuppressWarnings("unsafe") private static final @s int s = (@s int)1; // define 1 second

    public static void main(String[] args) {
        @m double meters = 5.0 * m;
        @s double seconds = 2.0 * s;
        // @kmPERh double speed = meters / seconds; // <-- doesn't compile
        @mPERs double speed = meters / seconds;

        System.out.println("Speed: " + speed);
    }
}

大酷吧,根据Checker的文档,你吧足以定义自己的情理单位。

末,试试污染项目系统,它能够帮助你跟被传染(潜在的摇摇欲坠)的多少,例如用户数录入的多寡:

package jmodern;

import org.checkerframework.checker.tainting.qual.*;

public class Main {
    public static void main(String[] args) {
        // process(parse(read())); // <-- doesn't compile, as process cannot accept tainted data
        process(parse(sanitize(read())));
    }

    static @Tainted String read() {
        return "12345"; // pretend we've got this from the user
    }

    @SuppressWarnings("tainting")
    static @Untainted String sanitize(@Tainted String s) {
        if(s.length() > 10)
            throw new IllegalArgumentException("I don't wanna do that!");
        return (@Untainted String)s;
    }

    // doesn't change the tainted qualifier of the data
    @SuppressWarnings("tainting")
    static @PolyTainted int parse(@PolyTainted String s) {
        return (@PolyTainted int)Integer.parseInt(s); // apparently the JDK libraries aren't annotated with @PolyTainted
    }

    static void process(@Untainted int data) {
        System.out.println("--> " + data);
    }
}

Checker通过类型接口给于Java可插拔交互类型。并且可透过工具及预编绎库增加项目注解。Haskell都开不顶及时或多或少。

Checker还并未交外的黄金时段,如果应用明智的语句,它见面化为当代Java开发者手中强有力的家伙有。

结束

我们都观望了Java8吃的变通,还来照应现代之家伙与货栈,Java相对于跟原有的版本的话,相似性不强。但是Java仍然是巨型应用被的亮点,而且Jva和它们的生态圈比新的简单的语言,更为成熟与高效。我们询问现代Java程序员是怎么样写代码的,但是咱挺不便平开始就是解开Java和Jvm的周力。特别当我们解了Java的监督及性质分析工具,和初的微应用网络下开发框架。在属下去的章中我们会谈及就几乎独话题。

若你想了解一个开,第二部分,我们会谈论现代Java打包方法(使用Capsule,有接触像npm,但是更酷),监控和保管(使用VisualVM,
JMX,
Jolokia
和Metrics)
,性能分析(使用 Java Flight
Recorder,
Mission
Control,

Byteman),基准测试(JMH)。老三片段,我们会谈论用Dropwizard,Comsat和Web
Actors,JSR-330写一个轻量级可扩大的HTTP服务。

初稿地址:Not Your Father’s Java: An Opinionated Guide to Modern Java
Development, Part
1

admin

网站地图xml地图