java语言基础及特性-02

时间:2022-01-19 17:06:11

1.hashMap与hashTable

        Java中数据存储方式最底层的两种结构,一种是数组,另一种就是链表,数组的特点:连续空间,寻址迅速,但是在删除或者添加元素的时候需要有较大幅度的移动,所以查询速度快,增删较慢。而链表正好相反,由于空间不连续,寻址困难,增删元素只需修改指针,所以查询慢、增删快。有没有一种数据结构来综合一下数组和链表,以便发挥他们各自的优势?答案是肯定的!就是:哈希表。哈希表具有较快(常量级)的查询速度,及相对较快的增删速度,所以很适合在海量数据的环境中使用。一般实现哈希表的方法采用“拉链法”,我们可以理解为“链表的数组”,如下图:

java语言基础及特性-02

        从上图中,我们可以发现哈希表是由数组 链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。

1.1 关于hashMap更详细的内容见:HashMap的存储与实现

1.2 HashTable的内部存储结构

HashTable和HashMap采用相同的存储机制,二者的实现基本一致,不同的是: 1.HashMap是非线程安全的,HashTable是线程安全的,内部的方法基本都是synchronized。 2.HashTable不允许有null值的存在,而hashMap则允许key或value为null。

在HashTable中调用put方法时,如果key为null,直接抛出NullPointerException。其它细微的差别还有,比如初始化Entry数组的大小等等,但基本思想和HashMap一样。


2.遍历map的4种方式的比较

public static void main(String[] args) {

Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");

//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}

//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}

//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}

3.Java中多线程

http://www.cnblogs.com/lwbqqyumidi/p/3804883.html

4.Java连接Oracle

这是道经常被写的面试题,http://m.blog.csdn.net/article/details?id=9068765,同时需要掌握socket的长连接和短连接;socket的同步和异步。


5.Java8中的新特性:stream

5.1利用stream将List转为Map

《利用Java8将list转为map》

5.2stream中常用几个API

《java8--List转为Map、分组、统计等操作》

//java8利用sream中map函数实现list转list
public List<Long> getIdList(List<Account> accounts) {
return accounts.stream().map(Account::getId).collect(Collectors.toList());
//return accounts.stream().map(Account->Account.getId).collect(Collectors.toList());
}

《Java8中的Steams API详解》

5.3利用stream将Map转为List

    //利用Java8中Stream接口map处理函数,将Map集合转为List
private static void convert_map_to_list_with_java8_lambda() {
Map<Integer, Movie> movieMap = new HashMap<Integer, Movie>();
movieMap.put(1, new Movie(1, "a"));
movieMap.put(2, new Movie(2, "b"));
movieMap.put(3, new Movie(3, "c"));

//将Map集合中所有的value值构建一个List
List<Movie> movieList = movieMap.entrySet().stream().map(o->o.getValue()).collect(Collectors.toList());
for (Movie movie:movieList) {
System.out.println(movie.getMoveName());
}
//利用Java8中forEach和lambda特性循环遍历输出
movieList.forEach(movie -> System.out.println(movie));
}

5.4 Java8新特性全搜罗


6.常用的非空判断

6.1字符串非空判断

org.apache.commons.lang3.StringUtils.StringUtils.isNoneEmpty(str);

一般情况下,在自己的代码中会继承org.apache.commons.lang3.StringUtils.StringUtils这个类而封装一个本地项目使用的工具类。

其实,在spring的框架中也有一个StringUtils工具类包。

6.2集合非空判断
org.springframework.util.CollectionUtils.isEmpty(list);

6.3 对象非空判断

obj != null;


7.Java8中的新特性:Lambda表达式

结合代码理解,如下:

package com.xiaojukeji.multiThread;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
* Description:
1.java8函数式接口:关于概念自行百度查询
下面是 Java SE 7 中已经存在的函数式接口:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.beans.PropertyChangeListener
除此之外,Java SE 8中增加了一个新的包:java.util.function,它里面包含了常用的函数式接口,例如:
Predicate<T>——接收 T 并返回 boolean
Consumer<T>——接收 T,不返回值
Function<T, R>——接收 T,返回 R
Supplier<T>——提供 T 对象(例如工厂),不接收值
UnaryOperator<T>——接收 T 对象,返回 T
BinaryOperator<T>——接收两个 T,返回 T
除了以上JDK以实现的函数式接口外,我们也可以自定义函数式接口;

2.Lamdba表达式的返回值就是以上函数式接口的某一种,也就是说lambda表达式返回值是函数式接口,
至于具体是哪一种函数式接口,则由java8根据上下文语义自行匹配,正是这种自适应匹配的能力,我们也可
将lambda返回值的类型称为"目标类型";

3.以下面ThreadApi类为例:
Runnable runnable = () -> {threadApi.m();};
new Tread(runnable).start;
即:() -> {threadApi.m();}返回值是一个只包含run一个方法的Runnable类型的函数式接口;

* Created by Guo_guo on 2017-7-16.
*/
public class ThreadApi {
public /*volatile*/ int count = 0;
public /*synchronized*/ void m (){
for (int i=0; i<10000; i++) {
count++;
}
}

public static void main(String[] args) {
ThreadApi threadApi = new ThreadApi();

List<Thread> threadList = new ArrayList<>(10);
for (int i=0; i<10; i++) {
//java8 lambda表达式构建线程,注意此处的ThreadApi没必要继承Runnable接口;
//() -> threadApi.m()的返回值是Runnable函数式接口
threadList.add(new Thread(() -> threadApi.m(), "thread-"+i) );
/*threadList.add(new Thread(
new Runnable() {
@Override
public void run() {
threadApi.m();
}
}
)//new Thread
);//.add
*/

/*
函数式接口:lanbda表达式返回值类型是一种函数式接口,
由于Java8中定义的函数式接口有多种类型,而lamdba表达式返回值能自适应目标类型,所以
也亦可将lambda表达式返回值的类型称之为"目标类型";
下面的例子中,(x) -> {System.out.print(x+": ");return "Function";}
返回值是Function类型的函数式接口类型,而在Function函数式接口类型中只有一个apply函数;
*/
Function<String,String> function = (x) -> {System.out.print(x+": ");return "Function";};
System.out.println(function.apply("hello world"));
}

threadList.forEach(obj -> obj.start());
threadList.forEach(obj -> {
try {
obj.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});

System.out.println(threadApi.count);
}
}

备注:关于Java中常见的一些坑或错误点,向大家推荐一本书,人民邮电出版社李刚主编的《疯狂Java:突破程序员基本功的16课》