关于jdk8:Java开启JMX远程监控

1. 服务端配置java启动命令减少以下参数即可: -Dcom.sun.management.jmxremote \-Dcom.sun.management.jmxremote.local.only=false \-Djava.rmi.server.hostname=test.xxx.com \-Dcom.sun.management.jmxremote.port=18097 \-Dcom.sun.management.jmxremote.rmi.port=18098 \-Dcom.sun.management.jmxremote.ssl=false \-Dcom.sun.management.jmxremote.authenticate=false \-Xloggc:logs/gc.log \参数阐明:不开启SSL-Dcom.sun.management.jmxremote.ssl=false不开启明码验证-Dcom.sun.management.jmxremote.authenticate=false 2. 客户端配置关上Java VisualVM配置近程连贯连贯留神项:主机填-Djava.rmi.server.hostname配置的主机端口填-Dcom.sun.management.jmxremote.port配置的端口配置-Dcom.sun.management.jmxremote.rmi.port不能省略

May 24, 2023 · 1 min · jiezi

关于jdk8:Jenkins-添加-Slave-Agent-节点时报类文件不匹配错误

在搭建好的 Jenkins Server 的控制面板上增加 Salve Agent 节点的时候产生了上面的谬误 Checking Java version in the PATHopenjdk version "1.8.0_345"OpenJDK Runtime Environment (build 1.8.0_345-b01)OpenJDK 64-Bit Server VM (build 25.345-b01, mixed mode)[11/19/22 04:35:32] [SSH] Checking java version of /home/shutang/jenkins/jdk/bin/javaCouldn't figure out the Java version of /home/shutang/jenkins/jdk/bin/javabash: /home/shutang/jenkins/jdk/bin/java: No such file or directory[11/19/22 04:35:32] [SSH] Checking java version of java[11/19/22 04:35:32] [SSH] java -version returned 1.8.0_345.[11/19/22 04:35:32] [SSH] Starting sftp client.[11/19/22 04:35:33] [SSH] Copying latest remoting.jar...Source agent hash is 8D575C4C8219E6AB2039295EC545C6C3. Installed agent hash is 8D575C4C8219E6AB2039295EC545C6C3Verified agent jar. No update is necessary.Expanded the channel window size to 4MB[11/19/22 04:35:33] [SSH] Starting agent process: cd "/home/shutang/jenkins" && java -jar remoting.jar -workDir /home/shutang/jenkins -jar-cache /home/shutang/jenkins/remoting/jarCacheError: A JNI error has occurred, please check your installation and try againException in thread "main" java.lang.UnsupportedClassVersionError: hudson/remoting/Launcher has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:756) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:473) at java.net.URLClassLoader.access$100(URLClassLoader.java:74) at java.net.URLClassLoader$1.run(URLClassLoader.java:369) at java.net.URLClassLoader$1.run(URLClassLoader.java:363) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:362) at java.lang.ClassLoader.loadClass(ClassLoader.java:418) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) at java.lang.ClassLoader.loadClass(ClassLoader.java:351 at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:601)Agent JVM has terminated. Exit code=1[11/19/22 04:35:33] Launch failed - cleaning up connection[11/19/22 04:35:33] [SSH] Connection closed.Searching for www.datang001.com in /var/jenkins_home/.ssh/known_hostsSearching for www.datang001.com:22 in /var/jenkins_home/.ssh/known_hosts[11/19/22 04:35:44] [SSH] WARNING: No entry currently exists in the Known Hosts file for this host. Connections will be denied until this new host and its associated key is added to the Known Hosts file.Key exchange was not finished, connection is closed.SSH Connection failed with IOException: "Key exchange was not finished, connection is closed.", retrying in 15 seconds. There are 3 more retries left.Searching for www.datang001.com in /var/jenkins_home/.ssh/known_hostsSearching for www.datang001.com:22 in /var/jenkins_home/.ssh/known_hosts[11/19/22 04:35:59] [SSH] WARNING: No entry currently exists in the Known Hosts file for this host. Connections will be denied until this new host and its associated key is added to the Known Hosts file.Key exchange was not finished, connection is closed.SSH Connection failed with IOException: "Key exchange was not finished, connection is closed.", retrying in 15 seconds. There are 2 more retries left.Searching for www.datang001.com in /var/jenkins_home/.ssh/known_hostsSearching for www.datang001.com:22 in /var/jenkins_home/.ssh/known_hosts[11/19/22 04:36:14] [SSH] WARNING: No entry currently exists in the Known Hosts file for this host. Connections will be denied until this new host and its associated key is added to the Known Hosts file.Key exchange was not finished, connection is closed.SSH Connection failed with IOException: "Key exchange was not finished, connection is closed.", retrying in 15 seconds. There are 1 more retries left.Searching for www.datang001.com in /var/jenkins_home/.ssh/known_hostsSearching for www.datang001.com:22 in /var/jenkins_home/.ssh/known_hosts[11/19/22 04:36:29] [SSH] WARNING: No entry currently exists in the Known Hosts file for this host. Connections will be denied until this new host and its associated key is added to the Known Hosts file.Key exchange was not finished, connection is closed.ERROR: Connection is not established!java.lang.IllegalStateException: Connection is not established! at com.trilead.ssh2.Connection.getRemainingAuthMethods(Connection.java:988) at com.cloudbees.jenkins.plugins.sshcredentials.impl.TrileadSSHPasswordAuthenticator.canAuthenticate(TrileadSSHPasswordAuthenticator.java:83) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:176) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) at java.base/java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1812) at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127) at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543) at com.cloudbees.jenkins.plugins.sshcredentials.SSHAuthenticator.newInstance(SSHAuthenticator.java:222) at com.cloudbees.jenkins.plugins.sshcredentials.SSHAuthenticator.newInstance(SSHAuthenticator.java:173) at hudson.plugins.sshslaves.SSHLauncher.openConnection(SSHLauncher.java:881) at hudson.plugins.sshslaves.SSHLauncher.lambda$launch$0(SSHLauncher.java:434) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829)通过查看 Jenkins 官网提供的信息如下 ...

November 19, 2022 · 3 min · jiezi

关于jdk8:windows环境安装JDK18

1.1 筹备工作: 下载安装包 JDK下载地址 1.2 抉择JDK版本: 这里抉择的是JDK1.8 (留神协定变动: Oracle JDK到底从哪个版本开始免费?) 1.3 抉择版本: 这里抉择windows64位,点击下载 2.1 关上方才下载下来的exe文件(留神下装置门路),点击下一步,直到装置完结. 2.2 我的电脑(右键--->抉择属性) 2.3 点击高级零碎设置 2.4 点击环境变量 2.5 在零碎环境,点击新建 至此装置JDK装置胜利

August 5, 2021 · 1 min · jiezi

关于jdk8:docker搭建java-jdk环境

下载centos镜像docker pull centos:7.9.2009以jdk8为例来搭建环境1.获取jdk8安装包,在下载页面找到与零碎对应的安装包,我这里抉择64位的安装包。 https://www.oracle.com/java/t... 2.创立Dockerfile在/usr/local目录下创立jdk目录,把jdk-8u301-linux-x64.tar.gz复制到/usr/local/jdk目录下,而后创立Dockerfile mkdir /usr/local/jdkcd /usr/local/jdkcp /usr/local/mylib/jdk-8u301-linux-x64.tar.gz ./touch Dockerfilevim Dockerfile编辑Dockerfile文件FROM centos:7.9.2009RUN mkdir /usr/local/jdkWORKDIR /usr/local/jdkADD jdk-8u301-linux-x64.tar.gz /usr/local/jdkENV JAVA_HOME /usr/local/jdk/jdk1.8.0_301ENV JRE_HOME /usr/local/jdk/jdk1.8.0_301/jreENV PATH $JAVA_HOME/bin:$PATH应用Dockerfile构建jdk1.8镜像docker build -t jdk1.8 . 当docker build命令执行实现之后,对应的jdk8的镜像曾经打包实现。 验证查看零碎所有docker镜像文件 docker images 1.创立容器 docker run -di --name="jdk1.8" jdk1.82.进入容器 docker exec -it jdk1.8 /bin/bash3.查看jdk版本 java -version 4.退出容器,验证java javac命令

July 26, 2021 · 1 min · jiezi

关于jdk8:linux-下安装-jdk

下载安装包上官网下载对应linux环境的安装包 上传安装包进入 /usr/local,新建一个放jdk的目录 cd /usr/localmkdir java ##目录名称 将下载好的jdk压缩包上传到下面新建的目录 解压安装包进入对应文件目录,应用 tar -zxvf jdk-8u291-linux-x64.tar.gz 解压。 x : 从 tar 包中把文件提取进去z : 示意 tar 包是被 gzip 压缩过的,所以解压时须要用 gunzip 解压v : 显示详细信息f xxx.tar.gz : 指定被解决的文件是 xxx.tar.gz 配置环境变量编辑 /etc/profile 文件,在开端加上以下配置 # 设置环境变量export JAVA_HOME=/usr/local/java/jdk1.8.0_291 ## 这里要留神目录要换成本人解压的jdk 目录export JRE_HOME=${JAVA_HOME}/jre export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${JAVA_HOME}/bin:$PATH 接着输出 source /etc/profile 使环境变量配置马上失效。 验证别离输出 java -version 和 javac 查看装置状况 至此,linux 下的 jdk 环境装置胜利。 技术交换 QQ 群:816425449

July 5, 2021 · 1 min · jiezi

关于jdk8:JAVA8之妙用Optional解决判断Null为空的问题

引言在文章的结尾,先说下NPE问题,NPE问题就是,咱们在开发中常常碰到的NullPointerException.假如咱们有两个类,他们的UML类图如下图所示在这种状况下,有如下代码user.getAddress().getProvince();这种写法,在user为null时,是有可能报NullPointerException异样的。为了解决这个问题,于是采纳上面的写法 if(user!=null){ Address address = user.getAddress(); if(address!=null){ String province = address.getProvince(); }}这种写法是比拟俊俏的,为了防止上述俊俏的写法,让俊俏的设计变得优雅。JAVA8提供了Optional类来优化这种写法,接下来的注释局部进行具体阐明 API介绍先介绍一下API,与其余文章不同的是,本文采取类比的形式来讲,同时联合源码。而不像其余文章一样,一个个API列举进去,让人找不到重点。 1、Optional(T value),empty(),of(T value),ofNullable(T value) 这四个函数之间具备相关性,因而放在一组进行记忆。 先阐明一下,Optional(T value),即构造函数,它是private权限的,不能由内部调用的。其余三个函数是public权限,供咱们所调用。那么,Optional的实质,就是外部贮存了一个实在的值,在结构的时候,就直接判断其值是否为空。好吧,这么说还是比拟形象。间接上Optional(T value)构造函数的源码,如下图所示那么,of(T value)的源码如下 public static <T> Optional<T> of(T value) { return new Optional<>(value);}也就是说of(T value)函数外部调用了构造函数。依据构造函数的源码咱们能够得出两个论断: 通过of(T value)函数所结构出的Optional对象,当Value值为空时,仍然会报NullPointerException。 通过of(T value)函数所结构出的Optional对象,当Value值不为空时,能失常结构Optional对象。 除此之外呢,Optional类外部还保护一个value为null的对象,大略就是长上面这样的 public final class Optional<T> { //省略.... private static final Optional<?> EMPTY = new Optional<>(); private Optional() { this.value = null; } //省略... public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }}那么,empty()的作用就是返回EMPTY对象。 ...

May 24, 2021 · 3 min · jiezi

关于jdk8:JAVA8之妙用Optional解决判断Null为空的问题

引言在文章的结尾,先说下NPE问题,NPE问题就是,咱们在开发中常常碰到的NullPointerException.假如咱们有两个类,他们的UML类图如下图所示在这种状况下,有如下代码user.getAddress().getProvince();这种写法,在user为null时,是有可能报NullPointerException异样的。为了解决这个问题,于是采纳上面的写法 if(user!=null){ Address address = user.getAddress(); if(address!=null){ String province = address.getProvince(); }}这种写法是比拟俊俏的,为了防止上述俊俏的写法,让俊俏的设计变得优雅。JAVA8提供了Optional类来优化这种写法,接下来的注释局部进行具体阐明API介绍先介绍一下API,与其余文章不同的是,本文采取类比的形式来讲,同时联合源码。而不像其余文章一样,一个个API列举进去,让人找不到重点。 1、Optional(T value),empty(),of(T value),ofNullable(T value) 这四个函数之间具备相关性,因而放在一组进行记忆。 先阐明一下,Optional(T value),即构造函数,它是private权限的,不能由内部调用的。其余三个函数是public权限,供咱们所调用。那么,Optional的实质,就是外部贮存了一个实在的值,在结构的时候,就直接判断其值是否为空。好吧,这么说还是比拟形象。间接上Optional(T value)构造函数的源码,如下图所示那么,of(T value)的源码如下 public static <T> Optional<T> of(T value) { return new Optional<>(value);}也就是说of(T value)函数外部调用了构造函数。依据构造函数的源码咱们能够得出两个论断: 通过of(T value)函数所结构出的Optional对象,当Value值为空时,仍然会报NullPointerException。 通过of(T value)函数所结构出的Optional对象,当Value值不为空时,能失常结构Optional对象。 除此之外呢,Optional类外部还保护一个value为null的对象,大略就是长上面这样的 public final class Optional<T> { //省略.... private static final Optional<?> EMPTY = new Optional<>(); private Optional() { this.value = null; } //省略... public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }}那么,empty()的作用就是返回EMPTY对象。 ...

May 24, 2021 · 3 min · jiezi

关于jdk8:函数式接口实现以及专业化

函数式接口 实现类接口Current Interface Preferred InterfaceFunction<Integer, R> IntFunction<R>Function<Long, R> LongFunction<R>Function<Double, R> DoubleFunction<R>Function<Double,Integer> DoubleToIntFunctionFunction<Double,Long> DoubleToLongFunctionFunction<Long,Double> LongToDoubleFunctionFunction<Long,Integer> LongToIntFunctionFunction<R,Integer> ToIntFunction<R>Function<R,Long> ToLongFunction<R>Function<R,Double>. ToDoubleFunction<R>Function<T,T>. UnaryOperator<T>BiFunction<T,T,T> BinaryOperator<T>Consumer<Integer> IntConsumerConsumer<Double> DoubleConsumerConsumer<Long> LongConsumerBiConsumer<T,Integer> ObjIntConsumer<T>BiConsumer<T,Long> ObjLongConsumer<T>BiConsumer<T,Double> ObjDoubleConsumer<T>Predicate<Integer> IntPredicatePredicate<Double> DoublePredicatePredicate<Long> LongPredicateSupplier<Integer> IntSupplierSupplier<Double> DoubleSupplierSupplier<Long> LongSupplierSupplier<Boolean> BooleanSupplierUnaryOperator<Integer> IntUnaryOperatorUnaryOperator<Double> DoubleUnaryOperatorUnaryOperator<Long> LongUnaryOperatorBinaryOperator<Integer> IntBinaryOperatorBinaryOperator<Long> LongBinaryOperatorBinaryOperator<Double> DoubleBinaryOperatorFunction<T, Boolean> Predicate<T>BiFunction<T,U,Boolean> BiPredicate<T,U>

December 19, 2020 · 1 min · jiezi

关于jdk8:JDK8中的新时间APIDuration-Period和ChronoUnit介绍

简介在JDK8中,引入了三个十分有用的工夫相干的API:Duration,Period和ChronoUnit。 他们都是用来对工夫进行统计的,本文将会具体解说一下这三个API的应用。 DurationDuration次要用来掂量秒级和纳秒级的工夫,应用于工夫精度要求比拟高的状况。 先来看看Duration的定义: public final class Duration implements TemporalAmount, Comparable<Duration>, Serializable能够看到,Duration是一个final class,并且它是可序列化和可比拟的。咱们留神,Duration还实现了TemporalAmount接口。 那么TemporalAmount接口是什么呢? TemporalAmount是Duration和Period的父接口。 它定义了4个必须要实现的办法: long get(TemporalUnit unit);List<TemporalUnit> getUnits();Temporal addTo(Temporal temporal);Temporal subtractFrom(Temporal temporal);其中TemporalUnit代表的是工夫对象的单位,比方:years, months, days, hours, minutes 和 seconds.而Temporal代表的是对工夫对象的读写操作。 咱们看下Duration的一些基本操作: Instant start = Instant.parse("2020-08-03T10:15:30.00Z"); Instant end = Instant.parse("2020-08-03T10:16:30.12Z"); Duration duration = Duration.between(start, end); log.info("{}",duration.getSeconds()); log.info("{}",duration.getNano()); log.info("{}",duration.getUnits());下面咱们创立了两个Instant,而后应用Duration.between办法来测算他们之间的差别。 其中秒局部的差别,应用duration.getSeconds()来获取,而秒以下精度局部的差别,咱们应用duration.getNano()来获取。 最初咱们应用duration.getUnits()来看一下duration反对的TemporalUnit(工夫单位)。 看下执行后果: INFO com.flydean.time - 60 INFO com.flydean.time - 120000000 INFO com.flydean.time - [Seconds, Nanos]除了Instance,咱们还能够应用LocalTime: ...

November 5, 2020 · 1 min · jiezi

关于jdk8:JDK源码那些事儿之传说中的AQS独占锁

上一篇文章中笔者曾经介绍过AQS的基础知识,然而更加具体的源码实现还未波及,本篇文章笔者就联合具体的AQS实现类来聊一聊AQS的独占锁实现过程 前言JDK版本号:1.8.0_171之前的文章中曾经介绍过,AQS是一套多线程访问共享资源的同步器框架实现,开发者只须要依照需要在实现类中实现对应的办法即可实现锁或者同步器的构建,在AQS的源码正文局部,如果你有认真看过的话应该会留神到,作者举了2个简略的例子,一个是独占锁实现Mutex,另一个是共享锁实现BooleanLatch 作为示例笔者就以这两个简略的锁实现联合AQS的具体方法来进行解说阐明,这里揭示下请先看下笔者的上篇文章JDK源码那些事儿之传说中的AQS-概览,理解AQS的基本知识,同时浏览下之前对Object和LockSupport的解说,笔者默认读者应该曾经理解了这些相干知识点 其次,集体认为初学者学习AQS的源码须要多思考多debug,多看几遍本篇文章能力了解。因为篇幅过长,笔者这篇文章只解说简略的独占锁实现流程 示例先来看下源码作者实现的独占锁Mutex,能够看到封装了外部类Sync继承AbstractQueuedSynchronizer实现了独占锁须要的几个办法,这里次要是tryAcquire,tryRelease,其余办法留给读者自行深刻,这里再温习下AQS定义这两个办法的含意: tryAcquire:独占模式尝试获取资源,胜利则返回true,失败则返回falsetryRelease:独占模式尝试开释资源,胜利则返回true,失败则返回false这里先理解下即可,可略过持续看上面的测试代码实现 class Mutex implements Lock, Serializable { // Our internal helper class private static class Sync extends AbstractQueuedSynchronizer { // Reports whether in locked state @Override protected boolean isHeldExclusively() { return getState() == 1; } // Acquires the lock if state is zero @Override public boolean tryAcquire(int acquires) { assert acquires == 1; // Otherwise unused if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } // Releases the lock by setting state to zero @Override protected boolean tryRelease(int releases) { assert releases == 1; // Otherwise unused if (getState() == 0) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); return true; } // Provides a Condition Condition newCondition() { return new ConditionObject(); } // Deserializes properly private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } } // The sync object does all the hard work. We just forward to it. private final Sync sync = new Sync(); @Override public void lock() { sync.acquire(1); } @Override public boolean tryLock() { return sync.tryAcquire(1); } @Override public void unlock() { sync.release(1); } @Override public Condition newCondition() { return sync.newCondition(); } public boolean isLocked() { return sync.isHeldExclusively(); } public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } @Override public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } @Override public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); }}笔者这里写了一个简略的应用示例供大家参考,其中应用了CountDownLatch,仅仅是保障线程池中的所有线程同一时刻争抢Mutex独占锁,读者能够不必过多关注,把这个去掉也能够,不是重点,咱们重点关注下Mutex的应用即可,最终的后果想必读者也能猜到,其中的线程一个一个争抢到锁能力执行业务逻辑操作 ...

October 24, 2020 · 5 min · jiezi

关于jdk8:Centos7-安装Oracle-JDK18和OpenJDK-18

首先:Oracle JDK和OpenJDK装任何一个就能够了.Oracle JDK和OpenJDK的区别: Oracle JDK由Oracle公司开发,该公司是Sun许可证,基于Java标准版标准实现。它以二进制产品的模式公布。它反对多种操作系统,如Windows,Linux,Solaris,MacOS等。它反对不同的平台,如Intel 32位和64位架构,ARM架构和SPARC。它齐全基于Java编程语言。之后,该许可证发表将依据GPL(通用公共许可证)许可证公布。Oracle JDK蕴含许多组件作为库模式的编程工具汇合OpenJDK是Java SE平台版的开源和收费实现,它是Sun Corporation(当初的Oracle Corporation)于2006年开始的开发后果。它是依据GNU GPL许可证受权的。它最后于2007年公布。它由Oracle Corporation,Red Hat,IBM,Apple Inc.,OpenJDK和Java Community等开发。它是应用C ++和Java编程语言编写的。它反对不同的操作系统,如FreeBSD,Linux,Microsoft Windows,Mac OS X. OpenJDK是Java SE Platform Edition的官网参考实现。 Oracle与OpenJDK之间比拟Oracle JDKOpenJDK执照它是依据GPL(通用公共许可证)许可证受权的它是依据GNU GPL(通用公共许可证)许可证受权的倒退由Sun Microsystems Inc.开发由Oracle,OpenJDK和Java社区开发性能依据Sun JDK的开发和实现提供性能提供由Oracle JDK之上的一些供应商开发的高性能可扩展性依据Sun的施行能够应用其余库或Oracle JDK进行改良费用Sun的官网执行许可证开源和收费施行可供收费应用速度由Sun Microsystems Inc.开发第三方供应商将通过进行一些调整来进步JVM的速度操作系统反对Windows,Linux,Solaris,MacOSFreeBSD,Linux,Microsoft Windows,Mac OS X.便于应用能够与任何利用程序开发一起应用能够与任何利用程序开发和其余开源工具一起应用,以进步开源实现模型的性能。Oracle JDK1.8的装置1.下载 jdk-8u261-linux-x64.tar.gz链接: https://pan.baidu.com/s/1_x5W... 明码: 6pat 2.创立目录 # 把 jdk-8u261-linux-x64.tar.gz通过ftp传送到Centos7服务器> mkdir /usr/local/java> tar -xzvf jdk-8u261-linux-x64.tar.gz -C /usr/local/java> mv /usr/local/java/jdk1.8.0_261 /usr/local/java/jdk1.83.配置环境变量 > vi /etc/profile# 增加JAVA_HOME环境变量到文件开端export JAVA_HOME=/usr/local/java/jdk1.8export PATH=${JAVA_HOME}/bin:${PATH}> source /etc/profile4.测试 > java -versionOpen JDK1.8的装置1.查看jdk1.8可用版本 ...

October 6, 2020 · 1 min · jiezi

关于jdk8:啃碎String源码

前言最近打算开始来读一下JDK的局部源码,这次先从咱们平时用的最多的String类(JDK1.8)开始,本文次要会对以下几个办法的源码进行剖析: equalshashCodeequalsIgnoreCaseindexOfstartsWithconcatsubstringsplittrimcompareTo如果有不对的中央请多多指教,那么开始进入注释。 源码分析equalsequals() 办法用于判断 Number 对象与办法的参数进是否相等String类重写了父类Object的equals办法,来看看源码实现: 首先会判断两个对象是否指向同一个地址,如果是的话则是同一个对象,间接返回true接着会应用instanceof判断指标对象是否是String类型或其子类的实例,如果不是的话则返回false接着会比拟两个String对象的char数组长度是否统一,如果不统一则返回false最初迭代顺次比拟两个char数组是否相等hashCodehashCode() 办法用于返回字符串的哈希码Hash算法就是一种将任意长度的消息压缩到某一固定长度的音讯摘要的函数。在Java中,所有的对象都有一个int hashCode()办法,用于返回hash码。 依据官网文档的定义:Object.hashCode() 函数用于这个函数用于将一个对象转换为其十六进制的地址。依据定义,如果2个对象雷同,则其hash码也应该雷同。如果重写了 equals() 办法,则原 hashCode() 办法也一并生效,所以也必须重写 hashCode() 办法。 依照下面源码举例说明: String msg = "abcd"; System.out.println(msg.hashCode());此时value = {'a','b','c','d'}  因而for循环会执行4次 第一次:h = 31*0 + a = 97 第二次:h = 31*97 + b = 3105 第三次:h = 31*3105 + c = 96354 第四次:h = 31*96354 + d = 2987074  由以上代码计算能够算出 msg 的hashcode = 2987074 在源码的hashcode的正文中还提供了一个多项式计算形式: s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1]另外,咱们能够看到,计算中应用了31这个质数作为权进行计算。能够尽可能保障数据分布更扩散 在《Effective Java》中有提及: ...

October 4, 2020 · 3 min · jiezi

JDK源码那些事儿之LinkedBlockingDeque

阻塞队列中目前还剩下一个比较特殊的队列实现,相比较前面讲解过的队列,本文中要讲的LinkedBlockingDeque比较容易理解了,但是与之前讲解过的阻塞队列又有些不同,从命名上你应该能看出一些端倪,接下来就一起看看这个特殊的阻塞队列 前言JDK版本号:1.8.0_171LinkedBlockingDeque在结构上有别于之前讲解过的阻塞队列,它不是Queue而是Deque,中文翻译成双端队列,双端队列指可以从任意一端入队或者出队元素的队列,实现了在队列头和队列尾的高效插入和移除 LinkedBlockingDeque是链表实现的线程安全的无界的同时支持FIFO、LIFO的双端阻塞队列,可以回顾下之前的LinkedBlockingQueue阻塞队列特点,本质上是类似的,但是又有些不同: 内部是通过Node节点组成的链表来实现的,当然为了支持双端操作,结点结构不同LinkedBlockingQueue通过两个ReentrantLock锁保护竞争资源,实现了多线程对竞争资源的互斥访问,入队和出队互不影响,可同时操作,然而LinkedBlockingDeque只设置了一个全局ReentrantLock锁,两个条件对象实现互斥访问,性能上要比LinkedBlockingQueue差一些无界,默认链表长度为Integer.MAX_VALUE,本质上还是有界阻塞队列,是指多线程访问竞争资源时,当竞争资源已被某线程获取时,其它要获取该资源的线程需要阻塞等待Queue和Deque的关系有点类似于单链表和双向链表,LinkedBlockingQueue和LinkedBlockingDeque的内部结点实现就是单链表和双向链表的区别,具体可参考源码 在第二点中可能有些人有些疑问,两个互斥锁和一个互斥锁的区别在哪里?我们可以考虑以下场景: A线程先进行入队操作,B线程随后进行出队操作,如果是LinkedBlockingQueue,A线程入队过程还未结束(已获得锁还未释放),B线程出队操作不会被阻塞等待(锁不同),如果是LinkedBlockingDeque则B线程会被阻塞等待(同一把锁)A线程完成操作才继续执行 LinkedBlockingQueue一般的操作是获取一把锁就可以,但有些操作例如remove操作,则需要同时获取两把锁,之前的LinkedBlockingQueue讲解曾经说明过,这里就不详细讲解了 类定义实现BlockingDeque接口,其中定义了双端队列应该实现的方法,具体方法不说明了,主要是每个方法都分为了First和Last两种方式,从头部或者尾部进行队列操作 public class LinkedBlockingDeque<E> extends AbstractQueue<E> implements BlockingDeque<E>, java.io.Serializable 常量/变量 /** * 头结点 */ transient Node<E> first; /** * 尾结点 */ transient Node<E> last; /** 双端队列实际结点个数 */ private transient int count; /** 双端队列容量 */ private final int capacity; /** 互斥重入锁 */ final ReentrantLock lock = new ReentrantLock(); /** 非空条件对象 */ private final Condition notEmpty = lock.newCondition(); /** 非满条件对象 */ private final Condition notFull = lock.newCondition();内部类为了实现双端队列,内部使用了双向链表,不像LinkedBlockingQueue使用的是单链表,前驱和后继指针的特殊情况需要注意 ...

November 2, 2019 · 6 min · jiezi

JDK源码那些事儿之SynchronousQueue上篇

今天继续来讲解阻塞队列,一个比较特殊的阻塞队列SynchronousQueue,通过Executors框架提供的线程池cachedThreadPool中我们可以看到其被使用作为可缓存线程池的队列实现,下面通过源码来了解其内部实现,便于后面帮助我们更好的使用线程池 前言JDK版本号:1.8.0_171synchronousQueue是一个没有数据缓冲的阻塞队列,生产者线程的插入操作put()必须等待消费者的删除操作take(),反过来也一样。当然,也可以不进行等待直接返回,例如poll和offer 在使用上很好理解,每次操作都需要找到对应的匹配操作,如A线程通过put插入操作填入值1,如果无其他线程操作则需要阻塞等待一个线程执行take操作A线程才能继续,反过来同样道理,这样看似乎synchronousQueue是没有队列进行保存数据的,每次操作都在等待其互补操作一起执行 这里和其他阻塞队列不同之处在于,内部类将入队出队操作统一封装成了一个接口实现,内部类数据保存的是每个操作动作,比如put操作,保存插入的值,并根据标识来判断是入队还是出队操作,如果是take操作,则值为null,通过标识符能判断出来是出队操作 多思考下,我们需要找到互补的操作必然需要一个公共的区域来判断已经发生的所有操作,内部类就是用来进行这些操作的,SynchronousQueue分为公平策略(FIFO)和非公平策略(LIFO),两种策略分别对应其两个内部类实现,公平策略使用队列结构实现,非公平策略使用栈结构实现 由于篇幅过长,本篇先说明SynchronousQueue相关知识和公平策略下的实现类TransferQueue,下篇将说明非公平策略下的实现类TransferStack和其他知识 类定义public class SynchronousQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable 常量/变量 /** The number of CPUs, for spin control */ // cpu数量,会在自旋控制时使用 static final int NCPUS = Runtime.getRuntime().availableProcessors(); // 自旋次数,指定了超时时间时使用,这个常量配合CAS操作使用,相当于循环次数 // 如果CAS操作失败,则根据这个参数判断继续循环 static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32; // 自旋次数,未指定超时时间时使用 static final int maxUntimedSpins = maxTimedSpins * 16; /** * The number of nanoseconds for which it is faster to spin * rather than to use timed park. A rough estimate suffices. */ // 自旋超时时间阈值,在设置的时间超过这个时间时以这个时间为准,单位,纳秒 static final long spinForTimeoutThreshold = 1000L; // 后进先出队列和先进先出队列 @SuppressWarnings("serial") static class WaitQueue implements java.io.Serializable { } static class LifoWaitQueue extends WaitQueue { private static final long serialVersionUID = -3633113410248163686L; } static class FifoWaitQueue extends WaitQueue { private static final long serialVersionUID = -3623113410248163686L; } // 序列化操作使用 private ReentrantLock qlock; private WaitQueue waitingProducers; private WaitQueue waitingConsumers; /** * The transferer. Set only in constructor, but cannot be declared * as final without further complicating serialization. Since * this is accessed only at most once per public method, there * isn't a noticeable performance penalty for using volatile * instead of final here. */ // 所有的队列操作都通过transferer来执行,统一方法执行 // 初始化时会根据所选的策略实例化对应的内部实现类 private transient volatile Transferer<E> transferer;从上边也能看出没有设置变量来保存入队出队操作的数据,统一操作方法都放置到了Transferer中 ...

September 7, 2019 · 9 min · jiezi

Ubuntu-JDK-PPA-安装失败的解决办法

Ubuntu JDK PPA 安装失败的解决办法最后一次更新于 2019/08/05 报错我大概是半年没用 Ubuntu 了, 今天刚想升级 Java JDK 就得到了下方的报错: 正在连接 download.oracle.com (download.oracle.com)|23.196.196.76|:443... 已连接。已发出的 HTTP 请求, 正在等待回应... 404 Not Found2019-08-05 18:03:51 错误 404: Not Found.download failedOracle JDK 8 is NOT installed.dpkg: 处理软件包 oracle-java8-installer (--configure)时出错: 子进程 已安装 post-installation 脚本 返回错误状态 1错误排查我寻思半天,经过反复尝试,最终确认是 Oracle 爸爸要坑我。不知道为啥 Google 搜索里没搜到这个错误出现的原因,所以我今天跟大家解释一下,帮助大家避一下坑。 首先得从 wget 说起。简单来说它是个 HTTP GET 请求,在以前个大网站不设安全验证的时期相当高效好用。Oracle 爸爸告诉你: 不,你以后想都别想。那么"想都别想"的这一天从什么时候开始呢?肯定跟这一天有关系: Oracle 为了确保 JDK 不被滥用,强制要求下载前必须登录 Oracle 账户。给不了解 HTTP 请求的朋友们稍微科普一下, GET 请求是直接访问对应 URL 的,处于无账户状态。而 POST 请求在访问对应 URL 的同时,会附带 json 数据,在这里指的就是 Oracle 账户的用户名和密码。 ...

August 27, 2019 · 1 min · jiezi

必看java后端亮剑诛仙最全知识点

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。你可能有所感悟。零散的资料读了很多,但是很难有提升。到处是干货,但是并没什么用,简单来说就是缺乏系统化。另外,噪音太多,雷同的框架一大把,我不至于全都要去学了吧。 这里,我大体根据基础、Java基础、Java进阶给分了下类,挑的也都是最常用最重要的工具。 这篇文章耗费了我大量的精力,你要是觉得好,请不要吝啬你的赞。如果你认同,可以关注我的微信公众号xjjdog,里面讲的就是这些内容。我会尝试更加系统化。 最新的内容会在github持续更新,添加新的精选相关文章。地址: https://github.com/sayhiai/javaok基础知识数据结构基本的数据结构是非常重要的,无论接触什么编程语言,这些基本数据结构都是首先要掌握的。具体的实现,就体现在java的集合类中。这些数据结构,就是这些复杂工具的具体原始形态,要烂记于心。 培训机构一般没有时间普及基础知识,通过算法和数据结构,“通常”能够一眼看出是否是经过培训。 常用算法算法是某些大厂的门槛。毫无疑问,某些参加过ACM的应届生,能够秒杀大多数工作多年的码农。算法能够培养逻辑思维能力和动手能力,在刚参加工作的前几年,是非常大的加分项。但随着工作年限的增加,它的比重在能力体系中的比重,会慢慢降低。 算法的学习方式就是通过不断的练习与重复。不精此道的同学,永远不要试图解决一个没见过的问题。一些问题的最优解,可能耗费了某个博士毕生的精力,你需要的就是理解记忆以及举一反三。最快的进阶途径就是刷leetcode。 对于普通研发,排序算法和时间复杂度是必须要掌握的,也是工作和面试中最常用的。时间充裕,也可涉猎动态规划、背包等较高阶的算法知识,就是下图的左列。 书籍《算法导论》 《编程之美》 《数学之美》 数据库基础 MySQLMySQL是应用最广的关系型数据库。除了了解基本的使用和建模,一些稍底层的知识也是必要的。 MySQL有存储引擎的区别。InnoDB和MyISAM是最常用的,优缺点应该明晓。ACID是关系型数据库的基本属性,需要了解背后的事务隔离级别。脏读、幻读问题的产生原因也要了解。 为了加快查询速度,索引是数据库中非常重要的一个结构,B+树是最常用的索引结构。因字符集的问题,乱码问题也是经常被提及的。 专业的DBA通常能帮你解决一些规范和性能问题,但并不总是有DBA,很多事情需要后端自己动手。 书籍《MySQL技术内幕——InnoDB存储引擎》 《高性能MySQL》 《高可用MySQL》 网络基础网络通信是互联网时代最有魅力的一个特点,可以说我们的工作和生活,每时每刻都在和它打交道。 连接的三次握手和四次挥手,至今还有很多人非常模糊。造成的后果就是对网络连接处于的状态不慎了解,程序在性能和健壮性上大打折扣。 HTTP是使用最广泛的协议,通常都会要求对其有较深入的了解。对于Java来说,熟悉Netty开发是入门网络开发的捷径。 爬虫是网络开发中另外一个极具魅力的点,但建议使用python而不是java去做。 书籍《HTTP权威指南》 《TCP/IP详解 卷一》 操作系统 Linux科班出身的都学过《计算机组成机构》这门课,这非常重要,但很枯燥。结合Linux理解会直观的多。鉴于目前大多数服务器环境都是Linux,提前接触能够相辅相成。 需要搞清楚CPU、内存、网络、I/O设备之间的交互和速度差别。对于计算密集型应用,就需要关注程序执行的效率;对于I/O密集型,要关注进程(线程)之间的切换以及I/O设备的优化以及调度。这部分知识是开发一些高性能高可靠中间件的前提,无法绕过。 对于Linux,首先应该掌握的就是日常运维,包括常用命令的使用和软件安装配置。正则也是必须要掌握的一个知识点。 脚本编程对后端来说是一个非常大的加分项。它不仅能增加开发效率,也能在一些突发问题上使你游刃有余。 书籍《UNIX环境高级编程(第3版)》 《鸟哥的Linux私房菜》 《Linux内核设计与实现》 《Linux命令行大全》 相关文章《Linux上,最常用的一批命令解析(10年精选)》 Java基础JVMJava程序员的最爱和噩梦。以oracle版本为准,各个jvm版本之间有差别。JVM的知识包含两方面。一个是存储级别的,一个是执行级别的。 以存储为例,又分为堆内的和堆外的两种,各有千秋。垃圾回收器就是针对堆内内存设计的,目前最常用的有CMS和G1。JVM有非常丰富的配置参数来控制这个过程。在字节码层面,会有锁升级以及内存屏障一类的知识,并通过JIT编译来增加执行速度。 JVM还有一个内存模型JMM,用来协调多线程的并发访问。JVM的spec非常庞大,但面试经常提及。 另外,jdk还提供了一系列工具来窥探这些信息。包含jstat,jmap,jstack,jvisualvm等,都是最常用的。 书籍《深入理解Java虚拟机》 JDK现在,终于到了java程序员的核心了:JDK,一套依据jvm规范实现的一套API。我们平常的工作,就是组合这些API,来控制程序的行为。 jdk的代码非常庞大,内容也非常繁杂。最重要的大体包括:集合、多线程、NIO、反射、文件操作、Lambda语法等。这部分内容加上下面的SSM,基本上就是大多数小伙伴玩耍的地方。 假如说数据结构和算法是理论,这里就是支撑理论的实现。Java玩的好不好,就是说这里。 书籍《Effective Java 中文版》 《数据结构与算法分析:Java语言描述》 SSM你可能会用SSM开发项目,觉得编程无非就这些东西。设计模式烂记于心,IOC、AOP手到擒来。这里集中了大部分同行,有些可能到此为止就Ok了,因为有些同学接下来的重点是项目管理,而不是技术。 SSM最擅长的是Web开发。目前的表现形式逐渐多样化,随着前后端分离的盛行,Restful这种有着明确语义的模式逐渐流行。 书籍《Head First 设计模式》 《Spring揭秘》 《SpringBoot揭秘》 《MyBatis技术内幕》 《深入剖析Tomcat》 ...

August 18, 2019 · 1 min · jiezi

JDK源码那些事儿之并发ConcurrentHashMap下篇

上一篇文章已经就ConcurrentHashMap进行了部分说明,介绍了其中涉及的常量和变量的含义,有些部分需要结合方法源码来理解,今天这篇文章就继续讲解并发ConcurrentHashMap 前言本文主要介绍ConcurrentHashMap中的一些重要方法,结合上篇文章中的讲解部分进行更进一步的介绍 回顾下上篇文章,我们应该已经知道ConcurrentHashMap的整体结构和HashMap基本一致,不同的是处理多线程并发下保证操作的正确性,ConcurrentHashMap通过CAS和synchronized进行并发控制,当然,这种情况下各种处理都会变的更为复杂,下面我们就通过方法来深入理解ConcurrentHashMap的操作 重要方法在一些方法中展示了各个变量以及常量的使用,能让我们更好的理解其中的操作 tabAt/casTabAt/setTabAt下列方法用于读写table数组,使用Unsafe提供的更新获取volatile变量,CAS更新数组元素等操作 // 读取table[i] @SuppressWarnings("unchecked") static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) { return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE); } // CAS更新table[i] static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i, Node<K,V> c, Node<K,V> v) { return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v); } // 插入table[i] static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) { U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v); }sizesize方法返回了一个不精确的值,在多线程环境下,返回一个不精确的值,通过sumCount迭代counterCells统计sum值。 ...

July 6, 2019 · 10 min · jiezi

Java8中创建Stream-流的四种方式以及-Stream-中间操作

Stream api**Stream api 是java8 中提供的对集合处理的api , 对数据进行一系列的中间操作,元数据不会发生改变 集合讲的是数据, 流 讲的是计算(用于操作数据源,集合,数组)所生成的元素序列。** Stream API位于 java.util.stream.* 包下。1 Stream 自己不会存储元素 2 Stream 不会改变源对象。相反,他们会返回一个持有结果的性Sstream 。 3 Stream 操作是延迟执行的。这以为这他们会等到需要结果的时候才执行(延迟加载)。一 创建里Stream 流的四种方式### 1 第一种 通过Collection得Stream()方法(串行流)或者 parallelStream()方法(并行流)创建Stream。 List<String> list = Arrays.asList("1","2","3","4","0","222","33"); Stream<String> stream = list.stream(); Stream<String> stream1 = list.parallelStream();### 2 通过Arrays中得静态方法stream()获取数组流 IntStream stream = Arrays.stream(new int[]{1,2,3});### 3 通过Stream类中得 of()静态方法获取流 Stream<String> stream = Stream.of("a","b","c");### 4 创建无限流(迭代、生成) //迭代(需要传入一个种子,也就是起始值,然后传入一个一元操作) Stream<Integer> stream1 = Stream.iterate(2, (x) -> x * 2); //生成(无限产生对象) Stream<Double> stream2 = Stream.generate(() -> Math.random()); 二 Stream 中间操作多个中间操作可以连接起来形成一个流水线,除非流水线终止操作,否则中间操作不会执行任何处理。终止操作时一次性全部处理,称为“延迟加载”1 筛选切片1 过滤List<String> list = Arrays.asList("1","2","3","4","0","222","33");Stream<String> stream = list.stream().filter((x) -> { System.out.println(" api 中建操作。"); return x.equals("3"); }); //终止操作:只有执行终止操作才会执行全部。即:延迟加载 stream.forEach(System.out::println);结果 ...

July 3, 2019 · 4 min · jiezi

JDK源码那些事儿之并发ConcurrentHashMap上篇

前面前已经说明了HashMap以及红黑树的一些基本知识,对JDK8的HashMap也有了一定的了解,本篇就开始看看并发包下的ConcurrentHashMap,说实话,还是比较复杂的,笔者在这里也不会过多深入,源码层次上了解一些主要流程即可,清楚多线程环境下整个Map的运作过程就算是很大进步了,更细的底层部分需要时间和精力来研究,暂不深入 前言jdk版本:1.8JDK7中,ConcurrentHashMap把内部细分成了若干个小的HashMap,称之为段(Segment),默认被分为16个段。多线程写操作对每个段进行加锁,段与段之间互不影响。而JDK8则抛弃了这种结构,类似HashMap,多线程下为了保证线程安全,通过CAS和synchronized进行并发控制,降低锁颗粒度,性能上也就提高许多 同时由于降低锁粒度,同时需要兼顾读操作的正确性,增加了许多内部类来帮助完成并发控制,保证读操作的正确执行,同时支持了并发扩容操作,算是相当复杂了,由于过于复杂,对ConcurrentHashMap的说明将分为两章说明,本章就对ConcurrentHashMap的常量,变量,内部类和构造方法进行说明,下一章将重点分析其中的重要方法 这里先提前说明下,有个整体印象: ConcurrentHashMap结构上类似HashMap,即数组+链表+红黑树锁颗粒度降低,复杂度提升多线程并发扩容多线程下保证读操作正确性计数方式处理:分段处理函数式编程(不是本文重点,自行查阅)类定义public class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V>, Serializable 继承AbstractMap,实现了ConcurrentMap接口,ConcurrentMap也可以看看源码,加入了并发操作方法,是一个实现了并发访问的集合接口 常量有些常量和变量可能不是很好理解,在后边到方法时会尽量详细说明 /** * 最大容量 */ private static final int MAXIMUM_CAPACITY = 1 << 30; /** * 默认初始化容量,同HashMap,必须为2的倍数 */ private static final int DEFAULT_CAPACITY = 16; /** * 可能达到的最大的数组大小值(非2的次幂),2的31次方-8 */ static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 默认并发级别,新版本无用,为了兼容旧版本,使用的地方在序列化方法writeObject中 */ private static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** * 负载因子,只是为了兼容性 * 构造方法里指定的负载因子只会影响初始化的table容量 * 一般也不使用浮点数计算 * ConcurrentHashMap不会使用这个常量,而使用类似 n -(n >>> 2) 的方式来进行调整大小 */ private static final float LOAD_FACTOR = 0.75f; /** * 树化阈值 * 同HashMap */ static final int TREEIFY_THRESHOLD = 8; /** * 调整大小时树转化为链表的阈值 */ static final int UNTREEIFY_THRESHOLD = 6; /** * 可以转化为红黑树的最小数组容量,即调整为红黑树时数组长度最小值必须为MIN_TREEIFY_CAPACITY * 如果bin包含太多节点,则会调整表的大小 * 该值应至少为4 * TREEIFY_THRESHOLD,避免扩容和树化阈值之间的冲突。 */ static final int MIN_TREEIFY_CAPACITY = 64; /** * * 扩容的每个线程每次最少要迁移16个hash桶 * 每个线程都可参与迁移任务,每个线程至少要连续迁移MIN_TRANSFER_STRIDE个hash桶 * 帮助扩容提高了效率,当然复杂性也提高了很多,要处理的事情更多 */ private static final int MIN_TRANSFER_STRIDE = 16; /** * 与移位量和最大线程数相关 * 先了解就好,后边涉及到方法会进行说明 */ private static int RESIZE_STAMP_BITS = 16; /** * 帮助扩容的最大线程数 */ private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1; /** * 移位量 */ private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS; /** * Node hash值编码,规定了各自的含义 */ // forwarding nodes节点hash值 // 临时节点,扩容时出现,不存储实际数据 // 如果旧数组的一个hash桶中全部的节点都迁移到新数组中,旧数组就在这个hash桶中放置一个ForwardingNode // 读操作遇见该节点时,转到新的table数组上执行,写操作遇见时,则帮助扩容 static final int MOVED = -1; // hash for forwarding nodes // TREEBIN节点 // TreeBin是ConcurrentHashMap中用于代理操作TreeNode的特殊节点 // 保存实际的红黑树根节点,在红黑树插入节点时会对读操作造成影响,该对象维护了一个读写锁来保证多线程的正确性 static final int TREEBIN = -2; // hash for roots of trees // ReservationNode节点hash值 // 保留节点,JDK8的新特性会用到,这里不过多说明 static final int RESERVED = -3; // hash for transient reservations // 负数转正数,定位hash桶时用到了,负数Hash值有特殊含义,具体看后边 static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash // CPU数量,限制边界,计算一个线程需要做多少迁移量 static final int NCPU = Runtime.getRuntime().availableProcessors(); // 序列化兼容性 private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("segments", Segment[].class), new ObjectStreamField("segmentMask", Integer.TYPE), new ObjectStreamField("segmentShift", Integer.TYPE) };变量 /** * The array of bins. Lazily initialized upon first insertion. * Size is always a power of two. Accessed directly by iterators. * * volatile保证可见性 * Node类和HashMap中的类似,val和next属性通过volatile保证可见性 */ transient volatile Node<K,V>[] table; /** * The next table to use; non-null only while resizing. * * 扩容时使用的数组,只在扩容时非空,扩容时会创建 */ private transient volatile Node<K,V>[] nextTable; /** * Table initialization and resizing control. When negative, the * table is being initialized or resized: -1 for initialization, * else -(1 + the number of active resizing threads). Otherwise, * when table is null, holds the initial table size to use upon * creation, or 0 for default. After initialization, holds the * next element count value upon which to resize the table. * * sizeCtl = -1,表示有线程在进行初始化操作 * sizeCtl < 0且不为-1表示有多个线程正在进行扩容操作,jdk源码解释部分感觉有点问题 * 每次第一个线程参与扩容时,会将sizeCtl设置为一个与当前table长度相关的数值,避免出现问题,讲解方法时进行说明 * sizeCtl > 0,表示第一次初始化操作中使用的容量,或者初始化/扩容完成后的阈值 * sizeCtl = 0,默认值,此时在真正的初始化操作中使用默认容量 */ private transient volatile int sizeCtl; /** * 多线程帮助扩容相关 * 下一个transfer任务的起始下标index + 1 的值 * transfer时下标index从length - 1到0递减 * 扩容index从后往前和迭代从前往后为了避免冲突 */ private transient volatile int transferIndex; /** * Base counter value, used mainly when there is no contention, * but also as a fallback during table initialization * races. Updated via CAS. * * 计数器基础值,记录元素个数,通过CAS操作进行更新 */ private transient volatile long baseCount; /** * Spinlock (locked via CAS) used when resizing and/or creating CounterCells. * * CAS自旋锁标志位,counterCells扩容或初始化时使用 */ private transient volatile int cellsBusy; /** * Table of counter cells. When non-null, size is a power of 2. * * 高并发下计数数组,counterCells数组非空时大小是2的n次幂 */ private transient volatile CounterCell[] counterCells; // views private transient KeySetView<K,V> keySet; private transient ValuesView<K,V> values; private transient EntrySetView<K,V> entrySet;同时需要注意静态代码块中已经获取了一些变量在对象中的内存偏移量,这个是为了方便我们在CAS中的使用,如果不明白CAS,请自行查阅资料学习,源码如下: ...

June 23, 2019 · 11 min · jiezi

JDK源码那些事儿之常用的ArrayList

前面已经讲解集合中的HashMap并且也对其中使用的红黑树结构做了对应的说明,这次就来看下简单一些的另一个集合类,也是日常经常使用到的ArrayList,整体来说,算是比较好理解的集合了,一起来看下 前言jdk版本:1.8类定义public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable继承了AbstractList,实现了List,提供对数组队列的增删改查操作实现RandomAccess接口,提供随机访问功能实现Cloneable接口,提供克隆功能实现Serializable接口,支持序列化,方便序列化传输 变量说明 private static final long serialVersionUID = 8683452581122892189L; /** * 默认的初始化容量 * 这里和HashMap初始容量不同,默认10 * 有些面试官可能问,虽然我感觉没必要记这玩意 */ private static final int DEFAULT_CAPACITY = 10; /** * 空集合,在构造函数中看说明 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 默认容量大小的空集合,这里和上边一样,但是第一次添加的时候会自动扩容到默认容量,看构造函数的说明 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. * * 基于数组实现容量大小变化,上边注释也说了第一次添加元素时,将容量扩展到DEFAULT_CAPACITY * 更详细的接着往下看 */ transient Object[] elementData; // non-private to simplify nested class access /** * 数组长度,即arraylist的长度 */ private int size; /** * 最大数组长度限制 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;从上边变量定义也能看出来ArrayList本质上是基于Object[]实现,故方法上的操作都是基于数组来进行 ...

May 11, 2019 · 7 min · jiezi

JDK源码那些事儿之HashMapTreeNode

前面几篇文章已经讲解过HashMap内部实现以及红黑树的基础知识,今天这篇文章就讲解之前HashMap中未讲解的红黑树操作部分,如果没了解红黑树,请去阅读前面的两篇文章,能更好的理解本章所讲解的红黑树源码操作,全文默认读者已经了解红黑树的相关知识,接下来,就以HashMap.TreeNode来说明红黑树的源码操作。 前言jdk版本:1.8以HashMap.TreeNode为例是因为之前HashMap的红黑树操作在文章省略了,这里进行一个解释,其实源码里并不是只有这个地方用红黑树结构,但是总体上都大同小异,故只说明这一部分就好,举一反三的能力相信各位都应该拥有。 类定义 static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V>继承LinkedHashMap.Entry,追溯源头可以到HashMap.Node,下面图展示了对应的结构关系: 属性 /** * 父节点 */ TreeNode<K,V> parent; // red-black tree links /** * 左子节点 */ TreeNode<K,V> left; /** * 右子节点 */ TreeNode<K,V> right; /** * 指向前一个节点 */ TreeNode<K,V> prev; // needed to unlink next upon deletion /** * 是否是红色节点 */ boolean red;以上的属性都是为了满足红黑树特性而设置 构造方法 /** * 构造方法直接调用的父类方法 * 最终还是HashMap.Node的构造方法,调用代码下面也列出来了 */ TreeNode(int hash, K key, V val, Node<K,V> next) { super(hash, key, val, next); } /** * HashMap.Node subclass for normal LinkedHashMap entries. */ static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,V> before, after; Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } } Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; }Node和TreeNode相同的构造方法 ...

May 3, 2019 · 12 min · jiezi

深入理解 lambda表达式 与 函数式编程 函数式接口源码解析(二)

package com.java.design.java8;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.Arrays;import java.util.Comparator;import java.util.List;import java.util.function.*;import java.util.stream.Collectors;/** * @author 陈杨 /@RunWith(SpringRunner.class)@SpringBootTestpublic class FuncInterface {一、函数式编程的理解// 函数式编程的理解//// 函数接口式编程 是 对 业务应用的进一步抽象// 在类方法定义中 只需实现FunctionalInterface 而不管业务实现的逻辑// 在外部应用 调用该业务时 使用Lambda表达式 灵活实现其业务逻辑二、 函数式接口的测试方法1、Function接口// FunctionFunction<Integer, Integer> sum = integer -> integer + 1;Function<Integer, Integer> multiply = integer -> integer * integer;List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);public int testFunctionCompose(Integer integer) { return sum.compose(multiply).apply(integer);}public int testFunctionAndThen(Integer integer) { return sum.andThen(multiply).apply(integer);}2、BiFunction接口// BiFunctionBiFunction<Integer, Integer, Integer> subtract = (first, last) -> first - last;public int testBiFunctionAndThen(Integer first, Integer last) { return subtract.andThen(multiply).apply(first, last);}3、BinaryOperator接口// BinaryOperatorBinaryOperator<Integer> binaryOperator = (first, last) -> first - last;public int testBinaryOperator(Integer first, Integer last) { return binaryOperator.apply(first, last);}public String testMinBy(String first, String last, Comparator<String> comparator) { return BinaryOperator.minBy(comparator).apply(first, last);}public String testMaxBy(String first, String last, Comparator<String> comparator) { return BinaryOperator.maxBy(comparator).apply(first, last);}//比较器//比较字符串的长度Comparator<String> length = (first, last) -> first.length() - last.length();//比较字符串首字母ASCII码大小Comparator<String> asc = (first, last) -> first.charAt(0) - last.charAt(0);4、Predicate接口// Predicatepublic List<Integer> testPredicate(Predicate<Integer> predicate) { return list.stream().filter(predicate).collect(Collectors.toList());}public Predicate<String> isEqual(Object object) { return Predicate.isEqual(object);}public Predicate<Integer> notPredicate(Predicate<Integer> predicate) { return Predicate.not(predicate);}public List<Integer> testPredicateNegate(Predicate<Integer> predicate) { return list.stream().filter(predicate.negate()).collect(Collectors.toList());}public List<Integer> testPredicateAnd(Predicate<Integer> first, Predicate<Integer> last) { return list.stream().filter(first.and(last)).collect(Collectors.toList());}public List<Integer> testPredicateOr(Predicate<Integer> first, Predicate<Integer> last) { return list.stream().filter(first.or(last)).collect(Collectors.toList());}5、Supplier接口// Supplier@Data@AllArgsConstructor@NoArgsConstructorprivate class Student { private Integer id; private String name; private String sex; private Integer age; private String addr; private Double salary;}三、测试结果 . ____ _ __ _ _ /\ / ’ __ _ () __ __ _ \ \ \ ( ( )__ | ‘_ | ‘| | ‘ / ` | \ \ \ \ \/ )| |)| | | | | || (| | ) ) ) ) ’ || .__|| ||| |_, | / / / / =========||==============|/=//// :: Spring Boot :: (v2.1.2.RELEASE)2019-01-31 11:51:58.460 INFO 12080 — [ main] com.java.design.java8.FuncInterface : Starting FuncInterface on DESKTOP-87RMBG4 with PID 12080 (started by 46250 in E:\IdeaProjects\design)2019-01-31 11:51:58.461 INFO 12080 — [ main] com.java.design.java8.FuncInterface : No active profile set, falling back to default profiles: default2019-01-31 11:51:58.988 INFO 12080 — [ main] com.java.design.java8.FuncInterface : Started FuncInterface in 0.729 seconds (JVM running for 1.556)——————–Function接口的理解———————6581——————BiFunction接口的理解———————64——————-Predicate接口的理解———————获取满足条件的集合:大于4[5, 6, 7, 8, 9]——————————获取满足条件的集合:大于4且是偶数[6, 8]——————————获取满足条件的集合:大于4 取反[1, 2, 3, 4, 0]——————————获取满足条件的集合:大于4或是偶数[2, 4, 5, 6, 7, 8, 9, 0]——————————使用Objects的Equals方法判断对象是否相同true——————————Predicate.not()返回(Predicate<T>)target.negate(); [1, 2, 3, 4, 0]——————————双重否定表肯定[5, 6, 7, 8, 9]————————————————-Supplier接口的理解———————FuncInterface.Student(id=1, name=Kirito, sex=Male, age=18, addr=ShenZhen, salary=9.99999999E8)———————————————BinaryOperator接口的理解——————-继承BiFunction的Apply方法 实现减法10 - 2 = 8——————————字符串较短的是:Asuna字符串较长的是:Kirito——————————字符串首字母ASCII码较小的是:Asuna字符串首字母ASCII码较大的是:KiritoProcess finished with exit code 0四、透过现象看本质 函数式接口的源码实现1、Function接口@Testpublic void testFuncInterface() { System.out.println("——————–Function接口的理解———————\n"); // Function接口的理解 // public interface Function<T, R> // R apply(T t); // Represents a function that accepts one argument and produces a result. // 一个函数:接收一个参数 返回一个结果 // T 输入类型 R 输出类型 /default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } * Returns a composed function that first applies the {@code before} * function to its input, and then applies this function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. / // 输入–>beforeFunction()处理–>得到结果作为下一个函数apply()的输入参数 形成函数式接口的串联调用 // beforeFunction 在当前函数apply前 进行调用 /default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } * Returns a composed function that first applies this function to * its input, and then applies the {@code after} function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. / // 输入–>apply()处理–>得到结果作为下一个函数after.apply()的输入参数 形成函数式接口的串联调用 // afterFunction 在当前函数apply后 进行调用 /static <T> Function<T, T> identity() { return t -> t; * Returns a function that always returns its input argument. }/ // 总是返回输入参数 // 总结: // function1.compose(function2) 执行顺序 –>BeforeFunction()–>thisFunction()–> function2 –> function1 // function1.andThen(function2) 执行顺序 –>thisFunction()–>AfterFunction()–> function1 –> function2 // 前一个函数的运算结果 作为下一个函数的输入参数 // 理解运行时机 可以类比 Junit中 @Before 与 @After System.out.println(this.testFunctionCompose(8)); System.out.println(this.testFunctionAndThen(8));2、BiFunction接口System.out.println("——————BiFunction接口的理解———————\n");// BiFunction 接口 的 理解// @FunctionalInterface// public interface BiFunction<T, U, R> {// R apply(T t, U u);// 一个函数:接收二个参数 返回一个结果/ default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t, U u) -> after.apply(apply(t, u)); } }/// 利用反证法 可以证明 BiFunction 没有 compose方法 (提示: 参数 与 返回值)// 将2个参数应用于BiFunction 只会得到一个返回值 这个返回值会作为Function传入的参数// biFunction.andthen(function)System.out.println(this.testBiFunctionAndThen(10, 2));3、Predicate接口System.out.println("——————-Predicate接口的理解———————\n");// public interface Predicate<T> {// Represents a predicate (boolean-valued function) of one argument./ * Evaluates this predicate on the given argument. * * 接收一个判断 判断是否满足预期条件 返回true false * boolean test(T t); /System.out.println(“获取满足条件的集合:大于4”);System.out.println(this.testPredicate(in -> in > 4));System.out.println("——————————\n"); / * Returns a composed predicate that represents a short-circuiting logical * AND of this predicate and another. When evaluating the composed * predicate, if this predicate is {@code false}, then the {@code other} * predicate is not evaluated. * * 短路逻辑与计算 * default Predicate<T> and(Predicate<? super T> other) { * Objects.requireNonNull(other); * return (t) -> test(t) && other.test(t); }/System.out.println(“获取满足条件的集合:大于4且是偶数”);System.out.println(this.testPredicateAnd(in -> in > 4, in -> in % 2 == 0));System.out.println("——————————\n");/ * Returns a predicate that represents the logical negation of this * predicate. * * 取反 * default Predicate<T> negate() { * return (t) -> !test(t); * } /System.out.println(“获取满足条件的集合:大于4 取反”);System.out.println(this.testPredicateNegate(in -> in > 4));System.out.println("——————————\n");/ * Returns a composed predicate that represents a short-circuiting logical * OR of this predicate and another. When evaluating the composed * predicate, if this predicate is {@code true}, then the {@code other} * predicate is not evaluated. * * 短路逻辑或计算 * default Predicate<T> or(Predicate<? super T> other) { * Objects.requireNonNull(other); * return (t) -> test(t) || other.test(t); * } /System.out.println(“获取满足条件的集合:大于4或是偶数”);System.out.println(this.testPredicateOr(in -> in > 4, in -> in % 2 == 0));System.out.println("——————————\n");/ * Returns a predicate that tests if two arguments are equal according * to {@link Objects#equals(Object, Object)}. * * 根据Objects的equals方法 来判断两个对象 是否相同 * static <T> Predicate<T> isEqual(Object targetRef) { * return (null == targetRef) * ? Objects::isNull * : object -> targetRef.equals(object); * } /System.out.println(“使用Objects的Equals方法判断对象是否相同”);System.out.println(this.isEqual(“Kirito”).test(“Kirito”));System.out.println("——————————\n");/ * Returns a predicate that is the negation of the supplied predicate. * This is accomplished by returning result of the calling * {@code target.negate()}. * * 返回提供的predicate的否定 * @SuppressWarnings(“unchecked”) * static <T> Predicate<T> not(Predicate<? super T> target) { * Objects.requireNonNull(target); * return (Predicate<T>)target.negate(); * } * } /System.out.println(“Predicate.not()返回(Predicate<T>)target.negate(); “);System.out.println(testPredicate(this.notPredicate(integer -> integer > 4)));System.out.println(”——————————\n”);System.out.println(“双重否定表肯定”);System.out.println(testPredicateNegate(this.notPredicate(integer -> integer > 4)));System.out.println("——————————\n");4、Supplier接口System.out.println("——————-Supplier接口的理解———————\n");/ * Represents a supplier of results. * * public interface Supplier<T> { * T get(); * } /// 构造方法引用 构造函数接口实例// 利用Supplier接口 Student类必须要有无参的构造方法// Supplier<Student> studentSupplier = () -> new Student();Supplier<Student> studentSupplier = Student::new;Student student = studentSupplier.get();student.setId(1);student.setName(“Kirito”);student.setSex(“Male”);student.setAge(18);student.setSalary(999999999.0);student.setAddr(“ShenZhen”);System.out.println(student);System.out.println("——————————\n");5、BinaryOperator接口 System.out.println("—————BinaryOperator接口的理解——————-\n"); / * * public interface BinaryOperator<T> extends BiFunction<T,T,T> { * * 返回2个比较参数之间的较小值 * public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) { * Objects.requireNonNull(comparator); * return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; * } * * 返回2个比较参数之间的较大值 * public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) { * Objects.requireNonNull(comparator); * return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; * } * } */ System.out.println(“继承BiFunction的Apply方法 实现减法”); System.out.println(“10 - 2 = “+this.testBinaryOperator(10, 2)); System.out.println(”——————————\n”); System.out.println(“字符串较短的是:"+this.testMinBy(“Kirito”,“Asuna”,length)); System.out.println(“字符串较长的是:"+this.testMaxBy(“Kirito”,“Asuna”,length)); System.out.println(”——————————\n”); System.out.println(“字符串首字母ASCII码较小的是:"+this.testMinBy(“Kirito”,“Asuna”,asc)); System.out.println(“字符串首字母ASCII码较大的是:"+this.testMaxBy(“Kirito”,“Asuna”,asc)); }} ...

January 31, 2019 · 6 min · jiezi

深入理解lambda表达式与@FunctionalInterface函数式接口(一)

一、集合遍历与Lambda表达式 引入package com.java.design.java8;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.*;import java.util.function.Consumer;/** * @author 陈杨 */@RunWith(SpringRunner.class)@SpringBootTestpublic class ErgodicList { @Test public void testErgodicList() { // 直接构造集合对象 保证了集合size>0 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0); System.out.println("—————————传统for循环——————–\n"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("—————————增强for循环——————–\n"); for (Integer i : list) { System.out.println(i); } System.out.println("—————————迭代器————————-\n"); Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) { Integer integer = iterator.next(); System.out.println(integer); } System.out.println("—————————forEach————————\n"); list.forEach(new Consumer<Integer>() { @Override public void accept(Integer integer) { System.out.println(integer); } });二、 @FunctionalInterface函数式接口与Lambda表达式1、概念// Consumer @FunctionalInterface函数式接口// Conceptually, a functional interface has exactly one abstract method.// 从概念上看,一个函数式接口有且只有一个精确的抽象方法// 从java8开始 接口中不仅仅存在抽象方法 还能存在有具体实现的方法(默认方法)2、 函数式接口的区分// Since {@linkplain java.lang.reflect.Method#isDefault()// default methods} have an implementation, they are not abstract. If// an interface declares an abstract method overriding one of the// public methods of {@code java.lang.Object}, that also does// <em>not</em> count toward the interface’s abstract method count// since any implementation of the interface will have an// implementation from {@code java.lang.Object} or elsewhere.// 因为java.lang.reflect.Method#isDefault() default methods 有一个实现 所以不是抽象的// 如果一个接口声明一个抽象方法,其实现了java.lang.Object类中public方法:不计入抽象方法的个数3、函数式接口的实例化方式// Note that instances of functional interfaces can be created with// lambda expressions, method references, or constructor references.// 函数式接口的实例化: lambda表达式 方法引用 构造方法引用4、函数式接口中的默认方法// default void forEach(Consumer<? super T> action) {// Objects.requireNonNull(action);// for (T t : this) {// action.accept(t);// }// }// action 针对每个元素 执行的动作行为// default 修饰接口 已实现的默认方法5、总结与思考// 1、如果一个接口中有且只有一个抽象方法 则其为一个函数式接口// 2、如果一个接口上声明了@FunctionalInterface注解 则编译器会按照函数式接口的定义来要求该接口// If a type is annotated with this annotation type, compilers are// required to generate an error message unless:// (1)The type is an interface type and not an annotation type, enum, or class.// (2)The annotated type satisfies the requirements of a functional interface.// However, the compiler will treat any interface meeting the// definition of a functional interface as a functional interface// regardless of whether or not a {@code FunctionalInterface}// annotation is present on the interface declaration.// 3、如果接口上只有一个抽象方法,但我们没有对其加上@FunctionalInterface 编译器仍然将其看作函数式接口// 加上注解后 一目了然 如果没有满足强制性要求 则会抛出错误信息// 4、只有一个抽象方法的接口 有必要加上 @FunctionalInterface 如 Runnable接口// 5、所有的函数式接口 都可以使用lambda表达式 实现(表达易懂 简单)三、函数式接口实例化 之 Lambda表达式System.out.println("——————–lambda创建函数式接口实例—————\n");list.forEach(i -> { // 若能推断出i的类型 不需要声明 // 如不能推断出(Integer i)->{} System.out.println(i);});四、在排序过程中 Lambda表达式的 演变System.out.println("————————–lambda排序———————–\n");// Collections.sort(list, new Comparator<Integer>() {// @Override// public int compare(Integer o1, Integer o2) {// return o2.compareTo(o1);// }// });// Collections.sort(list,(String o1, String o2)->{return o2.compareTo(o1);});// Collections.sort(list, (o1, o2) -> { return o2.compareTo(o1); });// statement { return o2.compareTo(o1); }// expression o2.compareTo(o1)// Collections.sort(list,(String::compareTo));// Collections.sort(list,Collections.reverseOrder());Collections.sort(list, (o1, o2) -> o2.compareTo(o1));System.out.println(list);五、函数式接口实例化 之 方法引用System.out.println("——————–方法引用创建函数式接口实例————–\n");list.forEach(System.out::println); }}六、深入理解Lambda表达式// lambda表达式:// 1、从函数式编程角度来看:// lambda表达式为Java添加了函数式编程的新特性 函数升格成为一等公民// 在函数作为一等公民的语言 如Python中 lambda表达式为函数类型// 但在java中 lambda表达式是对象类型 依赖于函数式接口Functional Interface// 2、lambda表达式书写// lambda表达式形式 () -> {} 必需根据上下文确定其匿名函数类型 函数方法 -> 函数实现// () 省略 参数只有一个且类型可根据上下文推导// {} 省略 方法体主体只有一条语句,返回值类型与主体表达式(匿名函数)一致// 3、进一步理解lambda表达式// lambda表达式传递行为action 不仅仅是值的传递 (类比Node.js的事件驱动 与 回调函数callback)// lambda表达式替换前: 事先定义对象及所持有的方法 根据 “对象.方法” 进行方法的调用 预先定义好的action// lambda表达式替换后: {} 方法调用 R apply(T t); 事先不知道action 仅在调用时才知道 action// 提升抽象层次 API重用性 使用灵活 ...

January 30, 2019 · 2 min · jiezi