类型推断:
你还可以进一步简化你的代码。
Java编译器会从上下文(目标类型)推断出用什么函数式接口来配合Lambda表达式,这意味着它也可以推断出适合Lambda的签名,因为函数描述符可以通过目标类型来得到。这样做的好处在于,编译器可以了解Lambda表达式的参数类型,这样就可以在Lambda语法中省去标注参数类型。
List<String> list =
new ArrayList<>();
lambda表达式:
方法引用: 简化lambda,重复利用已有的代码
方法引用让你可以重复使用现有的方法定义,并像Lambda一样传递它们。
方法引用可以被看作仅仅调用 【特定方法的Lambda】 的一种快捷写法。
当你需要使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面。
1,引用构造器
Supplier<类名> 变量名 = 类名::new
Student stu = 变量名.get();
2,引用有参数构造器
BiFunction<参数1, 参数2, 类名> bf = 类名::new;
类名 变量名 = bf.apply(值1,值2);
2.5,引用数组构造器
IntFunction<int[]> arrayMaker = int[]::new;
int[] array = arrayMaker.apply(10);
3,引用静态方法
函数接口类型 变量名 = 类名::静态方法名
4,普通方法的引用:
函数接口类型 变量名 = 对象::方法名;
5,实例方法引用
类名::方法名A;
将lambda的参数 直接当做 A方法的参数
这种写法,不讨论返回值的问题。有就自动返回。
1,如果lambda的参数正好和::后面方法A的参数一样
那么就是调用::后面的方法A,把lambda的参数传进去
// R apply(T t);
Consumer<String> f = System.out::println;
Consumer<String> f1 = (t)->{System.out.println(t);};
// void accept(T t, U u);
BiConsumer<Integer,Integer> bc = (a,b)->{Math.max(a, b);};
BiConsumer<Integer,Integer> bc1 = Math::max;
2,如果lambda的参数 比::后面方法A的参数多
那么就是第一个参数调用::后面方法A,把lambda剩下的参数传入::后面的方法A
// R apply(T t);
Function<String,String> fun1 = String::toUpperCase;
Function<String,String> fun = (t)->t.toUpperCase();
// void accept(T t, U u);
BiConsumer<String,Integer> bc = String::substring;
BiConsumer<String,Integer> bc1 = (a,b)->{a.substring(b);};
Optional类 : 可选择的
作用:防止NullPointerException异常的辅助类型
取值:null 或者 不是null
Optional 被定义为一个简单的容器,其值可能是null或者不是null。在Java8之前一般某个函数应该返回非空对象但是偶尔却可能返回了null,而在Java 8中,不推荐你返回null而是返回Optional。
这是一个可以为null的容器对象。
如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional的使用:
1,创建Optional:
1.Optional.of(值);
为非null的值创建一个Optional,如果这个值为null报错
2,Optional.ofNullable(值);
为值创建一个Optional,如果值为null,则返回一个空的Optional
代码:Optional.ofNullable(null);
返回结果 : Optional.empty
2,使用:
1,isPresent();
如果值不为空返回true,否则返回false
2,get();
如果有一个值,返回值,否则抛出 NoSuchElementException
3,ifPresent(Consumer<? super T> consumer)
如果存在值,则使用该值调用指定的消费者,否则不执行任何操作。
Optional o1 = Optional.of(“tom”);
Optional o2 = Optional.ofNullable(null);
o1.ifPresent(System.out::println);
o2.ifPresent(System.out::println);//不执行
4,orElse(T other)
值如果存在返回值,否则返回 other 。
System.out.println(o1.orElse(“aaa”));//o1,不为null返回原值
System.out.println(o2.orElse(“aaa”));//o2,为null 返回aaa
5,orElseGet(Supplier<? extends T> other)
返回值(如果存在),否则调用 other并返回该调用的结果。
将操作的结果当做other值
6,orElseThrow(Supplier<? extends X> exceptionSupplier)
返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
7,map(Function<? super T,? extends U> mapper)
如果存在一个值,则应用提供的处理函数,如果结果不为空,则返回一个 Optional结果的 Optional 。为null抛异常
Optional<Integer> map = o1.map(str->1);
System.out.println(map.get());
8,flatMap(Function<? super T,Optional<U>> mapper)
如果一个值存在,应用提供的 Optional映射函数给它,返回该结果,否则返回一个空的 Optional 。
Optional<String> o3 = o1.flatMap(a->Optional.of("10"));
System.out.println(o3.get());
区别 : flatMap中的mapper返回值必须是Optional;flatMap不会对返回值自动封装为Optional类型
9,filter(Predicate<? super T> predicate)
如果一个值存在,并且该值给定的断言相匹配时,返回一个 Optional描述的值,否则返回一个空的 Optional 。
Optional<String> filter = o1.filter(str->str.length()<2);
System.out.println(filter);
Stream : 流水线
流水线 : 对数据的一组操作
jdk8,添加了新的类java.util.Stream:
Java8中的Stream是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利高效的聚合操作,或者大批量数据操作
Stream的API结合Lambda表达式,极大的提高编程效率和程序可读性
同时它提供串行和并行两种模式进行操作
流操作
java.util.stream.Stream中的Stream接口定义了许多操作。
它们可以分为两大类。
1,中间操作 : 可以连接起来的流操作
2,终端操作 : 关闭流的操作
终端操作会从流的流水线生成结果。
其结果是任何不是流的值,比如ListInteger,甚至void。
注:除非流水线上触发一个终端操作,否则中间操作不会执行任何处理。
使用流
流的使用一般包括三件事:
1,一个数据源(如集合)来执行一组操作;
2,一个中间操作链,形成一条流的流水线;
3,一个终端操作,执行流水线,并能生成结果。
4,Stream对象的构建
1.使用值构建
Stream<String> stream = Stream.of("a", "b", "c");
2. 使用数组构建
String[] strArray = new String[] {"a", "b", "c"};
Stream<String> stream = Stream.of(strArray);
Stream<String> stream = Arrays.stream(strArray);
3. 利用集合构建(不支持Map集合)
List<String> list = Arrays.asList(strArray);
stream = list.stream();
注:基本数据类型的流:IntStream ,LongStream,DoubleStream
不要选用Stream<Integer>,Stream<Long>,Stream<Double>因为自动装箱耗时,效率低
Java 8 中还没有提供其它基本类型数值的Stream
4,IntStream:数值Stream的构建:
IntStream s1 = IntStream.of(new int[]{1, 2, 3});
//[1,3)
IntStream s2 = IntStream.range(1, 3);
//[1,3]
IntStream s3 = IntStream.rangeClosed(1, 3);
Stream转换为其它类型:
Stream stream = Stream.of(“hello”,“world”,“tom”);
1,转换为Array
String[] strArray = stream.toArray(String[]::new);
2,转换为Collection
List list1 = stream.collect(Collectors.toList());
List list2 = stream.collect(Collectors.toCollection(ArrayList::new));
Set set3 = stream.collect(Collectors.toSet());
Set set4 = stream.collect(Collectors.toCollection(HashSet::new));
3. 转换为String
String str = stream.collect(Collectors.joining()).toString();
注意 : 一个 Stream 只可以使用一次,上面的代码为了简洁而重复使用了多次。
这个代码直接运行会抛出异常的:
java.lang.IllegalStateException: stream has already been operated upon or closed
流操作
中间操作 : Intermediate
map
map(Function<? super T,? extends R> mapper)
返回由给定函数应用于此流的元素的结果组成的流。
eg:把 Stream中 的每一个元素,映射成另外一个元素
public static void main(String[] args) throws Exception {
Stream<String> stream = Stream.of("tom","lisi","wangwu");
//R apply(T t);
Function<String,String> fun = (t)->t.toUpperCase();
List<String> list = stream.map(fun).collect(Collectors.toList());
System.out.println(list);
}
filter :
filter(Predicate<? super T> predicate)
返回由与此给定谓词匹配的此流的元素组成的流。
eg:获取字符串中长度大于3的字符串
public static void main(String[] args) throws Exception {
Stream<String> stream = Stream.of("tom","lisi","wangwu","a");
List<String> list = stream.filter((msg)->msg.length()>3).collect(Collectors.toList());
// boolean test(T t);
// Predicate<T>
System.out.println(list);
}
peek : 偷看,可以用来检查流当前的状态。
(Consumer<? super T> action)
对每个元素执行操作并返回一个新的 Stream
注意:调用peek之后,一定要有一个最终操作
public static void main(String[] args) throws Exception {
Stream<String> stream = Stream.of("tom","lisi","wangwu");
stream.filter(e -> e.length() > 3)
.peek(e -> System.out.println("符合条件的值为: " + e))
.collect(Collectors.toList());
}
distinct
返回由不同元素组成的流
sorted
返回由此流的元素组成的流,根据自然顺序排序。
sorted(Comparator<? super T> comparator)
返回由此流的元素组成的流,根据自然顺序排序。
limit
limit(long maxSize)
限制流的长度不超过maxSize
public static void main(String[] args) throws Exception {
Stream<String> stream = Stream.of("tom","lisi","wangwu","hhhhhh","werwerwefwe");
stream.filter(e -> e.length() > 3)
.peek(e -> System.out.println("符合条件的值为: " + e)).limit(2)
.collect(Collectors.toList());
}
满足条件的有多个,但是最终返回的集合中只有两个数据。
skip
skip(long n);
跳过多少个元素
public static void main(String[] args) throws Exception {
Stream<String> st = Stream.of("tom","lisi","wangwu","zhaoliu");
List<String> list = st.skip(2).collect(Collectors.toList());
System.out.println(list);
}
最终打印[wangwu, zhaoliu]
parallel : 并行
sequential : 有顺序
终端操作 : Terminal
forEach
遍历 接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式。
stream.forEach(System.out::println);
findFirst
总是返回 Stream 的第一个元素,或者空,返回值类型:Optional。
如果集中什么都没有,那么list.stream().findFirst()返回一个Optional<String>对象,但是里面封装的是一个null。
public static void main(String[] args) throws Exception {
Stream<String> stream = Stream.of("hello","world","tom");
Optional<String> findFirst = stream.findFirst();
System.out.println(findFirst);
}
anyMatch
allMatch(Predicate<? super T> predicate)
任意一个匹配成功返回true
allMatch
allMatch(Predicate<? super T> predicate)
所有匹配成功才返回true
noneMatch
noneMatch(Predicate<? super T> predicate)
没有一个匹配的就返回true 否则返回false
count 计数
返回Stream中元素的个数,返回值类型是long。
reduce 合并
允许通过指定的函数来将stream中的多个元素规约合并为一个元素.
它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max等都是特殊的 reduce。
eg1:
1-10累加
IntStream red = IntStream.range(1, 10);
Integer sum = red.reduce(0, (a, b) -> a+b);
System.out.println(sum);
eg2:
拼接字符串
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
System.out.println(concat);
eg3:
List<String> list = Arrays.asList("test","javac","hello","world","java","tom","C","javascript");
Optional<String> reduce = list.stream().sorted((s1,s2)->s2.length()-s1.length()).filter(s->s.startsWith("j")).map(s->s+"_briup").reduce((s1,s2)->s1+"|"+s2);
System.out.println(reduce.orElse("值为空"));
//javascript_briup|javac_briup|java_briup
max:
max(Comparator<? super T> comparator)
根据提供的 Comparator返回此流的最大元素。
String[] arr= {"zom","lisi","wagnwu"};
Stream<String> stream = Arrays.stream(arr);
Optional<String> max = stream.max(String::compareTo);
System.out.println(max.get());//zom
min:
min(Comparator<? super T> comparator)
根据提供的 Comparator返回此流的最小元素。
String[] arr= {"zom","lisi","wagnwu"};
Stream<String> stream = Arrays.stream(arr);
Optional<String> max = stream.min(String::compareTo);
System.out.println(max.get());//lisi
forEachOrdered
如果流具有定义的遇到顺序,则以流的遇到顺序对该流的每个元素执行操作。
Stream<String> stream = Stream.of("tom","lisi");
stream.forEachOrdered((a)->{System.out.println(a);});
toArray
toArray(IntFunction<A[]> generator)
使用提供的 generator函数返回一个包含此流的元素的数组,以分配返回的数组,以及分区执行或调整大小可能需要的任何其他数组。
Stream<String> stream = Stream.of("tom","lisi");
String[] array = stream.toArray(String[]::new);
collect
collect(Collector<? super T,A,R> collector)
使用 Collector对此流的元素执行 mutable reduction Collector 。
Stream<String> stream = Stream.of("tom","lisi");
List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
findAny
返回描述流的一些元素的Optional如果流为空,则返回一个空的Optional
iterator
获得迭代器
短路操作 : Short-circuiting:
anyMatch
allMatch
noneMatch
findFirst
findAny
limit
Stream.generate
自己来控制Stream的生成
这种情形通常用于随机数、常量的 Stream,或者需要前后元素间维持着某种状态信息的 Stream。
把 Supplier 实例传递给 Stream.generate() 生成的 Stream,由于它是无限的,在管道中,必须利用limit之类的操作限制Stream大小。
可以使用此方式制造出海量的测试数据
eg:
生成100个随机数并由此创建出Stream实例
Stream.generate(()->(int)(Math.random()*100)).limit(100).forEach(System.out::println);
工具类:Collectors
java.util.stream.Collectors 类
主要作用就是辅助进行各类有用的操作。
eg1:
把Stream中的元素进行过滤然后再转为List集合
List<String> list = Arrays.asList("test","hello","world","java","tom","C","javascript");
List<String> result = list.stream().filter(s->s.length()>4).collect(Collectors.toList());
串行和并行
串行Stream上的操作是在一个线程中依次完成
并行Stream则是在多个线程上同时执行
串行和并行的相互转换:
可以通过对收集源调用parallelStream方法来把集合转换为并行流。
对顺序流调用parallel方法把流转换成并行流。
并行流就是一个把内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
对顺序流调用parallel方法并不意味着流本身有任何实际的变化。它在内部实际上就是设了一个boolean标志,表示你想让调用parallel之后进行的所有操作都并行执行。
只需要对并行流调用BaseStream下的sequential()方法就可以把它变成顺序流。
并行测试:
public static void main(String[] args) {
//生成100万个不同的字符串放到集合中
int max = 1000000;
List values = new ArrayList(max);
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
//1纳秒*10^9=1秒
long t0 = System.nanoTime();
//串行stream
long count = values.stream().sorted().count();
//并行stream
//long count = values.parallelStream().sorted().count();
long t1 = System.nanoTime();
long time = t1 - t0;
System.out.println(count);
System.out.println(time);
}
Map集合: HashMap
Map类型不支持stream
Java8为Map新增的方法
基础数据:
Map<String, Integer> map = new HashMap<>();
map.put("tom",1);
map.put("lisi",2);
map.put("wangwu",3);
map.put("zhaoliu",4);
map.put("zhangsan",null);
Object compute(Object key, BiFunction remappingFunction):
该方法使用remappingFunction根据原key-value对计算一个新的value。
只要新的value不为null,就使用新的value覆盖原value;
如果新的value为null,则删除原key-value对;
// BiFunction<? super K, ? super V, ? extends V>
// R apply(T t, U u);
BiFunction<String, Integer, Integer> bif = (key,value)->{
return 20;
};
map.compute("tom", bif);//替换tom的值
map.compute("lisi", (key,value)->33);//替换lisi的值
Object computeIfAbsent(Object key, Function mappingFunction):
如果传入的key参数在Map中对应的value为null,
该方法将使用mappingFunction根据原key、value计算一个新的结果,
则用该计算结果覆盖原value;
如果传入的key参数在Map中对应的value不为null,则该方法不做任何事情;
如果原Map原来不包括该key,该方法可能会添加一组key-value对。
value为null:
map.computeIfAbsent("zhangsan", (key)->19);
System.out.println(map);
value不为null:
map.computeIfAbsent("zhaoliu", (key)->19);
System.out.println(map);
key不存在:
map.computeIfAbsent("a", (key)->19);
System.out.println(map);
Object computeIfPresent(Object key, BiFunction remappingFunction):
并且该计算结果不为null,则使用该结果覆盖原来的value;
//R apply(T t, U u);
map.computeIfPresent("zhaoliu", (key,value)->10);
System.out.println(map);
void forEach(BiConsumer action):
该方法是Java8为Map新增的一个遍历key-value对的方法。
map.forEach((key,value)->{
System.out.println(key+"--"+value);
});
Object getOrDefault(Object key, V defaultValue):
获取指定的key对应的value。如果该key不存在,则返回defaultValue。
System.out.println(map.getOrDefault("zhaoliu", 10));//4
System.out.println(map.getOrDefault("a", 10));//10
Object merge(Object key, Object value, BiFunction remappingFunction):
该方法会先根据key参数获取该Map中对应的value。
如果获取的value为null,则直接使用传入的value覆盖原value。
如果获取的value不为null,则使用remappingFunction函数根据原value、新value计算一个新的结果,并用新的结果去覆盖原有的value。
key对应的value为null:
map.merge("zhangsan", 20, (key,value)->{return value+1;});
System.out.println(map);
//zhangsan=20
key对应的value不为null:
map.merge("zhaoliu", 20, (key,value)->{return value+1;});
System.out.println(map);
//{zhaoliu=21}
Object putIfAbsent(Object key, Object value):
该方法会自动检测指定的key对应的value是否为null,
如果该key对应的value为null,则使用传入的新value代替原来的null。
如果该key对应的value不是null,那么该方法不做任何事情。
key对应value为null:
map.putIfAbsent("zhangsan", 20);
System.out.println(map);
//zhangsan=20
key对应value不为null:
map.putIfAbsent("wangwu", 20);
System.out.println(map);
//wangwu=3
Object replace(Object key, Object value):
将Map中指定key对应的value替换成新value并把被替换掉的旧值返回。
如果key在Map中不存在,该方法不会添加key-value对,而是返回null。
map.replace("lisi", 42);
System.out.println(map);
//lisi=42
Boolean replace(K key, V oldValue, V newValue):
将Map中指定的key-value对的原value替换成新value。
如果在Map中找到指定的key-value对,则执行替换并返回true,否则返回false。
key-value都正确
map.replace("lisi", 2, 23);
System.out.println(map);
//lisi=23//替换成功
key-value没有都正确
map.replace("lisi", 21, 23);
System.out.println(map);
//lisi=2//替换失败
replaceAll(BiFunction function):
该方法使用function对原key-value对执行计算,
并将计算结果作为key-value对的value值
map.replaceAll((key,value)->{return value!=null?value+1:0;});
System.out.println(map);
{lisi=3, tom=2, zhaoliu=5, zhangsan=0, wangwu=4}
Date:
最原始:注:本次用到的Date都是java.util.Date
1,创建时间
//当前时间
java.util.Date d = new java.util.Date();
//某个时间戳创建时间
//时间戳 : 1970-01-01到某个日期的毫秒数
java.util.Date d1 = new java.util.Date(12310231231L);
2,将字符串解析为时间Date类型
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String msg = "2019-8-28 7:41:07";
Date parse = sdf.parse(msg);
System.out.println(parse.toLocaleString());
3,将日期Date类型格式化为字符串:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String format = sdf.format(new Date());
System.out.println(format);
新:提供了java.time包下的类处理日期
java.time – 包含值对象的基础包
java.time.chrono – 提供对不同的日历系统的访问
java.time.format – 格式化和解析时间和日期
java.time.temporal – 包括底层框架和扩展特性
java.time.zone – 包含时区支持的类
新增:
创建日期:
//创建指定时间
LocalDate date = LocalDate.of(2019, Month.OCTOBER, 28);
System.out.println(date.toString());
//创建当前时间
LocalDateTime now = LocalDateTime.now();
//创建指定时间
LocalDateTime ldt = LocalDateTime.of(2019, 8, 28, 7, 49, 28);
System.out.println(ldt.toString());
格式化日期:
将字符串转换为日期
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String time= "2019-08-28";
LocalDate dl1 = LocalDate.parse(time, dtf);
String str1 = dl1.format(dtf);
System.out.println(str1);