Java几点总结

1. 前言

这里也是从那几篇旧博客中抽出来的,不算一大部分了,主要介绍Optional、Stream、lambda、Buffer等相关知识点

2. Optional

基础

为了防止NullPointerException的一个工具类,Optional是一个容器,其值可以是null或者不是null。

通过对null进行封装,实现了函数式编程,不必写过多的if else进行判断。

其主要的函数包括:

  • of:将非空的Bean转换成Optional
  • ofNullable:将可以为空的Bean转换成Optional
  • map:map是对Optional进行操作,这个map与mapReduce的map不同
  • filter:对Optional进行操作,若返回为false则后边为null
  • orElse:Optional转换成Bean,若为null返回指定值
  • orElseThrow:Option转换成Bean,若为null抛异常

示例

示例1:

public static String getName(User u) {
    if (u == null || u.name == null)
        return "Unknown";
    return u.name;
}

改写为Optional风格:

public static String getName(User u) {
    return Optional.ofNullable(u)
                    .map(user->user.name)
                    .orElse("Unknown");
}

示例2:

public static String getChampionName(Competition comp) throws IllegalArgumentException {
    if (comp != null) {
        CompResult result = comp.getResult();
        if (result != null) {
            User champion = result.getChampion();
            if (champion != null) {
                return champion.getName();
            }
        }
    }
    throw new IllegalArgumentException("The value of param comp isn't available.");
}

改写成Optional风格:

public static String getChampionName(Competition comp) throws IllegalArgumentException {
    return Optional.ofNullable(comp)
            .map(Competition::getResult)  // 相当于c -> c.getResult(),下同
            .map(CompResult::getChampion)
            .map(User::getName)
            .orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available."));
}

示例3:

对name进行验证的,通过filter传入验证函数

public void setName(String name) throws IllegalArgumentException {
    this.name = Optional.ofNullable(name)
                        .filter(User::isNameValid)
                        .orElseThrow(()->new IllegalArgumentException("Invalid username."));
}

3. Stream

基础

表示能应用在一组元素执行的操作序列。Stream 操作分为中间操作和最终操作两种,最终操作是返回特定类型的计算结果,而中间操作返回 Stream 本身,这样你就可以将多个操作依次串起来。Stream 的创建需要指定一个数据源,比如 java.util.Collection 的子类,如 List 或者 Set,但不支持 Map。

示例

List<String> stringList = new ArrayList<>();
stringList.add("ddd2");
stringList.add("aaa2");
stringList.add("bbb1");
stringList.add("aaa1");
stringList.add("bbb3");
stringList.add("ccc");
stringList.add("bbb2");
stringList.add("ddd1");

// 测试 Filter(过滤)
stringList.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);  // aaa2 aaa1

// 测试 Sort (排序)
stringList.stream().sorted().filter((s) -> s.startsWith("a")).forEach(System.out::println);// aaa1 aaa2

// 测试 Map 操作
stringList.stream().map(String::toUpperCase).sorted((a, b) -> b.compareTo(a)).forEach(System.out::println);  // "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"

// 测试 Match (匹配)操作
boolean anyStartsWithA = stringList.stream().anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA);      // true

boolean allStartsWithA = stringList.stream().allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA);      // false

boolean noneStartsWithZ = stringList.stream().noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ);     // true

// 测试 Count (计数)操作
long startsWithB = stringList.stream().filter((s) -> s.startsWith("b")).count();
System.out.println(startsWithB);    // 3

// 测试 Reduce (规约)操作
Optional<String> reduced = stringList.stream().sorted().reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);  // aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2

// 求和,sumValue = 10, 有起始值,返回的是int
int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);

// 求和,sumValue = 10, 无起始值,返回的是Opitonal
int sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();

4. lambda

lambda表达式是在js、python等语言中早就存在,Java在1.8版本中引入。这里简单做个介绍:

lambda之前的问题

String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };
Arrays.sort(array, new Comparator<String>() {
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
});

在lambda出现之前,要想传入一个函数,需要采用类的方式来传入,由sort去调用固定的compare接口。

这种方式也能解决问题,但比较笨拙

这种方法有很多:如RunableCallableConsumer等等

lambda方案

lambda的引入,简化了这个问题

String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };
Arrays.sort(array, (s1, s2) -> {
    return s1.compareTo(s2);
});

lambda如何做的

Comparator接口中只用一个抽象方法(非static、非default):compare,这种方法在Java1.8中被定义为单方法接口或者叫函数式接口,可以用注解@FunctionalInterface标记。

例如:

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

每个 Lambda 表达式都能隐式地赋值给函数式接口,前提是lambda表达式的入参与返回类型要函数式接口匹配。

public interface MyInterface { 
    void printIt(String text); 
}
MyInterface myInterface = (String text) -> { 
    System.out.print(text); 
};

下边看一个对比的示例:

 //定义一个函数式接口
@FunctionalInterface
public interface WorkerInterface {
   public void doSomeWork();
}

public class WorkerInterfaceTest {
    public static void execute(WorkerInterface worker) {
        worker.doSomeWork();
    }

    public static void main(String [] args) {
        //invoke doSomeWork using Annonymous class
        execute(new WorkerInterface() {
            @Override
            public void doSomeWork() {
                System.out.println("Worker invoked using Anonymous class");
            }
        });
        //invoke doSomeWork using Lambda expression 
        execute( () -> System.out.println("Worker invoked using Lambda expression") );
    }

}

5. Buffer与I/O流

IO流的JavaIO流

buffer:内存中一块确定的临时存储区域。
stream:一段不确定长度的数据序列,可以认为stream就是I/O中input部分的FIFO实现。通过buffer可以增强stream的读写效率。

streams是读取、写入到文件、网络、设备中IO交互的抽象。对于字符流,抽象出了Reader与Writer,对于字节流抽象出了InputStream与OutputStream,本质上它们都是流。

以从硬盘上读取数据为例,一个字节一个字节的读取,效率太低,通过使用Buffer来加速读取,一次读取很多数据,然后存储到Buffer中。再从Buffer中一个字节一个字节的读取。

IO流 20191014111930276

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×