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

5 篇文章 0 订阅
5 篇文章 0 订阅

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");
        }
    }
}/*Output
dispose() 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);
        }
    }
}/*Output
Threat on 02/10/2005 from 58.27.82.161
Threat on 02/11/2005 from 204.45.234.40
Threat 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());
    }
}/*Output
Class name:FancyToyis Interface?[false]
Simple nameFancyToy
Canonical name:FancyToy
Class name:HasBatteriesis Interface?[true]
Simple nameHasBatteries
Canonical name:HasBatteries
Class name:Waterproofis Interface?[true]
Simple nameWaterproof
Canonical name:Waterproof
Class name:Shootsis Interface?[true]
Simple nameShoots
Canonical name:Shoots
Class name:Toyis Interface?[false]
Simple nameToy
Canonical 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());
    }
}/*Output
Class name:FancyToyis Interface?[false]
Simple nameFancyToy
Canonical name:FancyToy
Class name:HasBatteriesis Interface?[true]
Simple nameHasBatteries
Canonical name:HasBatteries
Class name:Waterproofis Interface?[true]
Simple nameWaterproof
Canonical name:Waterproof
Class name:Shootsis Interface?[true]
Simple nameShoots
Canonical name:Shoots
Class name:Toyis Interface?[false]
Simple nameToy
Canonical 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);
        }
    }
}/*Output
stun!
on
Phasers
*///~

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());
    }
}/*Output
Woof!
Sitting
Mime cannot speak
Pretending 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))));
    }
}/*Output
28
-26
[5, 6, 7]
5040
210
11.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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值