了解了一下java8的新特性,以下只列出了比较常用的一些新特性,还有许多用到的时候去查吧
以下用实例代码加注释的方式展示和说明这些新特性:
/**
* @FunctionalInterface注解:确保接口只包含一个抽象方法,若标注了该注解且抽象方法不止一个,则会报错,若不加该注解,则可以有多个抽象方法
*/
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
/**
* 此处看起来from是不是没有定义,却不报错?这是为什么呢?
* 原来是因为上面的接口只有一个抽象方法。所以lambda表达式会自动的去匹配参数类型,从而自动编译该参数,像下面的main方法,Converter<String, Integer>此时已经知道F对应的是String类型,T对应的是Integer类型,而且上面的接口中唯一的抽象方法中的参数是F类型,所以自动的将下面的form认为是F类型,且会自动的正确编译该参数
* java8新特性的lambda表达式是个好东西,我也还在摸索当中,有什么不对的地方希望大家能指出来,一起学习,一起进步
* @param args
*/
public static void main(String[] args) {
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);
//上面的代码还可以通过静态方法来引用,输出结果是一样的
//Java 8 允许你使用 :: 关键字来传递方法或者构造函数引用
Converter<String, Integer> converter2 = Integer::valueOf;
Integer converted2 = converter.convert("123");
System.out.println(converted2);
//startWith判断一个字符串是否以某某开头,若是,返回true,否则,返回false
String aString="ssssssssddd";
Boolean aBoolean=aString.startsWith("a");
System.out.println(aBoolean);
//Lambda表达式中是无法访问到接口的默认方法的,java8允许接口中含有一个默认方法,实现该接口的类可以直接调用该默认方法
//Predicate 接口只有一个参数,返回boolean类型。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非):
Predicate<String> predicate = (s) -> s.length() > 0;
predicate.test("foo"); // true
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):
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
String a=backToString.apply("123");
System.out.println(a);
//Supplier 接口返回一个任意范型的值,和Function接口不同的是该接口没有任何参数
Supplier<String> personSupplier = String::new;
personSupplier.get(); // new String
//Comparator 是老Java中的经典接口, Java 8在此之上添加了多种默认方法:
Comparator<String> comparator = (p1, p2) -> p1.compareTo(p2);
String p1 = new String("John");
String p2 = new String("Alice");
comparator.compare(p1, p2); // > 0
comparator.reversed().compare(p1, p2); // < 0
//java.util.Stream 表示能应用在一组元素上一次执行的操作序列。Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。Stream的操作可以串行执行或者并行执行。
//首先看看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");
//Filter 过滤
//过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作。
stringCollection
.stream()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
//Sort 排序
//排序是一个中间操作,返回的是排序好后的Stream。如果你不指定一个自定义的Comparator则会使用默认排序。
stringCollection
.stream()
.sorted()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
//需要注意的是,排序只创建了一个排列好后的Stream,而不会影响原有的数据源,排序之后原数据stringCollection是不会被修改的:
System.out.println(stringCollection);// ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1
//Map 映射
//中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象,下面的示例展示了将字符串转换为大写字符串。你也可以通过map来讲对象转换成其他类型,map返回的Stream类型是根据你map传递进去的函数的返回值决定的。
stringCollection
.stream()
.map(String::toUpperCase)
.sorted((b1, b2) -> b2.compareTo(b1))
.forEach(System.out::println);
// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
//Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作,并返回一个boolean类型的值。
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 startsWithB =
stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();
System.out.println(startsWithB); // 3
//Reduce 规约
//这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规越后的结果是通过Optional接口表示的:
Optional<String> reduced =
stringCollection
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"
//并行Streams
//串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
//并行版的快了50%之多,唯一需要做的改动就是将stream()改为parallelStream()。
//Map
//Map类型不支持stream,不过Map提供了一些新的有用的方法来处理一些日常任务。
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
map.putIfAbsent(i, "val" + i);
}
//map.forEach((id, val) -> System.out.println(val));
//以上代码很容易理解, putIfAbsent 不需要我们做额外的存在性检查,而forEach则接收一个Consumer接口来对map里的每一个键值对进行操作。
//以下是map的其它新特性
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里删除一个键值全都匹配的项:
map.remove(3, "val3");
map.get(3); // val33
map.remove(3, "val33");
map.get(3); // null
//有这个键则取此键的值,否则取默认值,此处为"not found"
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
}
到这儿差不多了,其他的基本上用的比较少,比如说注解,这些东西需要用到的时候再去找度娘吧,学习当中,有什么不对的地方各位提出来,一起学习,一起进步
推荐大家一个Java的学习网站:Java知识学习网,Java资料下载,Java学习路线图,网址:https://www.java1010.com