`
leonzhx
  • 浏览: 770540 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多

1) Generics are one of the more significant changes in Java SE5. Generics implement the concept of parameterized types, which allow multiple types. The term "generic" means "pertaining or appropriate to large groups of classes." The original intent of generics in programming languages was to allow the programmer the greatest amount of expressiveness possible when writing classes or methods, by loosening the constraints on the types that those classes or methods work with. 

 

2) When you create an instance of a parameterized type, casts will be taken care of for you and the type correctness will be ensured at compile time. This seems like an improvement. 

 

3) One of the primary motivations for generics is to specify what type of object a container holds, and to have that specification backed up by the compiler. So instead of Object, we’d like to use an unspecified type, which can be decided at a later time. To do this, you put a type parameter inside angle brackets after the class name, and then substitute an actual type when you use the class. 

 

4) A tuple is simply a group of objects wrapped together into a single object. The recipient of the object is allowed to read the elements but not put new ones in. (This concept is also called a Data Transfer Object (or Messenger.) Tuples can typically be of any length, but each object in the tuple can be of a different type. Note that a tuple implicitly keeps its elements in order. 

 

5) You cannot use primitives as type parameters. However, Java SE5 conveniently added autoboxing and autounboxing to convert from primitive types to wrapper types and back. 

 

6) You can also parameterize methods within a class. The class itself may or may not be generic—this is independent of whether you have a generic method. As a guideline, you should use generic methods "whenever you can." That is, if it’s possible to make a method generic rather than the entire class, it’s probably going to be clearer to do so. In addition, if a method is static, it has no access to the generic type parameters of the class, so if it needs to use genericity it must be a generic method. To define a generic method, you simply place a generic parameter list before the return value. 

 

7) Notice that with a generic class, you must specify the type parameters when you instantiate the class.(otherwise cause a compile warning)  But with a generic method, you don’t usually have to specify the parameter types, because the compiler can figure that out for you. (either from the argument passed to method or from return type) This is called type argument inference. Type inference doesn’t work for anything other than assignment when it can only infer from its return type. If you pass the result of a method call as an argument to another method, the compiler will not try to perform type inference. Instead it will treat the method call as though the return value is assigned to a variable of type Object. (won't compile)

Commented By Sean: I think it's because that method can be overloaded or overrided, to determine which method to call , JVM need to know the runtime type of the arguement, so compiler cann't know the exact method to be called. 

 

8) It is possible to explicitly specify the type in a generic method, although the syntax is rarely needed. To do so, you place the type in angle brackets after the dot and immediately preceding the method name. When calling a method from within the same class, you must use this before the dot, and when working with static methods, you must use the class name before the dot. 

 

9) Java compiler won't complain if you assign a parameterized class object to an unparameterized reference(upcast), but will issue a warning if you do vice versa.

Commented By Sean: Compiler will issue a warning if you use a unparameterized reference for a parameterized type. 

 

10) EnumSet is a Java SE5 tool for easy creation of Sets from enums. The static method EnumSet.range( ) is given the first and last elements of the range to create a Set including the enums in the range. 

 

11) Although you can say ArrayList.class, you cannot say ArrayList<Integer>.class.(Acutally you cannot access static members of a class use the generic form of class. Because type parameter is only meaningful for instance.Class.getTypeParameters( ) returns an array of TypeVariable objects that represent the type variables declared by the generic declaration. All you find out from it is the identifiers that are used as the parameter placeholders. (parameters instead of arguements) The cold truth is that there’s no information about generic parameter types available inside generic code. You can know things like the identifier of the type parameter and the bounds of the generic type—you just can’t know the actual type parameter(s) used to create a particular instance. 

 

12) Java generics are implemented using erasure. This means that any specific type information is erased when you use a generic. Inside the generic, the only thing that you know is that you’re using an object. So List<String> and List< Integer> are, in fact, the same type at run time. Both forms are "erased" to their raw type, List. 

 

13) In order to call a method from an object of generic class, we must assist the generic class by giving it a bound that tells the compiler to only accept types that conform to that bound. This reuses the extends keyword. (i.e. <T exteds List> then add() can be called from references of type T.)  We say that a generic type parameter erases to its first bound. The compiler actually replaces the type parameter with its erasure.( so in the above case, T erases to List which makes no difference to use List directly instead of generics.) 

 

14) Generics are only useful when you want to use type parameters that are more "generic" than a specific type(and all its subtypes) — that is, when you want code to work across multiple classes. As a result, the type parameters and their application in useful generic code will usually be more complex than simple class replacement. However, you can’t just say that anything of the form <T extends List> is therefore flawed. For example, if a class has a method that returns T, then generics are helpful, because they will then return the exact type. 

 

15) If generics had been part of Java 1.0, the feature would not have been implemented using erasure—it would have used reification to retain the type parameters as first-class entities, so you would have been able to perform type-based language and reflective operations on type parameters. The core motivation for erasure is that it allows generified clients to be used with non-generified libraries, and vice versa. This is often called migration compatibility. 

 

16) In an erasure-based implementation, generic types are treated as secondclass types that cannot be used in some important contexts. The generic types are present only during static type checking, after which every generic type in the program is erased by replacing it with a non-generic upper bound. For example, type annotations such as List<T> are erased to List, and ordinary type variables are erased to Object unless a bound is specified. (This is just for compile time type checking , at runtime there is no type information of generic type at all.) 

 

17) The cost of erasure is significant. Generic types cannot be used in operations that explicitly refer to runtime types, such as  instanceof operations and new expressions. Because all the type information about the parameters is lost, whenever you’re writing generic code you must constantly be reminding yourself that it only appears that you have type information about a parameter. 

 

18) Using Array.newInstance( ) is the recommended approach for creating arrays in generics. 

public class ArrayMaker<T> {
private Class<T> kind;
public ArrayMaker(Class<T> kind) { this.kind = kind; }
@SuppressWarnings("unchecked")
T[] create(int size) {
return (T[])Array.newInstance(kind, size);
}

 
19) Even though erasure removes the information about the actual type inside a method or class, the compiler can still ensure internal consistency in the way that the type is used within the method or class. 

 

20) Because erasure removes type information in the body of a method, what matters at runtime is the boundaries: the points where objects enter and leave a method. These are the points at which the compiler performs type checks at compile time, and inserts casting code. All the action in generics happens at the boundaries—the extra compile-time check for incoming values, and the inserted cast for outgoing values. It helps to counter the confusion of erasure to remember that "the boundaries are where the action takes place." 

 

21) You can compensate for erasure by introducing a type tag. This means you explicitly pass in the Class object for your type so that you can use it in type expressions. 

 

22) You can’t create arrays of generics. The general solution is to use an ArrayList everywhere that you are tempted to create an array of generics. You can define a reference in a way that makes the compiler happy. But you can never create an array of that exact type (including the type parameters).  The only way to successfully create an array of a generic type is to create a new array of the erased type, and cast that. The runtime type of the generic array can only be Object[]. 

 

23) Bounds allow you to place constraints on the parameter types that can be used with generics. Although this allows you to enforce rules about the types that your generics can be applied to, a potentially more important effect is that you can call methods that are in your bound types. 

 

24) Because erasure removes type information, the only methods you can call for an unbounded generic parameter are those available for Object. If, however, you are able to constrain that parameter to be a subset of types, then you can call the methods in that subset. To perform this constraint, Java generics reuse the extends keyword. (i.e. <T extends List>) 

 

25) Notice that wildcards are limited to a single bound.(i.e. List<? extends Date, Time> is not valid.) 

 

26) You can assign an array of a derived type to an array reference of the base type. But you can only put that derrived type to that array reference.(otherwise, there will be runtime exception) While it dosen't apply to generic containers. A List of Apple is not type-equivalent to a List of Fruit, even if an Apple is a type of Fruit. The real issue is that we are talking about the type of the container, rather than the type that the container is holding. Unlike arrays, generics do not have built-in covariance. This is because arrays are completely defined in the language and can thus have both compile-time and runtime checks built in, but with generics, the compiler and runtime system cannot know what you want to do with your types and what the rules should be.

Commented By Sean : for example, if you assign a List<Apple> reference to List<Fruit> and use this reference to add a Fruit reference which points to a non-Apple object at runtime. During compile time, compiler won't complain when you add a Fruit reference to List<Fruit> reference. But at runtime, due to type erasure, JVM don't know whether the List should host an Apple , thus won't verify the object being added to it is an Apple. However compiler has added cast codes when you retrive object from List<Apple> reference, which may cost ClassCastException if the list contains non-Apple Fruit instance. But such kind of issue will still happen if you assign a parameterized type reference to a raw type. 

 

27)

List<? extends Fruit> flist = new ArrayList<Apple>(); 
//or
List<?> wlist = new ArrayList<Apple>();

Once you do this kind of "upcast"(subtype wildcard)you lose the ability to put anything in, even an Object. 

 

28) While add( ) takes an argument of the generic parameter type, contains( ) and indexOf( ) take arguments of type Object. So when you specify an ArrayList <? extends Fruit >, the argument for add( ) becomes’? extends Fruit’. From that description, the compiler cannot know which specific subtype of Fruit is required there, so it won’t accept any type of Fruit. It doesn’t matter if you upcast the Apple to a Fruit first—the compiler simply refuses to call a method (such as add( )) if a wildcard is involved in the argument list.

Commented by Sean : Think this way, you can assign either ArrayList<Orange> or ArrayList<Apple> to ArrayList<? extends Fruit>,  so it's unsafe to add any type to the ArrayList<? exntends Fruit>. But for ArrayList<? super Apple>, you know that the list contains a super type of Apple and it's safe to put an Apple to it whatever object it originally held. 

 

29) It’s up to the generic class designer to decide which calls are "safe," and to use Object types for their arguments. To disallow a call when the type is used with wildcards, use the type parameter in the argument list. 

 

30) It’s also possible to use supertype wildcards. Here, you say that the wildcard is bounded by any base class of a particular class, by specifying <? super MyClass> or even using a type parameter: <? super T> (although you cannot give a generic parameter a supertype bound; that is, you cannot say <T super MyClass>). This allows you to safely pass a typed object into a generic type. 

 

31) Supertype bounds(wildcards) relax the constraints on what you can pass into a generic method.  

 

32) The unbounded wildcard <?> appears to mean "anything," and so using an unbounded wildcard seems equivalent to using a raw type. List actually means "a raw List that holds any Object type," whereas List<?> means "a non-raw homogeneous List of some specific type, but we just don’t know what that type is." While unbounded wildcard has the same limitations as subtype wildcard (Any method that takes an argument of the type parameter is disallowed to invoke.) and supertype wildcard ( Return type of any method that returns the parameterized type will be Object.).

Commented By Sean : You cannot know what exact type you get when you get the object from a List<? super Apple> , it can be of any super class of Apple. (i.e. Class.getSuperClass() return a Class<? super T> whose newInstance() method can only return Object type) So it's all about the boundary of a method : the input and output. 

 

33) One of the limitations you will discover in Java generics is that you cannot use primitives as type parameters (i.e. ArrayList<int>). Although autoboxing can help but it cann't help on auto-box primitive arrays to its wrapper arrays. 

 

34) Making the class generic wouldn’t work for static methods or fields.  

 

35) To avoid warning for 

List<Widget> lw = (List<Widget>)in.readObject()

 , you must use a new form of cast introduced in Java SE5, the cast via a generic class: Class.cast():

List<Widget> lw2 = List.class.cast(in.readObject());

Commented By Sean: Class.cast() method returns T , which here is List.

 

36) Generics doesn't support overloading, that is to say you cannot differentiate parameters via generic argument (i.e. List<String>  and List<Integer> are same parameters) 

 

37) To understand what curiously recurring (class A extends B<A>) means, try saying it aloud: "I’m creating a new class that inherits from a generic type that takes my class name as its parameter." What can the generic base type accomplish when given the derived class name? Well, generics in Java are about arguments and return types, so it can produce a base class that uses the derived type for its arguments and return types. It can also use the derived type for field types, even though those will be erased to Object. 

 

38) This is the essence of CRG (Curiously Recurring Generics): The base class substitutes the derived class for its parameters. This means that the generic base class becomes a kind of template for common functionality for all its derived classes, but this functionality will use the derived type for all of its arguments and return values. That is, the exact type instead of the base type will be used in the resulting class. 

 

39) What self-bounding (i.e. SelfBounded<T extends SelfBounded<T>> )does is require the use of the class in an inheritance relationship like this:
class A extends SelfBounded<A> {}
This forces you to pass the class that you are defining as a parameter to the base class.
It’s also possible to use self-bounding for generic methods. This prevents the method from being applied to anything but a self-bounded argument of the form shown.

Commented By Sean:  If you define SelfBounded<T extends SelfBounded> , then you can define A extends SelfBounded<B> where B is the subclass of SelfBounded. 

 

40) The value of self-bounding types is that they produce covariant argument types—method argument types vary to follow the subclasses. Although self-bounding types also produce return types that are the same as the subclass type, this is not so important because covariant return types were introduced in Java SE5.(Return type of overridden method is allowed to be the subtype of the original return type) Without self-bounding, the ordinary inheritance mechanism steps in, and you get overloading, just as with the non-generic case:  

class GenericSetter<T> { // Not self-bounded
  void set(T arg){
    System.out.println("GenericSetter.set(Base)");
  }
}

class DerivedGS extends GenericSetter<Base> {
  void set(Derived derived){
     System.out.println("DerivedGS.set(Derived)");
  }
}
public class PlainGenericInheritance {
  public static void main(String[] args) {
    Base base = new Base();
    Derived derived = new Derived();
    DerivedGS dgs = new DerivedGS();
    dgs.set(derived);
    dgs.set(base); // Compiles: overloaded, not overridden!
  }
} /* Output:
DerivedGS.set(Derived)
GenericSetter.set(Base)
*/

  

41) Because you can pass generic containers to pre-Java SE5 code, there’s still the possibility that old-style code can corrupt your containers. Java SE5 has a set of utilities in java.util.Collections to solve the type-checking problem in this situation: the static methods checkedCollection( ), checkedList( ), checkedMap( ), checkedSet( ), checkedSortedMap( ) and checkedSortedSet( ). Each of these takes the container you want to dynamically check as the first argument and the type that you want to enforce as the second argument. 

 

42) Because of erasure, the use of generics with exceptions is extremely limited. A catch clause cannot catch an exception of a generic type, because the exact type of the exception must be known at both compile time and run time. Also, a generic class can’t directly or indirectly inherit from Throwable (this further prevents you from trying to define generic exceptions that can’t be caught). 

 

43) However, type parameters may be used in the throws clause of a method declaration. This allows you to write generic code that varies with the type of a checked exception. 

interface Processor<T, E extends Exception> {
  void process(List<T> resultCollector) throws E;
}

class ProcessRunner<T,E extends Exception> extends ArrayList<Processor<T,E>> {
    List<T> processAll() throws E {
        List<T> resultCollector = new ArrayList<T>();
        for(Processor<T,E> processor : this)
            processor.process(resultCollector);
        return resultCollector;
  }
}

   

44) The term mixin seems to have acquired numerous meanings over time, but the fundamental concept is that of mixing in capabilities from multiple classes in order to produce a resulting class that represents all the types of the mixins. This is often something you do at the last minute, which makes it convenient to easily assemble classes. 

 

45) Erasure forgets the base-class type, so a generic class cannot inherit directly from a generic parameter:

public Mixins {

    //not allowed
    class Function1<T> extends T {
         void function1() {}
    }

    //not allowed
    class Function2<T> extends T {
         void function2() {}
    }
    class BaseFunction {
         void baseFunction() {}
    }
    public static void main(String[] args) {
        //define mixins as instance of BaseFunction, Function1 and Function2        
        Function2<Function1<BaseFunction> mixins = new Function2<>();
        mixins.function1();
        mixins.function2();
        mixins.baseFunction();
   }
}

 

46) Decorator pattern uses layered objects to dynamically and transparently add responsibilities to individual objects. Decorator specifies that all objects that wrap around your initial object have the same basic interface. Something is decoratable, and you layer on functionality by wrapping other classes around the decoratable. This makes the use of the decorators transparent. There are a set of common messages you can send to an object whether it has been decorated or not. A significant drawback to Decorator is that it only effectively works with one layer of decoration (the final one). 

 

47) It’s possible to use a dynamic proxy to create a mechanism that more closely models mixins. Because of the constraints of dynamic proxies, each class that is mixed in must be the implementation of an interface:

class MixinProxy implements InvocationHandler {
    Map<String,Object> delegatesByMethod;
    public MixinProxy(TwoTuple<Object,Class<?>>... pairs) {
        delegatesByMethod = new HashMap<String,Object>();
        for(TwoTuple<Object,Class<?>> pair : pairs) {
            for(Method method : pair.second.getMethods()) {
                String methodName = method.getName();
                // The first interface in the map
                // implements the method. 
                // Will have issues if two method have same name in different interface
                if (!delegatesByMethod.containsKey(methodName))
                    delegatesByMethod.put(methodName, pair.first);
            }
        }
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Object delegate = delegatesByMethod.get(methodName);
        return method.invoke(delegate, args);
    }
    
    @SuppressWarnings("unchecked")
    public static Object newInstance(TwoTuple... pairs) {
        Class[] interfaces = new Class[pairs.length];
        for(int i = 0; i < pairs.length; i++) {
            interfaces[i] = (Class)pairs[i].second;
        }
        ClassLoader cl = pairs[0].first.getClass().getClassLoader();
        return Proxy.newProxyInstance( cl, interfaces, new MixinProxy(pairs));
    }
}

public class DynamicProxyMixin {
    public static void main(String[] args) {
        Object mixin = MixinProxy.newInstance(
            tuple(new BasicImp(), Basic.class),
            tuple(new TimeStampedImp(), TimeStamped.class),
            tuple(new SerialNumberedImp(),SerialNumbered.class));
            Basic b = (Basic)mixin;
            TimeStamped t = (TimeStamped)mixin;
            SerialNumbered s = (SerialNumbered)mixin;
            b.set("Hello");
            System.out.println(b.get());
            System.out.println(t.getStamp());
            System.out.println(s.getSerialNumber());
    }
} /* Output: (Sample)
Hello
1132519137015
1
*/

 

48) Erasure requires that you specify the bounds of the generic types that may be used, in order to safely call specific methods for the generic objects in your code. However generic code typically only calls a few methods on a generic type, and a language with latent typing(structural typing or duck typing) loosens the constraint (and produces more generic code) by only requiring that a subset of methods be implemented, not a particular class or interface. Because of this, latent typing allows you to cut across class hierarchies, calling methods that are not part of a common interface. Because generics were added to Java late in the game, there was no chance that any kind of latent typing could be implemented, so Java has no support for this feature. We are forced to use a class or an interface and specify it in a bounds expression. In this case, generics were simply not necessary, since the classes were already forced to implement the common interface.

Commented By Sean: however with generics, you can accept and produce a specific type instead of a common interface. 

 

49) Through reflection, we are able to dynamically establish whether the desired methods are available in the object and call them. 49) Because the Java designers (understandably) did not see the need for an "Addable" interface, we are constrained within the Collection hierarchy, and any other class even though it has an add( ) method, will not work. Because it is thus constrained to working with Collection, the code is not particularly "generic." With latent typing, this would not be the case. Because you are not at the mercy of the past design decisions of any particular library creator, so you do not have to rewrite your code every time you encounter a new library that didn’t take your situation into account (thus the code is truly "generic"). 

 

50) Latent typing means that you could write code saying, "I don’t care what type I’m using here as long as it has these methods." In effect, latent typing creates an implicit interface containing the desired methods. So it follows that if we write the necessary interface by hand (since Java doesn’t do it for us), that should solve the problem. Writing code to produce an interface that we want from an interface that we have is an example of the Adapter design pattern. We can use adapters to adapt existing classes to produce the desired interface, with a relatively small amount of code. ( use composition to adapt a base class of a hierarchy and use inheritance to adapt a specific type.)

 

51)  Strategy design pattern completely isolates "the thing that changes" inside of a function object. A function object is an object that in some way behaves like a function—typically, there’s one method of interest. The value of function objects is that, unlike an ordinary method, they can be passed around, and they can also have state that persists across calls. The intent of the function object is primarily to create something that behaves like a single method that you can pass around; thus it is closely coupled with—and sometimes indistinguishable from—the Strategy design pattern. We are creating function objects which perform adaptation, and they are being passed into methods to be used as strategies:

// Different types of function objects:
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(); // Extract result of collecting parameter
}
interface UnaryPredicate<T> { boolean test(T x); }

public class Functional {
    // Calls the Combiner object on each element to combine
    // it with a running result, which is finally returned:
    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;
        }
        // If seq is the empty list:
        return null; // Or throw exception
    }

    // Take a function object and call it on each object in
    // the list, ignoring the return value. The function
    // object may act as a collecting parameter, so it is
    // returned at the end.
    public static <T> Collector<T> forEach(Iterable<T> seq, Collector<T> func) {
        for(T t : seq)
            func.function(t);
        return func;
    }

    // Creates a list of results by calling a
    // function object for each object in the list:
    public static <R,T> List<R> transform(Iterable<T> seq, UnaryFunction<R,T>     func) {
        List<R> result = new ArrayList<R>();
        for(T t : seq)
            result.add(func.function(t));
        return result;
    }

    // Applies a unary predicate to each item in a sequence,
    // and returns a list of items that produced "true":
    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;
    }

    // To use the above generic methods, we need to create
    // function objects to adapt to our particular needs:
    static class IntegerAdder implements Combiner<Integer> {
        public Integer combine(Integer x, Integer y) {
            return x + y;
        }
    }

    static class IntegerSubtracter 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) {
            // Not clear whether this is meaningful:
            return new AtomicLong(x.addAndGet(y.get()));
        }
    }

    // We can even make a UnaryFunction with an "ulp"
    // (Units in the last place):
    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) {
        // Generics, varargs & boxing working together:
        List<Integer> li = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
        Integer result = reduce(li, new IntegerAdder());
        print(result);
        result = reduce(li, new IntegerSubtracter());
        print(result);
        print(filter(li, new GreaterThan<Integer>(4)));
        print(forEach(li, new MultiplyingIntegerCollector()).result());
        print(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());
        print(rbd);
        print(filter(lbd, new GreaterThan<BigDecimal>(new BigDecimal(3))));
        // Use the prime-generation facility of BigInteger:
        List<BigInteger> lbi = new ArrayList<BigInteger>();
        BigInteger bi = BigInteger.valueOf(11);
        for(int i = 0; i < 11; i++) {
            lbi.add(bi);
            bi = bi.nextProbablePrime();
        }
        print(lbi);
        BigInteger rbi = reduce(lbi, new BigIntegerAdder());
        print(rbi);
        // The sum of this list of primes is also prime:
        print(rbi.isProbablePrime(5));
        List<AtomicLong> lal = Arrays.asList( new AtomicLong(11), new AtomicLong(47), new AtomicLong(74), new AtomicLong(133));
        AtomicLong ral = reduce(lal, new AtomicLongAdder());
        print(ral);
        print(transform(lbd,new BigDecimalUlp()));
    }
} /* Output:
28
-26
[5, 6, 7]
5040
210
11.000000
[3.300000, 4.400000]
[11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
311
true
265
[0.000001, 0.000001, 0.000001, 0.000001]
*/

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics