Thinking in Java 中闪耀的星星(二)

来源:互联网 发布:两个excel表格匹配数据 编辑:程序博客网 时间:2024/05/21 18:40

26.如果要实现某些方法,比如倒序顺序,建议用匿名内部类
看代码:第一个方法是倒序,第二个是打乱顺序

public class MultiIterableClass extends IterableClass{    public Iterable<String> reversed(){        return new Iterable<String>(){            public Iterator<String> iterator(){                return new Iterator<String>(){                    int current =words.length-1;                    public boolean hasNext(){                        return ccurrent>-1;                    }                    public String next(){                        return words[current--];                    }                    public void remove(){                        throw new UnsupportedOperationException();                    }                };            }        };    }    public Iterable<String> randomized(){        return new Iterable<String>(){            public Iterator<String> iterator(){                List<String> shuffled=new ArrayList<String>(Arrays.asList(words));                Collections.shuffled(shuffled,new Random(47));                return shuffled.iterator();            }        };    }

27.异常的作用
异常是Java的重要组成部分。结合Thinking in Java,我的理解是:
1)..异常类似于美国人的未来型消费,就是保证类库,基层代码的可用性,安全性,健壮性,把风险扔给高层处理。
2).把程序的异常集中处理,与程序分离,增强程序可读性。
28.异常日志

import java.io.*;class LoggingException extends Exception{    private static Logger logger=Logger.getLogger("LoggingException");    public LoggingException(){        StringWriter trace =new StringWriter();        printStackTrace(new PrintWriter(trace));        logger.severe(trace.toString());    }}public class LoggingExceptions{    public static void main(String[] args){        try{               throw new LoggingException();        }catch(LoggingException e){               System.err.println("Caught"+e);        }        try{               throw new LoggingException();        }catch(LoggingException e){               System.err.println("Caught"+e);        }    }}/*Output七月 25, 2016 5:48:06 下午 LoggingException <init>严重: LoggingException        at LoggingExceptions.main(LoggingExceptions.java:14)CaughtLoggingException七月 25, 2016 5:48:06 下午 LoggingException <init>严重: LoggingException        at LoggingExceptions.main(LoggingExceptions.java:19)CaughtLoggingException*//~

29.处理关闭连接的嵌套异常
在io流和数据库连接中,经常会打开一些连接,而这些连接往往会要求在程序结束时关闭,常见的是放在finally中。可是,如果这个连接创建不成功呢?那又何须关闭?给出了一个思路:如果连接创建失败,就不需要关闭连接,如果连接创建成功,最后再finally中关闭,可以通过异常嵌套来实现。

import java.io.*;class InputFile{    private BufferedReader in;    public InputFile(String fname)throws Exception{        try{            in=new BufferedReader(new FileReader(fname));        }catch(FileNotFoundException e){            System.out.println("Could not open "+ fname);            throw e;        }catch(Exception e){            try{                in.close();            }catch(IOException e2){                System.out.println("in.close() unsuccessful");            }            throw e;        }finally{        }    }    public String getLine(){        String s;        try{            s=in.readLine();        }catch(IOException e){            throw new RuntimeException("readLine() failed");        }        return s;    }    public void dispose(){        try{            in.close();            System.out.println("dispose() successful");        }catch(IOException e2){            throw new RuntimeException("in.close() failed");        }    }}public class Cleanup{    public static void main(String[] args){        try{            InputFile in=new InputFile("Cleanup.java");            try{                String s;                int i=1;                while((s=in.getLine())!=null);            }catch(Exception e){                System.out.println("Caught Exception in main");                e.printStackTrace(System.out);            }finally{                in.dispose();            }        }catch(Exception e){            System.out.println("InputFile construction failed");        }    }}/*Outputdispose() successful*///~

30.使用异常的建议
1).如果对异常没有明确的处理方案,不要轻易去处理异常。
2).尽量抛出异常给高层
3).尽量把不同的异常抛给高层
31.java正则
如果没有经常使用,正则的结构难记。建议在用时查看java的api文档。顺便提一下,java的控制台输出的system.out.format(…)会让我们记起C语言中的printf(…)。看下面防火墙的正则例子:

import java.util.*;public class ThreatAnalyzer{    static String threatData=        "58.27.82.161@02/10/2005\n"+        "204.45.234.40@02/11/2005\n"+        "58.27.82.161@02/11/2005\n"+        "[Next log section with different data format]";    public static void main(String[] args){        Scanner scanner=new Scanner(threatData);        String pattern="(\\d+[.]\\d+[.]\\d+[.]\\d+)@"+        "(\\d{2}/\\d{2}/\\d{4})";        while(scanner.hasNext(pattern)){            scanner.next(pattern);            MatchResult match=scanner.match();            String ip=match.group(1);            String date=match.group(2);            System.out.format("Threat on %s from %s\n",date,ip);        }    }}/*OutputThreat on 02/10/2005 from 58.27.82.161Threat on 02/11/2005 from 204.45.234.40Threat on 02/11/2005 from 58.27.82.161*///~

32.类对象
先明白:一个java程序写好之后,在命令行下输入:javac xx.java 即编译,把.java文件里面的类编译为.class文件,当输入:java xx 是在运行程序。这时java虚拟机 JVM会加载用到的类。一开始并不会全部加载,而是等到需要用到该类才会加载(动态加载,也是java一大与c++区别的特性)。
那么平常在程序中又如何通过类对象获取对象呢?(反射机制)
1.class.forName(“xxx”) 会抛出一个ClassNotFoundException异常
2.xxx..class 比class.forName()更安全更高效。xxx.class 这句话分为3个步骤:
1).加载,加载.class文件的字节码
2).连接,为变量开辟地址空间
3). 初始化,为变量赋值
.class 的宗旨是:尽可能的懒。
33.Class类的几个方法
forName()/iddInterface()/getSimpleName()/getName()…
看例子:

interface HasBatteries{}interface Waterproof{}interface Shoots{}class Toy{    Toy(){}    Toy(int i){}}class FancyToy extends Toy implements HasBatteries,Waterproof,Shoots{    FancyToy(){        super(1);    }}public class ToyTest{    static void printInfo(Class cc){        System.out.println("Class name:"+cc.getName()+"is Interface?["+cc.isInterface()+"]");        System.out.println("Simple name"+cc.getSimpleName());        System.out.println("Canonical name:"+cc.getCanonicalName());    }    public static void main(String[] args){        Class c=null;        try{            c=Class.forName("FancyToy");        }catch(ClassNotFoundException e){            System.out.println("Can't find FancyToy");            System.exit(1);        }        printInfo(c);        for(Class face:c.getInterfaces()){            printInfo(face);        }        Class up=c.getSuperclass();        Object obj=null;        try{            obj=up.newInstance();        }catch(InstantiationException e){            System.out.println("Cannot instantiate");            System.exit(1);        }catch(IllegalAccessException e){            System.out.println("Cannot access");            System.exit(1);        }        printInfo(obj.getClass());    }}/*OutputClass name:FancyToyis Interface?[false]Simple nameFancyToyCanonical name:FancyToyClass name:HasBatteriesis Interface?[true]Simple nameHasBatteriesCanonical name:HasBatteriesClass name:Waterproofis Interface?[true]Simple nameWaterproofCanonical name:WaterproofClass name:Shootsis Interface?[true]Simple nameShootsCanonical name:ShootsClass name:Toyis Interface?[false]Simple nameToyCanonical name:Toy*///~

34.RTTI(Runtime Type Information)的作用
多态,继承等在java程序运行时,必须告诉java编译器对象的类型。Java7的钻石语法 class也是一种,就是在编译时告诉编译器这是一个类,等到程序运行到需要明确指出类型时,才给出明确的类型(可以通过反射机制获取对象类型)(这些都是增强编译速度的)。到两个重要的类:xxx.newInstance() 和instanceof()
看例子:

1).import java.util.*;class CountedInteger{    private static long counter;    private final long id=counter++;    public String toString(){        return Long.toString(id);    }}public class FilledList<T>{    private Class<T> type;    public FilledList(Class<T> type){this.type=type;}    public List<T> create(int nElements){        List<T> result=new ArrayList<T>();        try{            for(int i=0;i<nElements;i++){                result.add(type.newInstance());}            }catch(Exception e){                throw new RuntimeException(e);            }        return result;    }    public static void main(String[] args){        FilledList<CountedInteger> fl=new FilledList<CountedInteger>(CountedInteger.class);        System.out.println(fl.create(15));    }}/*Output[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]*///~        try{            obj=up.newInstance();        }catch(InstantiationException e){            System.out.println("Cannot instantiate");            System.exit(1);        }catch(IllegalAccessException e){            System.out.println("Cannot access");            System.exit(1);        }        printInfo(obj.getClass());    }}/*OutputClass name:FancyToyis Interface?[false]Simple nameFancyToyCanonical name:FancyToyClass name:HasBatteriesis Interface?[true]Simple nameHasBatteriesCanonical name:HasBatteriesClass name:Waterproofis Interface?[true]Simple nameWaterproofCanonical name:WaterproofClass name:Shootsis Interface?[true]Simple nameShootsCanonical name:ShootsClass name:Toyis Interface?[false]Simple nameToyCanonical name:Toy*///~

2).instanceof的用法是
if(A instanceof B)返回一个boolean值
35.java的泛型
在《数据结构》中,泛型指的是数据类型不一致,操作方法一致。然而c++的泛型才能称为真正意义上的泛型,java的泛型实际上是假的。java泛型在java编译器编译的时候会有一个erasure(擦除)特性,就是把类型置空,比如 ArrayList,ArrayList在编译的时候都是ArrayList(),两者是相等的,所以,java泛型在使用(运行时)必须明确指定类型。但是,java的擦除特性是为java类库与上层程序开发的相互影响而迁就的办法,解决了版本之间的兼容性和java的可移植性。
java泛型的设计是为拓展代码的复用性。
36.java泛型的语法
下面通过一个简单的java版本的栈例子来看看:

public class LinkedStack<T>{    private static class Node<U>{        U item;        Node<U> next;        Node(){item=null;next=null;}        Node(U item,Node<U> next){            this.item=item;            this.next=next;        }        boolean end(){return item==null&&next==null;}    }    private Node<T> top=new Node<T>();    public void push(T item){        top=new Node<T>(item,top);    }    public T pop(){        T result=top.item;        if(!top.end()){            top=top.next;        }        return result;    }     public static void main(String[] args){        LinkedStack<String> lss=new LinkedStack<String>();        for(String s:"Phasers on stun!".split(" "))        {            lss.push(s);        }        String s;        while((s=lss.pop())!=null){            System.out.println(s);        }    }}/*Outputstun!onPhasers*///~

37.在一些java的QQ群里,有人说:java泛型不就是集合中存取不同类吗?
这是错误的。因为泛型结合集合一起使用的功能强大,因此,java泛型大多以集合形式出现。
java泛型可以用在类,接口,方法。还可以继承。
38.泛型不能使用重载
void f(List v){}
void f(List w){}
由于擦除特性,在编译的时候两个都是:void f(List xx){},编译器也不会让程序编译通过的。
38.泛型的Latent typing特性
举个例子,一个哑巴类,一个狗类,一个表演类(里面有说话,坐下…的方法),只需要把狗/哑巴当成参数传给表演类,再调用表演类的方法,就可以表示狗/哑巴的表演。这就是Latent typing特性。很不幸,java没有latent typing特性,python与c++有。但是,在实际编程中,Latent typing是有用的,java虽然没有,但是可以手动模拟,看下面的例子:

import java.lang.reflect.*;class Mime{    public void walkAgainstTheWind(){}    public void sit(){System.out.println("Pretending to sit");}    public void puhInvisibleWalls(){}    public String toString(){return "Mime";}}class SmartDog{    public void speak(){System.out.println("Woof!");}    public void sit(){System.out.println("Sitting");}    public void reproduce(){}}class CommunicateReflectively{    public static void perform(Object speaker){        Class<?> spkr=speaker.getClass();        try{            try{                Method speak=spkr.getMethod("speak");                speak.invoke(speaker);            }catch(NoSuchMethodException e){                System.out.println(speaker+" cannot speak");            }            try{                Method sit=spkr.getMethod("sit");                sit.invoke(speaker);            }catch(NoSuchMethodException e){                System.out.println(speaker+" cannot sit");            }        }catch(Exception e){            throw new RuntimeException(speaker.toString(),e);        }    }}public class LatentReflection{    public static void main(String[] args){        CommunicateReflectively.perform(new SmartDog());        CommunicateReflectively.perform(new Mime());    }}/*OutputWoof!SittingMime cannot speakPretending to sit*///~

39.java泛型+策略模式+适配器模式模拟c++的泛型
代码有点多,也有点难理解,了解思路就行:

import java.math.*;import java.util.concurrent.atomic.*;import java.util.*;interface Combiner<T>{T combine(T x,T y);}interface UnaryFunction<R,T>{R function(T x);}interface Collector<T> extends UnaryFunction<T,T>{T result();}interface UnaryPredicate<T>{boolean test(T x);}public class Functional{    public static <T> T reduce(Iterable<T> seq,Combiner<T> combiner){        Iterator<T> it=seq.iterator();        if(it.hasNext()){            T result=it.next();            while(it.hasNext())                result=combiner.combine(result,it.next());            return result;        }        return null;    }    public static <T> Collector<T> forEach(Iterable<T> seq,Collector<T> func){        for(T t:seq)            func.function(t);        return func;    }    public static <T> List<T> filter(Iterable<T> seq,UnaryPredicate<T> pred){        List<T> result=new ArrayList<T>();        for(T t:seq)            if(pred.test(t))                result.add(t);        return result;    }    static class IntegerAdder implements Combiner<Integer>{        public Integer combine(Integer x,Integer y){            return x+y;        }    }    static class IntegerSubstracter implements Combiner<Integer>{        public Integer combine(Integer x,Integer y){            return x-y;        }    }    static class BigDecimalAdder implements Combiner<BigDecimal>{        public BigDecimal combine(BigDecimal x,BigDecimal y){            return x.add(y);        }    }    static class BigIntegerAdder implements Combiner<BigInteger>{        public BigInteger combine(BigInteger x,BigInteger y){            return x.add(y);        }    }    static class AtomicLongAdder implements Combiner<AtomicLong>{        public AtomicLong combine(AtomicLong x,AtomicLong y){            return new AtomicLong(x.addAndGet(y.get()));        }    }     static class BigDecimalUlp implements UnaryFunction<BigDecimal,BigDecimal>{        public BigDecimal function(BigDecimal x){            return x.ulp();        }    }    static class GreaterThan<T extends Comparable<T>> implements UnaryPredicate<T>{        private T bound;        public GreaterThan(T bound){this.bound=bound;}        public boolean test(T x){            return x.compareTo(bound)>0;        }    }    static class MultiplyingIntegerCollector implements Collector<Integer>{        private Integer val=1;        public Integer function(Integer x){            val*=x;            return val;        }        public Integer result(){return val;}    }    public static void main(String[] args){        List<Integer> li=Arrays.asList(1,2,3,4,5,6,7);        Integer result=reduce(li,new IntegerAdder());        System.out.println(result);        result=reduce(li,new IntegerSubstracter());        System.out.println(result);        System.out.println(filter(li,new GreaterThan<Integer>(4)));        System.out.println(forEach(li,new MultiplyingIntegerCollector()).result());        System.out.println(forEach(filter(li,new GreaterThan<Integer>(4)),new MultiplyingIntegerCollector()).result());        MathContext mc=new MathContext(7);        List<BigDecimal> lbd=Arrays.asList(new BigDecimal(1.1,mc),new BigDecimal(2.2,mc),        new BigDecimal(3.3,mc),new BigDecimal(4.4,mc));        BigDecimal rbd=reduce(lbd,new BigDecimalAdder());        System.out.println(rbd);        System.out.println(filter(lbd,new GreaterThan<BigDecimal>(new BigDecimal(3))));    }}/*Output28-26[5, 6, 7]504021011.000000[3.300000, 4.400000]*///~

40.数组+泛型
java设计者是推崇集合的,尤其是在高版本的java中。但是,对于基本类型,数组还是有用的。下面看看一个数组+泛型的例子:

import java.util.*;public class ArrayOfGenerics{    @SuppressWarnings("unchecked")    public static void main(String[] args){        List<String>[] ls;        List[] la=new List[10];        ls=(List<String>[])la;        ls[0]=new ArrayList<String>();        System.out.println(ls);        Object[] objects=ls;        objects[1] =new ArrayList<Integer>();        System.out.println(ls);    }}/*Output*///~
0 0