Java8学习笔记(2)
3.Optional
在复杂的if (xx != null)的情况中,使用Optional代码的可读性更好,而且它提供的是编译时检查,能极大的降低NPE这种Runtime Exception 对程序的影响,或者迫使程序员更早的在编码阶段处理空值问题,而不是留到运行时再发现和调试。
// Optional 的两个用例:以下两组示例是等价的
// Java 8
Optional.ofNullable(text).ifPresent(System.out::println);
// Pre-Java 8
if (text != null) {
System.out.println(text);
}
//----------
// Java 8
return Optional.ofNullable(text).map(String::length).orElse(-1);
// Pre-Java 8
return if (text != null) ? text.length() : -1;
- 创建
- Optional.ofNullable()
- Optional.of()
- Optional.empty()
- 安全使用
- Optional.ifPresent()
- Optional.isPresent()
- 获取值
- Optional.get()
- Optional.orElseGet()
- Optional.orElseThrow()
- 过滤与转换
- Optional.filter()
- Optional.map()
4.函数式接口
1.概述:
在 Java 中,Marker(标记)类型的接口是一种没有方法或属性声明的接口,简单地说,marker 接口是空接口。相似地,函数式接口是只包含一个抽象方法声明的接口。
2.常用函数式接口
- java.lang.Runnable
- java.util.function.Predicate
//原始类型特化:IntPredicate, LongPredicate, DoublePredicate
public interface Predicate<T> {
boolean test(T t);
}
// 判断是否是正数
IntPredicate predicate = i -> (i > 0);
// true
predicate.test(5);
- java.util.function.Consumer
// 原始类型特化:IntConsumer,LongConsumer, DoubleConsumer
public interface Consumer<T> {
void accept(T t);
}
// 输出数字到控制台
IntConsumer consumer = i -> System.out.println(i);
//IntConsumer consumer = System.out::println;
// 5
consumer.accept(5);
- java.util.function.Function
//原始类型特化:
// IntFunction < R >, IntToDoubleFunction, IntToLongFunction,
// LongFunction < R >, LongToDoubleFunction, LongToIntFunction,
// DoubleFunction < R >,
// ToIntFunction < T >, ToDoubleFunction < T >, ToLongFunction < T >
public interface Function<T, R> {
R apply(T t);
}
// 整型转字符串
IntFunction<String> int2StringFunc = i -> (i + "");
//"10"
int2StringFunc.apply(10);
// 字符串转整型
ToIntFunction<String> string2IntFunc = s -> Integer.parseInt(s);
//ToIntFunction<String> string2IntFunc = Integer::parseInt;
// 22
string2IntFunc.applyAsInt("22");
- java.util.function.Supplier
// 原始类型特化:BooleanSupplier,IntSupplier, LongSupplier, DoubleSupplier
public interface Supplier<T> {
T get();
}// 无中生有
Supplier<String> supplier = () -> "Welcome to my blog";
// "Welcome to my blog"
supplier.get();
- 输入为两个参数的方法
- Bifunction
- BiConsumer
- BiPredicate
- BinaryOperator
3.默认方法
常用默认方法
Consumer :andThen()
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
Function: compose() andThen()
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
Predicate: and() or() negate()
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
5.方法引用
- 类的静态方法
在重写方法时,方法体中只有一行代码,并且这行代码时调用了某个类的静态方法,并且把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中
格式类名::方法名
- 对象的实例方法
方法体中只有一行代码,并且这行代码时调用了某个对象的成员方法,并且把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中
格式对象名::方法名
StringBuilder sb =new StringBuilder();
authors.stream()
.map(author -> author.getName())
.forEach(sb::append);
- 类的实例方法
方法体中只有一行代码,并且这行代码时调用了第一个参数的成员方法,并且把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中
格式第一个参数的类名::方法名
interface UseString{
String use(String str,int start,int length);
}
public static String subPersonName(String str,UseString useString){
int start =0,length =1;
return useString.use(str,start,length)
}
public static void main(String[] args){
subPersonName("str",String::subString);
}
- 构造器引用
法体中只有一行代码,并且这行代码时调用了某个类的构造方法,并且把要重写的抽象方法中所有的参数都按照顺序传入了这个构造方法中
格式类名::new
6.其它
-
并行流
stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,需要注意使用并行流的前提是流中的数据处理没有顺序要求(会乱序,即使用了forEachOrdered)。
除了直接创建并行流,还可以通过parallel()把顺序流转换成并行流:
Optional<Integer> findFirst = list.stream().parallel().filter(x->x>4).findFirst();
- Java8中新增方法
- Collection: removeIf() | spliterator() | stream() | parallelStream() | forEach()
- List: replaceAll() | sort()
- Map: getOrDefault() | forEach() | replaceAll() | putIfAbsent() | remove() replace() | computeIfAbsent() | computeIfPresent() | merge()
- stream基本数据类型优化
Stream流的方法大都使用了泛型,所以涉及到的参数和返回值都是引用数据类型
JDK5中引入的自动装箱和自动拆箱让我们在使用对应的包装类时就好像使用基本数据类型一样方便,但是在大量数据不断装箱和拆箱的时候,时间消耗是可观的,所以要使用专门针对基本数据类型的方法
例如:mapToInt,mapToLong,mapToDouble,flatMapToInt,flatMapToLong,flatMapToDouble
persons.stream()
.map(person -> person.getAge())//Stream<Integer>
.map(age -> age+10)
.filter(age -> age>18)
.forEach(System.out::println)
//优化为
persons.stream()
.mapToInt(person -> person.getAge()) //IntStream
.map(age -> age+10) //这里新建的函数式接口是 IntUnaryOperator
.filter(age -> age>18)
.forEach(System.out::println)
- 常用场景
//基本类型int[] -->List<Integer>
int[] src = {1,2,3,4,5,6,7,8,9,10};
List<Integer> list = Arrays.stream( src ) //返回IntStream
.boxed() //装箱
.collect(Collectors.toList());
// List<Integer>-->int[]
int[] arr=list.stream()
.mapToInt(Integer::valueOf)//参数可以为 Integer::intValue
.toArray();
// char[] --->List<Character>
new String(cha).chars() //str.chars() 返回IntStream
.mapToObj(i -> (char) i) //IntStream.mapToObj(),这里装箱为Character
.collect(Collectors.toList())
## 3.Optional
在复杂的if (xx != null)的情况中,使用Optional代码的可读性更好,而且它提供的是编译时检查,能极大的降低NPE这种Runtime Exception 对程序的影响,或者迫使程序员更早的在编码阶段处理空值问题,而不是留到运行时再发现和调试。
```java
// Optional 的两个用例:以下两组示例是等价的
// Java 8
Optional.ofNullable(text).ifPresent(System.out::println);
// Pre-Java 8
if (text != null) {
System.out.println(text);
}
//----------
// Java 8
return Optional.ofNullable(text).map(String::length).orElse(-1);
// Pre-Java 8
return if (text != null) ? text.length() : -1;
- 创建
- Optional.ofNullable()
- Optional.of()
- Optional.empty()
- 安全使用
- Optional.ifPresent()
- Optional.isPresent()
- 获取值
- Optional.get()
- Optional.orElseGet()
- Optional.orElseThrow()
- 过滤与转换
- Optional.filter()
- Optional.map()
4.函数式接口
1.概述:
在 Java 中,Marker(标记)类型的接口是一种没有方法或属性声明的接口,简单地说,marker 接口是空接口。相似地,函数式接口是只包含一个抽象方法声明的接口。
2.常用函数式接口
- java.lang.Runnable
- java.util.function.Predicate
//原始类型特化:IntPredicate, LongPredicate, DoublePredicate
public interface Predicate<T> {
boolean test(T t);
}
// 判断是否是正数
IntPredicate predicate = i -> (i > 0);
// true
predicate.test(5);
- java.util.function.Consumer
// 原始类型特化:IntConsumer,LongConsumer, DoubleConsumer
public interface Consumer<T> {
void accept(T t);
}
// 输出数字到控制台
IntConsumer consumer = i -> System.out.println(i);
//IntConsumer consumer = System.out::println;
// 5
consumer.accept(5);
- java.util.function.Function
//原始类型特化:
// IntFunction < R >, IntToDoubleFunction, IntToLongFunction,
// LongFunction < R >, LongToDoubleFunction, LongToIntFunction,
// DoubleFunction < R >,
// ToIntFunction < T >, ToDoubleFunction < T >, ToLongFunction < T >
public interface Function<T, R> {
R apply(T t);
}
// 整型转字符串
IntFunction<String> int2StringFunc = i -> (i + "");
//"10"
int2StringFunc.apply(10);
// 字符串转整型
ToIntFunction<String> string2IntFunc = s -> Integer.parseInt(s);
//ToIntFunction<String> string2IntFunc = Integer::parseInt;
// 22
string2IntFunc.applyAsInt("22");
- java.util.function.Supplier
// 原始类型特化:BooleanSupplier,IntSupplier, LongSupplier, DoubleSupplier
public interface Supplier<T> {
T get();
}// 无中生有
Supplier<String> supplier = () -> "Welcome to my blog";
// "Welcome to my blog"
supplier.get();
- 输入为两个参数的方法
- Bifunction
- BiConsumer
- BiPredicate
- BinaryOperator
3.默认方法
常用默认方法
Consumer :andThen()
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
Function: compose() andThen()
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
Predicate: and() or() negate()
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
5.方法引用
- 类的静态方法
在重写方法时,方法体中只有一行代码,并且这行代码时调用了某个类的静态方法,并且把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中
格式类名::方法名
- 对象的实例方法
方法体中只有一行代码,并且这行代码时调用了某个对象的成员方法,并且把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中
格式对象名::方法名
StringBuilder sb =new StringBuilder();
authors.stream()
.map(author -> author.getName())
.forEach(sb::append);
- 类的实例方法
方法体中只有一行代码,并且这行代码时调用了第一个参数的成员方法,并且把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中
格式第一个参数的类名::方法名
interface UseString{
String use(String str,int start,int length);
}
public static String subPersonName(String str,UseString useString){
int start =0,length =1;
return useString.use(str,start,length)
}
public static void main(String[] args){
subPersonName("str",String::subString);
}
- 构造器引用
法体中只有一行代码,并且这行代码时调用了某个类的构造方法,并且把要重写的抽象方法中所有的参数都按照顺序传入了这个构造方法中
格式类名::new
6.其它
-
并行流
stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,需要注意使用并行流的前提是流中的数据处理没有顺序要求(会乱序,即使用了forEachOrdered)。
除了直接创建并行流,还可以通过parallel()把顺序流转换成并行流:
Optional<Integer> findFirst = list.stream().parallel().filter(x->x>4).findFirst();
- Java8中新增方法
- Collection: removeIf() | spliterator() | stream() | parallelStream() | forEach()
- List: replaceAll() | sort()
- Map: getOrDefault() | forEach() | replaceAll() | putIfAbsent() | remove() replace() | computeIfAbsent() | computeIfPresent() | merge()
- stream基本数据类型优化
Stream流的方法大都使用了泛型,所以涉及到的参数和返回值都是引用数据类型
JDK5中引入的自动装箱和自动拆箱让我们在使用对应的包装类时就好像使用基本数据类型一样方便,但是在大量数据不断装箱和拆箱的时候,时间消耗是可观的,所以要使用专门针对基本数据类型的方法
例如:mapToInt,mapToLong,mapToDouble,flatMapToInt,flatMapToLong,flatMapToDouble
persons.stream()
.map(person -> person.getAge())//Stream<Integer>
.map(age -> age+10)
.filter(age -> age>18)
.forEach(System.out::println)
//优化为
persons.stream()
.mapToInt(person -> person.getAge()) //IntStream
.map(age -> age+10) //这里新建的函数式接口是 IntUnaryOperator
.filter(age -> age>18)
.forEach(System.out::println)
- 常用场景
//基本类型int[] -->List<Integer>
int[] src = {1,2,3,4,5,6,7,8,9,10};
List<Integer> list = Arrays.stream( src ) //返回IntStream
.boxed() //装箱
.collect(Collectors.toList());
// List<Integer>-->int[]
int[] arr=list.stream()
.mapToInt(Integer::valueOf)//参数可以为 Integer::intValue
.toArray();
// char[] --->List<Character>
new String(cha).chars() //str.chars() 返回IntStream
.mapToObj(i -> (char) i) //IntStream.mapToObj(),这里装箱为Character
.collect(Collectors.toList())
部分内容来源于网上,侵删。