说句实话,干开发这么多年,针对于Java方面的技术,自己了解的也不是特别深,前段时间工作不忙,自己就整理了很多技术相关的文档,现在就发出来吧。
用了那么多时间的JAVA1.6没有一个具体的针对于1.8的系统的总结,咱们就先说说这个JAVA1.8吧。
********************************************************************************************************************************
JAVA1.8功能介绍
********************************************************************************************************************************
1.java编程语言
1.1、Lambda表达式:一个新的语言特性,他们使您能够将函数视为方法参数,或将代码视为数据
1.2、方法引用:方法引用为已经有名称的方法提供易于阅读的Lambda表达式
1.3、默认方法:使用default关键字为借口定义默认方法(有实现的方法)
1.4、重复注解:提供了将同一注解多次应用同一声明或类型使用的能力
1.5、类型注解:提供了在使用类型的任何地方应用注解的能力,而不仅仅是在声明上
1.6、java8增强了类型推断
1.7、方法参数反射
1.8、java.util.function:一个新的包,它包含为lambda表达式和方法引用提供目标类型的通用功能接口
2.集合(Collections)
2.1、java.util.stream包中新增了Stream API,用来支持对元素流的函数式操作
2.2、改进了有键冲突问题的HashMap
3.精简运行时(Compact Profiles)
4.安全性(Security)
5.JavaFX
6.Tools(包含一些调用Nashorn引擎、启动JavaFX应用程序等等)
7.国际化(Internationalization)
7.1、Unicode增强,包括对Unicode6.2.0的支持
7.2、提供了新的Calendar和Locale API
8.部署(Deployment)
9.日期-时间 包(Date-Time Package):提供了更全面的时间和日期操作
10.脚本(Scripting):Java 8提供了一个新的 Nashorn javascript 引擎(取代了Nashorn javascript引擎),它允许我们在JVM上运行特定的 javascript 应用
11.改进IO和NIO
12.改进java.lang 和 java.util
12.1、支持数组并行排序
12.2、支持Base64 的编码和解码
12.3、支持无符号运算
12.4、Optional类:最大化减少空指针异常
13.JDBC
13.1、JDBC-ODBC桥已被移除
13.2、JDBC 4.2引入了新的特性
14.Java DB(一个Java数据库)
15.网络(Networking):新增了java.net.URLPermission
16.并发(Concurrency):
16.1、CompletableFuture增强了之前的Future
16.2、java.util.concurrent.ConcurrentHashMap支持基于新添加的stream功能和lambda表达式的聚合操作
16.3、java.util.concurrent.atomic提供了一组变量类,对于单个变量支持无锁、线程安全操作的工具类
16.4、java.util.concurrent.ForkJoinPool用于补充ExecutorService
16.5、java.util.concurrent.locks.StampedLock提供了基于功能的锁,有三种模式用于控制读/写访问
17.JVM:移除了PermGen,取而代之的是Metaspace
Java8特别强大的是Lambda表达式和Stream,通过这两点新增和增强了很多包
新增包:java.lang.invoke、java.util.function、java.util.stream
***************************************************纯手打分割线*******************************************************
一、Lambda表达式 可以把Lambda表达式理解为简洁的表示可传递的匿名函数的一种方式,Lambda表达式基于数学中的λ演算得名:
它没有名称,但有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。 1.匿名--匿名函数(即没有函数名的函数),不像普通的方法有一个明确的名称
2.函数--Lambda函数不像方法那样属于某个特定的类,但一样有参数列表、函数主体和返回类型
3.传递--Lambda表达式可以作为参数传递给方法或者存储在变量中 4.简介--无需像匿名类那样写很多模板代码
Lambda表达式使您能够封装单个行为单元并将其传递给其他代码。如果希望对集合的每个元素、流程完成时 或流程遇到错误时执行某个操作。可以使用lambda.
1.为什么要使用Lambda表达式
Lambda是一个匿名函数,我们可以把lambda表达式 理解为是一段可以传递的代码(将代码像数据一样进行传递
--行为参数化)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
匿名类的一个问题是,如果您的匿名类的实现非常简单,例如一个接口只包含一个方法,那么匿名类的语法可能看
起来很笨拙和不清楚。在这些情况下,您通常试图将功能作为参数传递给另一个方法,例如当有人单击按钮时应该采取
什么操作。Lambda表达式允许您这么做,将功能视为方法参数,或将代码视为数据。
2.Lambda表达式语法
(parameters) -> expression 或(parameters) ->{ statements; }
Lambda 表达式在 Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。它将
Lambda 分为两个部分:
左侧:指定了Lambda表达式需要的所有参数
右侧:指定了Lambda体,即Lambda表达式要执行的功能
3.Lambda表达式实例
官方提供的示例,假设你要开发一个社交软件,那个缺打的PM成天改需求,今天要查询出成年用户的信息,
明天又要查询成年女性的用户信息,后天又要按各种奇怪的搜索条件查询。这时的程序员:
从简单的用户遍历比较方法改为通用的搜索方法到后来都用上了工厂模式,等到第7天的时候,你不耐烦了,
玛德,每个条件就一句话,我写了7个类,我可不想做CtrlCV工程师,这时候Lambda表达式是你的不二之选。
行为参数化就是可以帮助你处理频繁变更的需求的一种软件开发模式。
官方提供的Demo,一步步告诉你使用java8的好处(从值参数化到行为参数化)
新建一个Person类具体代码见本项目
public class Person {
public enum Sex {
MALE, FEMALE
}
String name;
LocalDate birthday;
Sex gender;
String emailAddress;
public Person(){
}
Person(String nameArg, LocalDate birthdayArg,
Sex genderArg, String emailArg) {
name = nameArg;
birthday = birthdayArg;
gender = genderArg;
emailAddress = emailArg;
}
public int getAge() {
return birthday
.until(IsoChronology.INSTANCE.dateNow())
.getYears();
}
public void printPerson() {
System.out.println(name + ", " + this.getAge());
}
public Sex getGender() {
return gender;
}
public String getName() {
return name;
}
public String getEmailAddress() {
return emailAddress;
}
public LocalDate getBirthday() {
return birthday;
}
public static int compareByAge(Person a, Person b) {
return a.birthday.compareTo(b.birthday);
}
@Override
public String toString() {
return "Person [name=" + name + ", birthday=" + birthday + ", gender=" + gender + ", emailAddress="
+ emailAddress + "]";
}
public static List<Person> createRoster() {
List<Person> roster = new ArrayList<>();
roster.add(new Person(
"Fred",
IsoChronology.INSTANCE.date(1980, 6, 20),
Person.Sex.MALE,
"fred@example.com"));
roster.add(new Person(
"Jane",
IsoChronology.INSTANCE.date(1990, 7, 15),
Person.Sex.FEMALE, "jane@example.com"));
roster.add(new Person(
"George",
IsoChronology.INSTANCE.date(1983, 8, 13),
Person.Sex.MALE, "george@example.com"));
roster.add(new Person(
"Bob",
IsoChronology.INSTANCE.date(2000, 9, 12),
Person.Sex.MALE, "bob@example.com"));
return roster;
}
}
public class RosterTest {
interface CheckPerson {
boolean test(Person p);
}
/**
* 1. eg:输出年龄大于20岁的成员
* 匹配符合某一特征的成员的方法
* 如果老板要年龄在某一区间的成员呢?接着换方法
*/
public static void printPersonsOlderThan(List<Person> roster, int age) {
for (Person p : roster) {
if (p.getAge() >= age) {
p.printPerson();
}
}
}
/**
* 2. eg:输出年龄在14到30岁之间的成员
* 更全面的匹配方法
* 如果老板只要男性成员呢?
*/
public static void printPersonsWithinAgeRange(
List<Person> roster, int low, int high) {
for (Person p : roster) {
if (low <= p.getAge() && p.getAge() < high) {
p.printPerson();
}
}
}
// Approach 3: Specify Search Criteria Code in a Local Class
// Approach 4: Specify Search Criteria Code in an Anonymous Class
// Approach 5: Specify Search Criteria Code with a Lambda Expression
/**
* 3. eg:老板又提出了各种复杂的需求,不要处女座的、只要邮箱是163的,怎么搞?
* 方法1:在本地类中指定搜索条件代码,通过接口方式,不同的需求对应不同的实现类,
* 每次都要新建实现类,写大量的代码
* 方法2:在匿名类中指定搜索条件代码,不需要写各种实现,但是还要写个interface CheckPerson,
* 而且匿名类写起来也挺麻烦
* 方法3:Lambda表达式是懒人的不二之选,CheckPerson是一个只包含一个抽象方法的接口,
* 比较简单,Lambda可以省略其实现
*
*本方法需要根据业务需求实现CheckPerson接口,即每个业务都需要实现不同的实现类
*/
public static void printPersons(
List<Person> roster, CheckPerson tester) {
for (Person p : roster) {
if (tester.test(p)) {
p.printPerson();
}
}
}
/**
* 4. eg: 搞这么久,还得写一个接口,而且是只有一个抽象方法,还是不爽?
* 你也可以使用标准的函数接口来代替接口CheckPerson,从而进一步减少所需的代码量
* java.util.function包中定义了标准的函数接口
* 我们可以使用JDK8提供的 Predicate<T>接口来代替CheckPerson。
* 该接口包含方法boolean test(T t)
*
* 该方法可以替换上面的CheckPerson接口,因为Predicate接口为java8新添加的函数式接口,
* 仅提供了一个方法test,返回值为boolean,供所有使用者使用,不用重新创建接口
*
*/
public static void printPersonsWithPredicate(
List<Person> roster, Predicate<Person> tester) {
for (Person p : roster) {
if (tester.test(p)) {
p.printPerson();
}
}
}
/**
* 5. Lambda表达式可不只是能够简化匿名类
* 简化 p.printPerson(),
* 使用Consumer<T>接口的void accept(T t)方法,相当于入参的操作
*
* Predicate和Consumer接口的test()和accept()方法都接收一个泛型参数。
* 不同的是test()方法进行某些逻辑判断并返回一个boolean值,
* 而accept()接受并改变某个对象的内部值。
*
* Consumer为java8新添加的另外一种函数式接口,仅提供accept()方法,无返回值
* Consumer接口表示接受单个输入参数且无返回的操作
*
* 在第4步基础上添加参数Consumer<T>接口类型,用于针对对象进行消费,或者说针对对象进行修改操作,
* 无返回,因为该方法无返回所以一般用于对对象进行修改或包装
*/
public static void processPersons(
List<Person> roster,
Predicate<Person> tester,
Consumer<Person> block) {
for (Person p : roster) {
if (tester.test(p)) {
block.accept(p);
}
}
}
/**
* 6.
* Function<T,R>接口,相当于输入类型,mapper定义参数,block负责方对给定的参数进行执行
*
* Predicate<T>接口 boolean test(T t)表示对参数T或其中的属性进行判断返回一个boolean类型的值
* Consumer<T>接口 void accept(T t)表示接收单个输入参数无返回值的操作结果一般用于接收并改变某个对象的内部值
* Function<T, R>接口 R apply(T t)表示接收一个参数并产生结果的函数。其中T为参数,R为返回值类型
*
*
* 在第五步的基础上添加Function<T,R>接口,用于对参数进行处理从而返回指定格式的值
*/
public static void processPersonsWithFunction(
List<Person> roster,
Predicate<Person> tester,
Function<Person, String> mapper,
Consumer<String> block) {
for (Person p : roster) {
if (tester.test(p)) {
String data = mapper.apply(p);
block.accept(data);
}
}
}
/**
* 7. eg: 使用泛型
*
* 将第6步中的实际对象抽象为可迭代的任意对象
*/
public static <X, Y> void processElements(
Iterable<X> source,
Predicate<X> tester,
Function<X, Y> mapper,
Consumer<Y> block) {
for (X p : source) {
if (tester.test(p)) {
Y data = mapper.apply(p);
block.accept(data);
}
}
}
public static void main(String[] args) {
List<Person> roster = Person.createRoster();
/**
* 1. 输出年龄大于20岁的成员
*/
System.out.println("1.年龄大于20岁的成员:");
printPersonsOlderThan(roster, 20);
System.out.println();
/**
* 2. 输出年龄在14到30岁之间的成员
*/
System.out.println("2.年龄在14到30岁之间的成员:");
printPersonsWithinAgeRange(roster, 14, 30);
System.out.println();
/**
* 3. 输出年龄在18到25岁的男性成员
* (在本地类中指定搜索条件)
* 您可以使用一个匿名类而不是一个本地类,并且不必为每个搜索声明一个新类
*/
System.out.println("3.年龄在18到25岁的男性成员:");
class CheckPersonEligibleForSelectiveService implements CheckPerson {
public boolean test(Person p) {
return p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25;
}
}
// 这个其实就是通过行为参数化传递代码
// 直白点说这个就是将实现CheckPerson接口并完成指定业务逻辑的行为当做参数传递
printPersons(
roster, new CheckPersonEligibleForSelectiveService());
System.out.println();
/**
* 3.输出年龄在18到25岁的男性成员
*
* (在匿名类中指定搜索条件代码)
* 相对于使用本地类,匿名类更为简单,代码更少
* */
System.out.println("3.年龄在18到25岁的男性成员:(匿名类)");
printPersons(
roster,
new CheckPerson() {
public boolean test(Person p) {
return p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25;
}
}
);
System.out.println();
/**
* 3.输出年龄在18到25岁的男性成员
*
* (使用lambda表达式)
*
* 这里说一下lambda表达式,其实lambda表达式就是忽略它本身的接口,只关注接口内部的行为,
* 所以在lambda表达式中你根本就看不到他实现的是哪个接口,只能通过调用的方法来辨别lambda表达式
* 所代替的参数的是属于那种类别。
* 同时,lambda表达式只关注行为本身,即参数,方法体和返回值.
*
*
* */
System.out.println("3.年龄在18到25岁的男性成员:(Lambda表达式)");
// printPersons(
// roster,
// (Person p) -> p.getGender() == Person.Sex.MALE
// && p.getAge() >= 18
// && p.getAge() <= 25
// );
printPersons(roster, p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25);
System.out.println();
/**
* 4.使用Lambda的标准功能接口
*
* 使用Predicate接口 boolean test()
* 该方法可以替换上面的CheckPerson接口,因为Predicate接口为java8新添加的函数式接口
*
* 是不是发现该方法和上面第三步的方法只是换了个方法名,是的,所以说lambda表达式更关注的是
* 方法的执行行为,不体现方法名称,主要记住这点,之后可以判断什么时候应该使用lambda表达式。
* */
System.out.println("4.使用Predicate接口:");
printPersonsWithPredicate(
roster,
p -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
);
System.out.println();
/**
* 5.使用Predicate<T>接口 boolean test(T t)
* 使用Consumer<T>接口的void accept(T t)
*
* 在4的基础上添加了Consumer接口,用于对对象进行包装修改或者打印信息等操作
* 此处为输出Person对象
* 因为Consumer为无返回的接口所以注定该接口只是一个消费型接口
* */
System.out.println("5.使用Predicate和Consumer参数:");
processPersons(
roster,
p -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25,
p -> p.printPerson()
);
System.out.println();
/**
* 6.通过Function<T,R> 指定输出类型
*
* 使用Predicate<T>接口 boolean test(T t)
* 使用Consumer<T>接口void accept(T t)
* 使用Function<T,R>接口R apply(T t)
*
* 添加Function<T,R>接口用于指定输出类型或者说是用于类型转换
*
* */
System.out.println("6.使用Function,Predicate,Consumer参数:");
processPersonsWithFunction(
roster,
p -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25, //对参数进行判断
//对数据类型进行转换,此处为将Person类型转化为String类型
p -> p.getEmailAddress(), //或者说获取到对象指定格式的信息
email -> System.out.println(email)//对结果进行输出
);
System.out.println();
/**
* 7.使用泛型
*
* 在第6步的基础上使用泛型
*
* */
System.out.println("7.使用Function,Predicate,Consumer参数(泛型):");
/**
* This method invocation performs the following actions:
*
* Obtains a source of objects from the collection source. In this example, it obtains a source of Person objects from the collection roster. Notice that the collection roster, which is a collection of type List, is also an object of type Iterable.
* Filters objects that match the Predicate object tester. In this example, the Predicate object is a lambda expression that specifies which members would be eligible for Selective Service.
* Maps each filtered object to a value as specified by the Function object mapper. In this example, the Function object is a lambda expression that returns the e-mail address of a member.
* Performs an action on each mapped object as specified by the Consumer object block. In this example, the Consumer object is a lambda expression that prints a string, which is the e-mail address returned by the Function object.
*/
processElements(
roster,
p -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25,
p -> p.getEmailAddress(),
email -> System.out.println(email)
);
System.out.println();
/**
* 8.使用接受lambda表达式的批量数据操作
*
* 使用java8新添加的api采用流处理对集合进行操作,
* 对一下操作进行解析:
* 1.将list对象转化为strean对象,即通常我们说的流化
* steam():把一个源数据,可以是集合,数组,I/O channel, 产生器generator 等,转化成流
* 2.调用filter方法传入参数为Predicate<T>即一般我们用于进行条件判断的语句进行条件过滤
* filter 方法用于通过设置的条件过滤出元素
* 3.调用map方法传入参数为Function<T,R>即用于进行格式转化或获取对象内部指定属性,
* map()用于映射每个元素到对应的结果。
* 4.forEach方法传入参数为Consumer<T>对当前流化处理的数据进行遍历
* forEach()迭代流中的每个数据
* */
System.out.println("8.使用接受lambda表达式的批量数据操作:");
roster.stream()
.filter(
p -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
)
.map(p -> p.getEmailAddress())
.forEach(email -> System.out.println(email));
System.out.println();
/**
* 9. 按年龄排序。Java 8 之前需要实现 Comparator 接口
* 接口比较器是一个功能接口。因此,可以使用lambda表达式来代替定义并创建一个实现了Comparator的类的新实例:
*/
System.out.println("9.按照年龄排序:");
Person[] rosterAsArray = roster.toArray(new Person[roster.size()]);
/**
* 这种比较两个Person实例的出生日期的方法已经作为Person.
* comparebyage存在。你可以在lambda表达式中调用这个方法
*/
Arrays.sort(rosterAsArray,
(a, b) -> Person.compareByAge(a, b)
);
for (Person person : roster) {
person.printPerson();
}
/**
* 1.stream()将roster即人员集合转化为数据流
* 2.sorted()对流化后的集合数据进行排序,传入参数Comparator
* 调用Comparator中的静态方法comparing(Function<T,R>)
* 其中(Person::getBirthday)为方法引用也就是Lambda表达式的另外一种简写
* 相当于 () -> Person对象.getBirthday();
* 该语句整体含义就是根据Person对象中的Birthday属性进行排序
* 3.collect()传入参数Collector,一般结束流化时用,用于转化为原有的集合类型
* */
List<Person> personSortAge=roster
.stream()
.sorted(Comparator.comparing(Person::getBirthday))
.collect(Collectors.toList());
personSortAge.forEach(p -> System.out.println(p));
/**
* 流化处理时常用的方法:
* 1.steam():把一个源数据,可以是集合,数组,I/O channel, 产生器generator 等,转化成流。
* 2.forEach():迭代流中的每个数据。
* 3.map():用于映射每个元素到对应的结果
* 4.filter():filter 方法用于通过设置的条件过滤出元素
* 5.sorted(): 用于对流进行排序。
* 6.Collectors(): 类实现了很多归约操作,例如将流转换成集合和聚合元素
* 即collect()
*
* */
/**
* 这种比较两个Person实例的出生日期的方法已经作为Person. comparebyage存在。
* 你可以在lambda表达式中调用这个方法
*/
Arrays.sort(rosterAsArray,
(a, b) -> Person.compareByAge(a, b)
);
/**
* ===================================================================
* 方法引用:
* 这个lambda表达式调用现有的方法,所以您可以使用方法引用而不是lambda表达式
* Person::compareByAge 等同于 (a, b) -> Person.compareByAge(a, b)
*/
Arrays.sort(rosterAsArray, Person::compareByAge);
System.out.println();
/**
* 引用特定对象的实例方法
*
* */
class ComparisonProvider {
public int compareByName(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
public int compareByAge(Person a, Person b) {
return a.getBirthday().compareTo(b.getBirthday());
}
}
ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
for (Person person : rosterAsArray) {
person.printPerson();
}
System.out.println();
/**
* 引用特定类型的任意对象的实例方法
* String::compareToIgnoreCase 格式化 (String a, String b) ,并去调用 a.compareToIgnoreCase(b)
*/
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
for (String s : stringArray) {
System.out.println(s);
}
System.out.println();
// 通过 stream 将计算集合的和
Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 };
List<Integer> listOfIntegers =
new ArrayList<>(Arrays.asList(intArray));
System.out.println("Sum of integers: " +
listOfIntegers
.stream()
.reduce(Integer::sum).get());
}
}
public static void main(String[] args) {
//1.无参,无返回,Lambda体只需要一条语句
Runnable runnable = () -> System.out.println("Hello Lambda");
//2.Lambda需要一个参数
Consumer<String> consumer = (p) -> System.out.println(p);
//Lambda只需要一个参数时,参数的小括号可以省略
Consumer<String> consumer1 = p -> System.out.println(p);
//3.Lambda需要两个参数,并且有返回值
BinaryOperator<Long> binaryOperator = (Long x,Long y) -> {
System.out.println("实现函数接口的方法");
return x+y;
};
//参数的数据类型可以省略,Java8增强了类型推断,且当Lambda体只有一条语句时,return与大括号可以省略
BinaryOperator<Long> binaryOperator2 = (x,y) -> x+y;
/**
* 类型推断
*
* 上述Lambda表达式中的参数类型都是有编译器推断出的。Lambda表达式中无需指定类型,程序依然可以编译,
* 这是因为javac根据程序的上下文,在后台推断出了参数的类型。Lambda表达式的类型依赖于上下文环境,是
* 由编译器推断出来的,这就是所谓的“类型推断”。Java7中引入的菱形运算符(<>),就是利用泛型从上下文
* 推断类型
*
* */
}
源码下载地址:https://download.csdn.net/download/qq_20410965/12434193