特性1
/**
* 接口的默认方法:
* Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法
*
* @author ljz07
*
*/
public class Feature1 {
public static void main(String[] args) {
Formlua formlua=new Formlua() {
@Override
public double calculate(int a) {
//注意这里一定是要已经实现了的接口方法
return sqrt(a*100);
}
};
formlua.calculate(100);
formlua.sqrt(16);
//该代码非常容易理解,6行代码实现了计算 sqrt(a * 100)
System.out.println(formlua.calculate(16));
System.out.println(formlua.sqrt(16));
}
}
interface Formlua {
/**
* Formula接口在拥有calculate方法之外同时还定义了sqrt方法,
* 实现了Formula接口的子类只需要实现一个calculate方法,
* 默认方法sqrt将在子类上可以直接使用
* @param a
* @return
*/
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
特性2
/**
* Lambda 表达式用在
* 集合的排序
*
* @author ljz07
*
*/
public class Feature2 {
private static List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
public static void main(String[] args) {
sort();
sortNew1();
sortNew2();
sortNew3();
}
// old
public static void sort() {
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
System.out.println(names);
}
//在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式
public static void sortNew1() {
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
System.out.println(names);
}
//代码变得更段且更具有可读性,但是实际上还可以写得更短:
public static void sortNew2() {
Collections.sort(names, (String a, String b) -> b.compareTo(a));
System.out.println(names);
}
//对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字,但是你还可以写得更短点:
public static void sortNew3() {
Collections.sort(names, (a, b) -> b.compareTo(a));
System.out.println(names);
}
}
特新3
/**
* 函数式接口
* “函数式接口”是指仅仅只包含一个抽象方法的接口,每一个lambda表达式都会被匹配到这个抽象方法。
* 因为默认方法不算抽象方法,也可以给你的函数式接口添加默认的方法。
*
* 只包含一个抽象方法的接口类型可以使用lambda表达式。如果你的接口确定是这样的需求你可以添加@FunctionalInterface
* 编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的
* @author ljz07
*
*/
public class Feature3 {
public static void main(String[] args) {
Converter<String, Integer> converter =(from)->Integer.valueOf(from);
Integer converted=converter.convert("1123");
System.out.println(converted);
//六 一 二 八 立 日 早 十 音 古 克 章 儿 兄 口 竞 辛 旦 亘 亠
//
}
}
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
//可以添加默认的方法,不是属于抽象方法
default int getInt(F form) {
return 0;
}
}
特性4
/**
* 四、方法与构造函数引用
* 允许你使用 :: 关键字来传递方法或者构造函数引用,引用一个静态方法,也可以引用一个对象的方法
*
* @author ljz07
*
*/
public class Feature4 {
public static void main(String[] args) {
//static的引用,通过静态方法引用来表示
Converter<String,Integer> converter=Integer::valueOf;
Integer converted=converter.convert("123");
System.out.println(converted);
//我们只需要使用 Person::new 来获取Person类构造函数的引用
//返回构造函数的引用
PersonFactory<Person> personFactory=Person::new;
//Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。
Person p=personFactory.create("Li", "Janle");
System.out.println(p);
}
}
/**
* person实体
*/
class Person{
String firstName;
String lastName;
public Person() {
}
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Person(String firstName) {
this.firstName = firstName;
}
@Override
public String toString() {
return this.firstName+" "+this.lastName;
}
}
/**
* 构建person对象的工厂接口
* @param <P>
*/
interface PersonFactory<P extends Person>{
//这里自己会去找相应方法签名的构造函数,但是接口的方法只能是一个
P create (String firstName,String lastName);
//P create (String firstName);
}
特性5
/**
* Lambda 作用域
* 访问局部变量
* 在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。
* 你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
*
* @author ljz07
*/
public class Feature5 {
public static void main(String[] args) {
final int num = 1;
// 可以在外层直接定义变量
Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num);
String str = stringConverter.convert(2);
System.out.println(str);
// 这里和匿名对象不同的是这里可以不是final的变量
int num1 = 1;
Converter<Integer, String> num1Converter = (from) -> String.valueOf(num1 + from);
String str1 = num1Converter.convert(2);
System.out.println(str1);
// num1=4;//但是num1不能被后边的代码修改,具有隐含的num1的final的语法的功能,lanmbda不能修改
}
}
特性6
/**
* 访问对象字段与静态变量
* lambda内部对于实例的字段以及静态变量是即可读又可写。该行为和匿名对象是一致的
*
* @author ljz07
*
*/
public class Feature6 {
public static void main(String[] args) {
new Lambda().testScorpe();
}
}
class Lambda{
static int outerStaticNum ;
int outerNum;
void testScorpe(){
Converter<Integer,String> converter1=(from)->{
//可以使用
outerNum=23;
return String.valueOf(from);
};
System.out.println(converter1.convert(24));
Converter<Integer,String> converter2=(from)->{
//可以使用
outerStaticNum =25;
return String.valueOf(from-outerStaticNum);
};
System.out.println(converter2.convert(45));
}
}
特性7这个很牛的
/**
* 访问接口的默认方法 1.Lambda表达式中是无法访问到默认方法
*
* @author ljz07
*
*/
public class Feature7 {
public static void main(String[] args) {
// Formlua formlua=(a)->sqrt( a * 100);
optional();
System.out.println("---------------------stream--------------------");
stream();
//并行排序和串行排序的测试
//streams();
}
// Predicate
// 接口只有一个参数,返回boolean类型。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非):
private static void predicate() {
Predicate<String> predicate = (s) -> s.length() > 0;
predicate.test("foo");// ture
predicate.negate().test("foo");// false
Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();
}
// Function 接口有一个参数并且返回一个结果,并附带了一些可以和其他函数组合的默认方法(compose, andThen)
private static void function() {
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
backToString.apply("122");// 122
System.out.println(backToString.apply("122"));
}
// Supplier 接口返回一个任意范型的值,和Function接口不同的是该接口没有任何参数
private static void supplier() {
Supplier<Person> personSupplier = Person::new;
personSupplier.get(); // new Person
System.out.println(personSupplier.get());
}
// Consumer 接口表示执行在单个参数上的操作。这里感觉就像是回调函数一样,当你不谢accept时候不会打印
private static void consumer() {
Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker"));
}
// Comparator 是老Java中的经典接口, Java 8在此之上添加了多种默认方法:
private static void comparator() {
Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);
Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");
comparator.compare(p1, p2); // >0
comparator.reversed().compare(p1, p2); // <0
}
/**
* Optional 不是函数是接口,这是个用来防止NullPointerException异常的辅助类型,这是下一届中将要用到的重要概念,
* Optional 被定义为一个简单的容器,其值可能是null或者不是null。在Java
* 8之前一般某个函数应该返回非空对象但是偶尔却可能返回了null, 而在Java 8中,不推荐你返回null而是返回Optional。
*/
private static void optional() {
Optional<String> optional = Optional.of("bam");
optional.isPresent(); // true
optional.get(); // "bam"
optional.orElse("fallback"); // "bam"
optional.ifPresent((s) -> System.out.println(s.charAt(0)));
}
// Stream 表示能应用在一组元素上一次执行的操作序列。Stream的操作可以串行执行或者并行执行。
private static void stream() {
// 首先创建实例代码的用到的数据List:
List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");
// Java 8扩展了集合类,可以通过 Collection.stream() 或者 Collection.parallelStream()
// 来创建一个Stream
stringCollection.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);
// 排序是一个中间操作,返回的是排序好后的Stream。如果你不指定一个自定义的Comparator则会使用默认排序,
// 注意排序后只会影响stream,不会影响原有的数据源,排列后的stringCollection不会被修改
stringCollection.stream().sorted((f, d) -> d.compareTo(f)).filter((s) -> s.startsWith("b"))
.forEach(System.out::println);
// 中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象,也可以通过map来将对象转换成其他类型,map返回的Stream类型是根据你map传递进去的函数的返回值决定的
stringCollection.stream().map(String::toUpperCase).sorted((f, d) -> d.compareTo(f))
.forEach(System.out::println);
// match匹配
boolean anyStartsWithA = stringCollection.stream().anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true
boolean allStartsWithA = stringCollection.stream().allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false
boolean noneStartsWithZ = stringCollection.stream().noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // true
// Count 计数是一个最终操作,返回Stream中元素的个数,返回值类型是long
long startWithB = stringCollection.stream().filter((s) -> s.endsWith("2")).count();
System.out.println(startWithB);
// Reduce 规约
// 这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规越后的结果是通过Optional接口表示的:
// 这里不是返回的stream,前边我们提到的都是返回stream,
Optional<String> reduced = stringCollection.stream().sorted().reduce((a, b) -> a + "#" + b);
reduced.ifPresent(System.out::println);
//Map类型不支持stream,不过Map提供了一些新的有用的方法来处理一些日常任务。
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
//putIfAbsent不会校验存在性检查,forEach接收一个Consumer接口来对map里的每一个键值对进行操作
map.putIfAbsent(i, "val" + i);
}
map.forEach((key,value)->System.out.print(value+" "));
map.computeIfPresent(3,(num,val)->val+num);
map.get(3); // val33
map.computeIfPresent(9, (num, val) -> null);
map.containsKey(9); // false
map.computeIfAbsent(23, num -> "val" + num);
map.containsKey(23); // true
//校验存在性检查,如果存在就不会替换
map.computeIfAbsent(3, num -> "bam");
map.get(3); // val33
map.remove(3, "val3");
map.get(3); // val33
map.remove(3, "val33");
map.get(3); // null
map.getOrDefault(42, "not found"); // not found
//对Map的元素做合并也变得很容易了:Merge做的事情是如果键名不存在则插入,否则则对原键对应的值做合并操作并重新插入到map中。
map.merge(9, "val9", (value, newValue) -> value.concat(newValue));
map.get(9); // val9
map.merge(9, "concat", (value, newValue) -> value.concat(newValue));
map.get(9); // val9concat
}
public static void streams() {
// 并行Streams
// 前面提到过Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
int max = 1000000;
// 创建一个没有重复元素的大表
List<String> values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
long tc0 = System.nanoTime();
//串行排序:
long count = values.stream().sorted().count();
System.out.println(count);
long tc1 = System.nanoTime();
long millis = TimeUnit.NANOSECONDS.toMillis(tc1 - tc0);
System.out.println(String.format("use stream sequential sort took: %d ms", millis));
//并行排序:
long tb0 = System.nanoTime();
long countB =values.parallelStream().sorted().count();
System.out.println(countB);
long tb1=System.nanoTime();
long millisb=TimeUnit.NANOSECONDS.toMillis(tb1-tb0);
System.out.println(String.format("use parallelStream sequential sort took: %d ms", millisb));
}
}
特性8
/**
* Annotation 注解
* 在Java 8中支持多重注解了,
*
* @author ljz07
*
*/
public class Feature10 {
public static void main(String[] args) {
Hint hint=Student.class.getAnnotation(Hint.class);
System.out.println(hint);
Hints hints1 = Student.class.getAnnotation(Hints.class);
System.out.println(hints1.value().length); // 2
Hint[] hints2 = Student.class.getAnnotationsByType(Hint.class);
System.out.println(hints2.length); //2
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Hints {
Hint[] value();
}
@Retention(RetentionPolicy.RUNTIME) //这里指明在运行时候保留
@Repeatable(Hints.class)//可以重复
@interface Hint {
String value();
}
//@Hints({@Hint("hint1"), @Hint("hint2")}) //使用包装类当容器来存多个注解
@Hint("hint1")
@Hint("hint2")
class Student{}